allocation map takes into account the infrastructure context

git-svn-id: https://svn.research-infrastructures.eu/d4science/gcube/trunk/portlets/user/rstudio-wrapper-portlet@142831 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Massimiliano Assante 2017-02-21 10:55:08 +00:00
parent e46051e252
commit 8d851ca255
3 changed files with 110 additions and 98 deletions

View File

@ -7,11 +7,13 @@ import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.resources.gcore.ServiceEndpoint;
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;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.vomanagement.usermanagement.UserManager;
@ -32,10 +34,11 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS
private static final Logger _log = LoggerFactory.getLogger(RStudioServiceImpl.class);
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 PATH_TO_RCONNECTOR = "/r-connector/gcube/service/connect";
private static final String SERVICE_EP_NAME = "RConnector";
private static final String CATEGORY = "DataAnalysis";
public static final String USER_ID_ATTR_NAME = "gcube-userId";
@ -48,6 +51,9 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS
// user = "costantino.perciante";
return user;
}
/**
*
*/
@Override
public String retrieveRStudioSecureURL() throws IllegalArgumentException {
String toReturn = "";
@ -78,20 +84,31 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS
_log.debug("calling rConnector with scope = " + scope + " and token = "+token );
List<ServiceEndpoint> resources = getRStudioServiceEndpoints(scope);
if (resources.size() == 0){
_log.warn("There is no Servcie Endpoint having CATEGORY " + CATEGORY +" and NAME " + SERVICE_EP_NAME + " in this scope. Returning default instance");
_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();
} else {
UserManager um = new LiferayUserManager();
_log.debug("Checking if user " + curUser.getFullname() + " has already an RStudio Instance set ... ");
//check RStudio
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) {
String hostedOn = (String) um.readCustomAttr(userId, RSTUDIO_URL);
_log.info("**** The instance set for user " + curUser.getFullname() + " is " + hostedOn);
toReturn = getRConnectorURL(hostedOn, token);
_log.debug("User " + curUser.getFullname() + " has RStudio Instance set, returning rConnector URL " + toReturn);
_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 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) ) {
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, calculating allocation ... ");
_log.info("User " + curUser.getFullname() + " DOES NOT have RStudio Instance set or the instance previous set no longer exists, calculating allocation ... ");
HashMap<String, Integer> rStudioDistributionMap = new HashMap<>();
for (ServiceEndpoint res : resources) {
String hostedOn = res.profile().runtime().hostedOn();
@ -100,8 +117,8 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS
List<GCubeUser> vreUsers = um.listUsersByGroup(pContext.getCurrentGroupId(getThreadLocalRequest()), false);
_log.debug("VRE " + scope + " has totalUsers = " + vreUsers.size());
for (GCubeUser gCubeUser : vreUsers) {
if (um.readCustomAttr(gCubeUser.getUserId(), RSTUDIO_URL) != null && um.readCustomAttr(gCubeUser.getUserId(), RSTUDIO_URL).toString().compareTo("") != 0) {
String hostedOn = (String) um.readCustomAttr(gCubeUser.getUserId(), RSTUDIO_URL);
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);
@ -126,8 +143,8 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS
}
i++;
}
um.saveCustomAttr(userId, RSTUDIO_URL, host2Select);
_log.debug("User " + curUser.getFullname() + " RStudio Instance set calculated = " + host2Select);
writeRStudioInstanceInScope(um, curUser, scope, host2Select);
_log.debug("User " + curUser.getFullname() + " RStudio Instance set calculated = " + host2Select + " for context " + scope);
toReturn = getRConnectorURL(host2Select, token);
_log.debug("User " + curUser.getFullname() + " has RStudio Instance set, returning rConnector URL " + toReturn);
}
@ -140,6 +157,49 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS
return toReturn;
}
/**
*
* @param um
* @param gCubeUser
* @return a map containing the scope and the RStudio Instances set for this user
* @throws UserRetrievalFault
*/
private Map<String, String> getUserRStudioInstances(UserManager um, GCubeUser gCubeUser) throws UserRetrievalFault {
Map<String, String> theInstances = new HashMap<>();
if (um.readCustomAttr(gCubeUser.getUserId(), RSTUDIO_INSTANCES) != null && um.readCustomAttr(gCubeUser.getUserId(), RSTUDIO_INSTANCES).toString().compareTo("") != 0) {
String[] values = (String[]) um.readCustomAttr(gCubeUser.getUserId(), RSTUDIO_INSTANCES);
if (values != null && values.length > 0) {
for (int i = 0; i < values.length; i++) {
String[] splits = values[i].split("\\|");
RStudioInstance istance = new RStudioInstance(splits);
theInstances.put(istance.getContext(), istance.getHostedOn());
}
}
}
return theInstances;
}
/**
* write the RStudio Instance
* @param um
* @param gCubeUser
* @param context the infra scope
* @param hostedOn
* @throws UserRetrievalFault
*/
private void writeRStudioInstanceInScope(UserManager um, GCubeUser gCubeUser, String context, String hostedOn) throws UserRetrievalFault {
Map<String, String> theInstances = getUserRStudioInstances(um, gCubeUser);
theInstances.put(context, hostedOn);
String[] theValues = new String[theInstances.size()];
int i = 0;
for (String instanceScope : theInstances.keySet()) {
String toPut = instanceScope+"|"+theInstances.get(instanceScope); //-> /gcube/devNext/NextNext|rstudio.d4science.org:443
theValues[i] = toPut;
i++;
}
//overwrite the values
um.saveCustomAttr(gCubeUser.getUserId(), RSTUDIO_INSTANCES, theValues);
}
private String getRConnectorURL(String hostedOn, String token) throws MalformedURLException, IllegalArgumentException {
String[] splits = hostedOn.split(":");
int port = 80;
@ -155,33 +215,6 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS
return "http://"+hostedOn+PATH_TO_RCONNECTOR+"?gcube-token="+token;
}
}
// private String getRConnectorURL(String hostedOn, String token) {
// _log.info("getRConnectorURL hostedOn:" + hostedOn);
// String[] splits = hostedOn.split(":");
// String host = splits[0];
// int port = 80;
// try {
// port = Integer.parseInt(splits[1]);
// } catch (Exception e) {
// _log.warn("Could not find an integer after :, using default port 80");
// }
//
// String toReturn = "";
// try {
// toReturn = rConnector().at(host, port).build().connect().toURL().toExternalForm();
// } catch (MalformedURLException | IllegalArgumentException e) {
// e.printStackTrace();
// return null;
// }
// if ((port == 443 || port == 8443) && !toReturn.startsWith("https")) {
// toReturn = toReturn.replaceFirst("http", "https");
// return toReturn;
// }
// else {
// return toReturn;
// }
// }
/**
*
* @return the
@ -199,21 +232,13 @@ public class RStudioServiceImpl extends RemoteServiceServlet implements RStudioS
ScopeProvider.instance.set(currScope);
return toReturn;
}
// /**
// *
// * @return the
// * @throws Exception
// */
// private List<GCoreEndpoint> getRStudioServiceEndpoints(String scope) throws Exception {
// _log.debug("getRStudioServiceEndpoints on scope="+scope );
// String currScope = ScopeProvider.instance.get();
// ScopeProvider.instance.set(scope);
// SimpleQuery query = queryFor(GCoreEndpoint.class);
// query.addCondition("$resource/Profile/ServiceName/text() eq '"+ SERVICE_NAME +"'");
// query.addCondition("$resource/Profile/ServiceClass/text() eq '"+ SERVICECLASS +"'");
// DiscoveryClient<GCoreEndpoint> client = clientFor(GCoreEndpoint.class);
// List<GCoreEndpoint> toReturn = client.submit(query);
// ScopeProvider.instance.set(currScope);
// return toReturn;
// }
private static boolean checkRStudioInstanceExistence(GCubeUser curUser, String hostedOn, List<ServiceEndpoint> 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");
return true;
}
return false;
}
}

