package org.gcube.portal.social.networking.caches; import static org.gcube.resources.discovery.icclient.ICFactory.clientFor; import static org.gcube.resources.discovery.icclient.ICFactory.queryFor; import java.io.InputStream; import java.util.List; import java.util.Properties; import net.sf.ehcache.Ehcache; import net.sf.ehcache.Element; import org.gcube.applicationsupportlayer.social.shared.SocialNetworkingSite; import org.gcube.common.portal.GCubePortalConstants; import org.gcube.common.resources.gcore.ServiceEndpoint; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.portal.social.networking.liferay.ws.GroupManagerWSBuilder; import org.gcube.resources.discovery.client.api.DiscoveryClient; import org.gcube.resources.discovery.client.queries.api.SimpleQuery; import org.gcube.smartgears.ContextProvider; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.vomanagement.usermanagement.GroupManager; import org.gcube.vomanagement.usermanagement.model.GCubeGroup; import org.gcube.vomanagement.usermanagement.model.VirtualGroup; import org.slf4j.LoggerFactory; /** * When a notification needs to be sent, this class offers utility to discover (starting from the scope) * the site information needed to build up the SocialNetworkingSite object (which, for instance, contains the * portal email). * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ public class SocialNetworkingSiteFinder { // Logger private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SocialNetworkingSiteFinder.class); private static final String EMAIL_SENDER_SITE_CUSTOM_FIELD = "Emailsender"; private static final String CATEGORY = "Portal"; // these properties could be overwritten by the ones read from config.properties private static String PROD_FALLBACK_GATEWAY = "D4Science.org Gateway"; private static String DEV_FALLBACK_GATEWAY = "gCube Dev4 Snapshot Gateway"; private static String PREPROD_FALLBACK_GATEWAY = "gCube Preprod (dev) Gateway"; /** * Singleton object */ private static SocialNetworkingSiteFinder singleton = new SocialNetworkingSiteFinder(); /** * Build the singleton instance */ private SocialNetworkingSiteFinder(){ // read fallback properties try{ logger.info("Trying to read config.properties"); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); InputStream input = classLoader.getResourceAsStream("config.properties"); Properties properties = new Properties(); properties.load(input); PROD_FALLBACK_GATEWAY = properties.getProperty("PROD_FALLBACK_GATEWAY"); DEV_FALLBACK_GATEWAY = properties.getProperty("DEV_FALLBACK_GATEWAY"); PREPROD_FALLBACK_GATEWAY = properties.getProperty("PREPROD_FALLBACK_GATEWAY"); }catch(Exception e){ logger.warn("Failed to read config.properties...", e); } } /** * Retrieve the singleton instance */ public static SocialNetworkingSiteFinder getInstance(){ return singleton; } /** * Retrieve the SocialNetworkingSite given the scope * @param scope * @return */ public static SocialNetworkingSite getSocialNetworkingSiteFromScope(String scope){ Ehcache socialSitesCache = CachesManager.getCache(CachesManager.SOCIAL_NETWORKING_SITES_CACHE); if(scope == null || scope.isEmpty()) throw new IllegalArgumentException("Scope cannot be null/empty"); if(socialSitesCache.get(scope) != null) return (SocialNetworkingSite) socialSitesCache.get(scope).getObjectValue(); else{ SocialNetworkingSite site = discoverSite(scope); if(site != null) socialSitesCache.put(new Element(scope, site)); return site; } } /** * Discover the site for this scope * @param scope * @return */ private static SocialNetworkingSite discoverSite(String scope) { try{ logger.info("Requested site for scope " + scope); GroupManager groupManager = GroupManagerWSBuilder.getInstance().getGroupManager(); long groupId = groupManager.getGroupIdFromInfrastructureScope(scope); GCubeGroup matchingGateway = null; if(groupManager.isVRE(groupId)){ // get the Virtual groups for the groupid related to the scope List virtualGroupsOfGroup = groupManager.getVirtualGroups(groupId); if(virtualGroupsOfGroup == null || virtualGroupsOfGroup.isEmpty()) throw new Exception("It seems that the VRE is not linked to any VirtualGroups"); // get the gateways List gateways = groupManager.getGateways(); if(gateways == null || gateways.isEmpty()) throw new Exception("It seems there is no gateway here!"); logger.info("Retrieved Gateways are " + gateways); // now, retrieve the virtual groups for each gateway and stop when a VG matches with one of the group // then, it is the gateway of interest ext_loop: for (GCubeGroup gateway : gateways) { List gatewayVirtualGroups = groupManager.getVirtualGroups(gateway.getGroupId()); if(gatewayVirtualGroups != null && !gatewayVirtualGroups.isEmpty()){ for (VirtualGroup gatewayVirtualGroup : gatewayVirtualGroups) { if(virtualGroupsOfGroup.contains(gatewayVirtualGroup)){ logger.info("Matching gateway for scope " + scope + " is " + gateway); matchingGateway = gateway; break ext_loop; } } } } }else{ List gateways = groupManager.getGateways(); // vo and root vo cases are treated separately: in production environment services.d4science.org is used, instead // in dev next.d4science.org is used TODO better way... ApplicationContext ctx = ContextProvider.get(); // get this info from SmartGears String rootContext = "/"+ctx.container().configuration().infrastructure(); String matchingGatewayName = null; if(isDevOrPreprod(rootContext)){ matchingGatewayName = DEV_FALLBACK_GATEWAY; }else{ matchingGatewayName = PROD_FALLBACK_GATEWAY; } // find the matching one among the gateways for (GCubeGroup gateway : gateways) { if(gateway.getGroupName().equals(matchingGatewayName)){ matchingGateway = gateway; break; } } if(matchingGateway == null && isDevOrPreprod(rootContext)){ logger.warn("Checking if it is the preprod environment"); matchingGatewayName = PREPROD_FALLBACK_GATEWAY; // find the matching one among the gateways for (GCubeGroup gateway : gateways) { if(gateway.getGroupName().equals(matchingGatewayName)){ matchingGateway = gateway; break; } } } } if(matchingGateway == null){ logger.warn("There is no gateway for such scope. Returning null"); return null; }else{ String siteName = matchingGateway.getGroupName(); String emailSender = (String)groupManager.readCustomAttr(matchingGateway.getGroupId(), EMAIL_SENDER_SITE_CUSTOM_FIELD); String siteLandingPagePath = GCubePortalConstants.PREFIX_GROUP_URL + matchingGateway.getFriendlyURL(); String siteUrl = discoverHostOfServiceEndpoint(siteName); SocialNetworkingSite site = new SocialNetworkingSite(siteName, emailSender, siteUrl, siteLandingPagePath); logger.info("Site is " + site); return site; } }catch(Exception e){ logger.error("Failed to determine the SocialNetworkingSite for scope " + scope, e); } return null; } private static boolean isDevOrPreprod(String rootContext) { return rootContext.equals("/gcube"); } /** * Retrieve endpoint host from IS for this gateway * @return the host for the gateway * @throws Exception */ private static String discoverHostOfServiceEndpoint(String gatewayName){ String currentScope = ScopeProvider.instance.get(); ApplicationContext ctx = ContextProvider.get(); // get this info from SmartGears ScopeProvider.instance.set("/"+ctx.container().configuration().infrastructure()); String host = null; try{ SimpleQuery query = queryFor(ServiceEndpoint.class); query.addCondition("$resource/Profile/Name/text() eq '"+ gatewayName +"'"); query.addCondition("$resource/Profile/Category/text() eq '"+ CATEGORY +"'"); DiscoveryClient client = clientFor(ServiceEndpoint.class); List toReturn = client.submit(query); for (ServiceEndpoint serviceEndpoint : toReturn) { host = "https://" + serviceEndpoint.profile().runtime().hostedOn(); logger.info("Gateway host is " + host); break; } }catch(Exception e){ logger.error("Error while retrieving host for the gateway " + gatewayName); }finally{ ScopeProvider.instance.set(currentScope); } return host; } }