diff --git a/.classpath b/.classpath index 2c48a08..8c7e737 100644 --- a/.classpath +++ b/.classpath @@ -1,18 +1,18 @@ - + - + - + @@ -30,16 +30,16 @@ - - - - - - + + + + + + diff --git a/.settings/com.gwtplugins.gdt.eclipse.core.prefs b/.settings/com.gwtplugins.gdt.eclipse.core.prefs index a33d7f8..f521e97 100644 --- a/.settings/com.gwtplugins.gdt.eclipse.core.prefs +++ b/.settings/com.gwtplugins.gdt.eclipse.core.prefs @@ -1,4 +1,4 @@ eclipse.preferences.version=1 -lastWarOutDir=/Users/massi/Documents/workspace/rstudio-wrapper-portlet/target/rstudio-wrapper-portlet-1.3.1-SNAPSHOT +lastWarOutDir=${webappDirectory} warSrcDir=src/main/webapp warSrcDirIsOutput=false diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 8db228c..4e4a3ad 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,9 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.7 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml index c5b2895..0e7b425 100644 --- a/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,10 +1,10 @@ - + diff --git a/pom.xml b/pom.xml index 4e9d5fb..de48eb9 100644 --- a/pom.xml +++ b/pom.xml @@ -24,10 +24,10 @@ distro 6.2.5 6.2.10.12 - /Users/massi/portal/liferay-portal-6.2-ce-ga6/deploy - /Users/massi/portal/liferay-portal-6.2-ce-ga6/tomcat-7.0.62/webapps - /Users/massi/portal/liferay-portal-6.2-ce-ga6/tomcat-7.0.62/lib/ext - /Users/massi/portal/liferay-portal-6.2-ce-ga6/tomcat-7.0.62/webapps/ROOT + ${system.CATALINA_HOME}/../deploy + ${system.CATALINA_HOME}/webapps + ${system.CATALINA_HOME}/lib/ext + ${system.CATALINA_HOME}/webapps/ROOT diff --git a/src/main/java/org/gcube/portlets/user/rstudio_wrapper_portlet/server/RStudioServiceImpl.java b/src/main/java/org/gcube/portlets/user/rstudio_wrapper_portlet/server/RStudioServiceImpl.java index 21ccb33..6fa20bc 100644 --- a/src/main/java/org/gcube/portlets/user/rstudio_wrapper_portlet/server/RStudioServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/rstudio_wrapper_portlet/server/RStudioServiceImpl.java @@ -5,12 +5,17 @@ import static org.gcube.resources.discovery.icclient.ICFactory.clientFor; import static org.gcube.resources.discovery.icclient.ICFactory.queryFor; import java.net.MalformedURLException; +import java.net.URI; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.gcube.common.portal.PortalContext; +import org.gcube.common.resources.gcore.GCoreEndpoint; +import org.gcube.common.resources.gcore.GCoreEndpoint.Profile.Endpoint; import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.utils.Group; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.portlets.user.rstudio_wrapper_portlet.client.RStudioService; import org.gcube.portlets.user.rstudio_wrapper_portlet.shared.RStudioInstance; @@ -37,6 +42,9 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS private static final String RSTUDIO_INSTANCES = "RStudio-Instances"; private static final String RSTUDIO_URL = "RStudio-URL"; private static final String RCONNECTOR_EntryName = "org.gcube.data.analysis.rconnector.RConnector"; + private static final String GCORE_SERVICE_NAME = "RConnector"; + private static final String GCORE_SERVICE_CLASS = "DataAnalysis"; + private static final String PATH_TO_RCONNECTOR = "/r-connector/gcube/service/connect"; private static final String SERVICE_EP_NAME = "RConnector"; @@ -75,13 +83,13 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS _log.debug("calling rConnector with scope = " + scope + " and token = "+token ); List resources = getRStudioServiceEndpoints(scope); if (resources.size() == 0){ - _log.warn("There is no Service Endpoint having CATEGORY " + CATEGORY +" and NAME " + SERVICE_EP_NAME + " in this scope. Returning default instance"); - toReturn = rConnector().build().connect().toURL().toExternalForm(); + _log.info("There is no Service Endpoint having CATEGORY " + CATEGORY +" and NAME " + SERVICE_EP_NAME + " in this scope. Passing to the gCore instances"); + toReturn = getRStudioGCoreEndpoint(pContext, userId, curUser, scope, token); } else { UserManager um = new LiferayUserManager(); _log.debug("Checking if user " + curUser.getFullname() + " has already an RStudio Instance set ... "); String hostedOnSet = null; - + //check if an RStudio instance was previously set (RETRO-COMPATIBILY) if (um.readCustomAttr(userId, RSTUDIO_URL) != null && um.readCustomAttr(userId, RSTUDIO_URL).toString().compareTo("") != 0) { _log.debug("User had already an RStudio Instance set, upgrading to new version "); @@ -89,9 +97,9 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS writeRStudioInstanceInScope(um, curUser, scope, hostedOnSet); um.saveCustomAttr(userId, RSTUDIO_URL, ""); //reset the old value to blank so that from now on it will read from the new field } - + hostedOnSet = getUserRStudioInstances(um,curUser).get(scope); - + _log.info("**** Checking if still exist on this scope: " + scope); //if the instance exists and is still available in the given context if (hostedOnSet != null && checkRStudioInstanceExistence(curUser, hostedOnSet, resources) ) { @@ -147,11 +155,105 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS _log.info("returning URL from rConnector = "+toReturn); if (!toReturn.startsWith("https")) { toReturn = toReturn.replace("http:", "https:"); + toReturn = toReturn.replace(":8080", ""); + toReturn = toReturn.replace(":80", ""); _log.info("Changed URL from rConnector to support SSL: "+toReturn); } return toReturn; } + + /** + * new method + * @param pContext + * @param userId + * @param curUser + * @param scope + * @param token + * @return + */ + private String getRStudioGCoreEndpoint(PortalContext pContext, long userId, GCubeUser curUser, String scope, String token) { + String toReturn = ""; + UserManager um = new LiferayUserManager(); + _log.debug("Checking if user " + curUser.getFullname() + " has already an RStudio Instance set ... "); + String hostedOnSet = null; + try { + //check if an RStudio instance was previously set (RETRO-COMPATIBILY) + if (um.readCustomAttr(userId, RSTUDIO_URL) != null && um.readCustomAttr(userId, RSTUDIO_URL).toString().compareTo("") != 0) { + _log.debug("User had already an RStudio Instance set, upgrading to new version "); + hostedOnSet = (String) um.readCustomAttr(userId, RSTUDIO_URL); + writeRStudioInstanceInScope(um, curUser, scope, hostedOnSet); + um.saveCustomAttr(userId, RSTUDIO_URL, ""); //reset the old value to blank so that from now on it will read from the new field + } + hostedOnSet = getUserRStudioInstances(um,curUser).get(scope); + _log.info("**** Checking if the user instance " + hostedOnSet+" exists in the VO for this VRE: " + scope); + //if the instance exists and is still available in the given context + List gCoreResources = getRStudioGCoreEndpoints(scope); + if (hostedOnSet != null && checkRStudioGCoreInstanceExistence(curUser, hostedOnSet, gCoreResources) ) { + toReturn = getRConnectorURL(hostedOnSet, token); + _log.info("User " + curUser.getFullname() + " has RStudio Instance set and is valid, returning rConnector URL " + toReturn); + } + else {//need to find the RStudio + _log.info("User " + curUser.getFullname() + " DOES NOT have RStudio Instance set or the instance previous set no longer exists, calculating allocation ... "); + HashMap rStudioDistributionMap = new HashMap<>(); + for (GCoreEndpoint res : gCoreResources) { + String hostedOn = extractGCoreEndpointHostAndPort(res); + rStudioDistributionMap.put(hostedOn, 0); + } + List vreUsers = um.listUsersByGroup(pContext.getCurrentGroupId(getThreadLocalRequest()), false); + _log.debug("VRE " + scope + " has totalUsers = " + vreUsers.size()); + for (GCubeUser gCubeUser : vreUsers) { + if (getUserRStudioInstances(um,gCubeUser).get(scope) != null) { + String hostedOn = getUserRStudioInstances(um,gCubeUser).get(scope); + if (rStudioDistributionMap.containsKey(hostedOn)) { + int noToSet = rStudioDistributionMap.get(hostedOn)+1; + rStudioDistributionMap.put(hostedOn, noToSet); + } + } + } + _log.info("VRE - RStudio allocaiton map as follows: "); + int min = 0; + int i = 0; + String host2Select = ""; + for (String host : rStudioDistributionMap.keySet()) { + _log.info("Host " + host + " has # users=" + rStudioDistributionMap.get(host)); + if (i==0) { + host2Select = host; + min = rStudioDistributionMap.get(host); + } else { + int usersNo = rStudioDistributionMap.get(host); + if (usersNo < min) { + _log.info("Host " + host + " has LESS users than " + host2Select + " updating"); + host2Select = host; + } + } + i++; + } + writeRStudioInstanceInScope(um, curUser, scope, host2Select); + _log.debug("User " + curUser.getFullname() + " RStudio gCore Instance set calculated = " + host2Select + " for context " + scope); + toReturn = getRConnectorURL(host2Select, token); + _log.debug("User " + curUser.getFullname() + " has RStudio gCore Instance set, returning rConnector URL " + toReturn); + } + + } catch (Exception e) { + e.printStackTrace(); + } + return toReturn; + } + + private List getRStudioGCoreEndpoints(String scope) { + _log.debug("getRStudioGCoreEndpoints on scope="+scope ); + String currScope = ScopeProvider.instance.get(); + ScopeProvider.instance.set(scope); + SimpleQuery query = queryFor(GCoreEndpoint.class); + query.addCondition("$resource/Profile/ServiceName/text() eq '"+ GCORE_SERVICE_NAME +"'"); + query.addCondition("$resource/Profile/ServiceClass/text() eq '"+ GCORE_SERVICE_CLASS +"'"); + DiscoveryClient client = clientFor(GCoreEndpoint.class); + List toReturn = client.submit(query); + ScopeProvider.instance.set(currScope); + return toReturn; + } + /** * * @param um @@ -204,11 +306,15 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS _log.warn("Could not find an integer after :, using default port 80"); } //http://rstudio-dev.d4science.org:80/r-connector/gcube/service/connect?gcube-token=6fa92d94-6568-4510-8443-a1c5ecdf1c7d-98187548s - if (port == 443 || port == 8443) - return "https://"+hostedOn+PATH_TO_RCONNECTOR+"?gcube-token="+token; + String toReturn = ""; + if (port == 443 || port == 8443) { + toReturn = "https://"+hostedOn+PATH_TO_RCONNECTOR+"?gcube-token="+token; + } else { - return "http://"+hostedOn+PATH_TO_RCONNECTOR+"?gcube-token="+token; + toReturn = "http://"+hostedOn+PATH_TO_RCONNECTOR+"?gcube-token="+token; } + _log.debug("**getRConnectorURL toReturn="+toReturn); + return toReturn; } /** * @@ -227,13 +333,32 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS ScopeProvider.instance.set(currScope); return toReturn; } - + private static boolean checkRStudioInstanceExistence(GCubeUser curUser, String hostedOn, List resources) { for (ServiceEndpoint serviceEndpoint : resources) if (serviceEndpoint.profile().runtime().hostedOn().equals(hostedOn)) { - _log.info("**** The instance previously set for user " + curUser.getFullname() + " on " + hostedOn + " is still valid"); + _log.info("---- checkRStudioServiceEndpointExistence: The instance previously set for user " + curUser.getFullname() + " on " + hostedOn + " is still valid"); return true; } return false; } + + private static boolean checkRStudioGCoreInstanceExistence(GCubeUser curUser, String hostedOn, List resources) { + for (GCoreEndpoint gcoreEndpoint : resources) { + String instance = extractGCoreEndpointHostAndPort(gcoreEndpoint); + if (instance.equalsIgnoreCase(hostedOn)) { + _log.info("**** checkRStudioGCoreInstanceExistence: The instance previously set for user " + curUser.getFullname() + " on " + hostedOn + " is still valid"); + return true; + } + } + return false; + } + + private static String extractGCoreEndpointHostAndPort(GCoreEndpoint resource) { + Collection eps = resource.profile().endpoints().asCollection(); + for (Endpoint ep : eps) + if (ep.name().equalsIgnoreCase(RCONNECTOR_EntryName)) + return new StringBuilder(ep.uri().getHost()).append(":").append(ep.uri().getPort()).toString(); + return null; + } }