View File

@ -1,42 +0,0 @@
package org.gcube.portlets.user.rstudio_wrapper_portlet.shared;
/**
* <p>
* FieldVerifier validates that the name the user enters is valid.
* </p>
* <p>
* This class is in the <code>shared</code> packing because we use it in both
* the client code and on the server. On the client, we verify that the name is
* valid before sending an RPC request so the user doesn't have to wait for a
* network round trip to get feedback. On the server, we verify that the name is
* correct to ensure that the input is correct regardless of where the RPC
* originates.
* </p>
* <p>
* When creating a class that is used on both the client and the server, be sure
* that all code is translatable and does not use native JavaScript. Code that
* is note translatable (such as code that interacts with a database or the file
* system) cannot be compiled into client side JavaScript. Code that uses native
* JavaScript (such as Widgets) cannot be run on the server.
* </p>
*/
public class FieldVerifier {
/**
* Verifies that the specified name is valid for our service.
*
* In this example, we only require that the name is at least four
* characters. In your application, you can use more complex checks to ensure
* that usernames, passwords, email addresses, URLs, and other fields have the
* proper syntax.
*
* @param name the name to validate
* @return true if valid, false if invalid
*/
public static boolean isValidName(String name) {
if (name == null) {
return false;
}
return name.length() > 3;
}
}

View File

@ -0,0 +1,29 @@
package org.gcube.portlets.user.rstudio_wrapper_portlet.shared;
public class RStudioInstance {
String context;
String hostedOn;
public RStudioInstance(String[] splits) {
this.context = splits[0];
this.hostedOn = splits[1];
}
public RStudioInstance(String context, String hostedOn) {
this.hostedOn = hostedOn;
this.context = context;
}
public String getHostedOn() {
return hostedOn;
}
public void setHostedOn(String hostedOn) {
this.hostedOn = hostedOn;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
}