411 lines
17 KiB
Java
411 lines
17 KiB
Java
package org.gcube.smartgears.handler.resourceregistry.resourcemanager;
|
|
|
|
import java.net.URI;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
|
|
import javax.servlet.ServletRegistration;
|
|
|
|
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
|
import org.gcube.informationsystem.model.impl.properties.HeaderImpl;
|
|
import org.gcube.informationsystem.model.impl.properties.PropagationConstraintImpl;
|
|
import org.gcube.informationsystem.model.reference.entities.Facet;
|
|
import org.gcube.informationsystem.model.reference.entities.Resource;
|
|
import org.gcube.informationsystem.model.reference.properties.Header;
|
|
import org.gcube.informationsystem.model.reference.properties.PropagationConstraint;
|
|
import org.gcube.informationsystem.model.reference.properties.PropagationConstraint.AddConstraint;
|
|
import org.gcube.informationsystem.model.reference.properties.PropagationConstraint.RemoveConstraint;
|
|
import org.gcube.informationsystem.model.reference.relations.ConsistsOf;
|
|
import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.AvailableInAnotherContextException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.entities.resource.ResourceNotFoundException;
|
|
import org.gcube.informationsystem.resourceregistry.client.ResourceRegistryClient;
|
|
import org.gcube.informationsystem.resourceregistry.client.ResourceRegistryClientFactory;
|
|
import org.gcube.informationsystem.resourceregistry.publisher.ResourceRegistryPublisher;
|
|
import org.gcube.informationsystem.resourceregistry.publisher.ResourceRegistryPublisherFactory;
|
|
import org.gcube.informationsystem.utils.ElementMapper;
|
|
import org.gcube.resourcemanagement.model.impl.entities.facets.AccessPointFacetImpl;
|
|
import org.gcube.resourcemanagement.model.impl.entities.facets.EventFacetImpl;
|
|
import org.gcube.resourcemanagement.model.impl.entities.facets.SoftwareFacetImpl;
|
|
import org.gcube.resourcemanagement.model.impl.entities.facets.StateFacetImpl;
|
|
import org.gcube.resourcemanagement.model.impl.entities.resources.EServiceImpl;
|
|
import org.gcube.resourcemanagement.model.impl.properties.ValueSchemaImpl;
|
|
import org.gcube.resourcemanagement.model.impl.relations.consistsof.IsIdentifiedByImpl;
|
|
import org.gcube.resourcemanagement.model.impl.relations.isrelatedto.ActivatesImpl;
|
|
import org.gcube.resourcemanagement.model.reference.entities.facets.AccessPointFacet;
|
|
import org.gcube.resourcemanagement.model.reference.entities.facets.EventFacet;
|
|
import org.gcube.resourcemanagement.model.reference.entities.facets.MemoryFacet;
|
|
import org.gcube.resourcemanagement.model.reference.entities.facets.SoftwareFacet;
|
|
import org.gcube.resourcemanagement.model.reference.entities.facets.StateFacet;
|
|
import org.gcube.resourcemanagement.model.reference.entities.resources.EService;
|
|
import org.gcube.resourcemanagement.model.reference.entities.resources.HostingNode;
|
|
import org.gcube.resourcemanagement.model.reference.properties.ValueSchema;
|
|
import org.gcube.resourcemanagement.model.reference.relations.consistsof.HasPersistentMemory;
|
|
import org.gcube.resourcemanagement.model.reference.relations.consistsof.HasVolatileMemory;
|
|
import org.gcube.resourcemanagement.model.reference.relations.consistsof.IsIdentifiedBy;
|
|
import org.gcube.resourcemanagement.model.reference.relations.isrelatedto.Activates;
|
|
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
|
|
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
|
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
|
import org.gcube.smartgears.handler.resourceregistry.Constants;
|
|
import org.gcube.smartgears.handler.resourceregistry.ContextUtility;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/**
|
|
* @author Luca Frosini (ISTI-CNR)
|
|
*/
|
|
public class EServiceManager {
|
|
|
|
private static Logger logger = LoggerFactory.getLogger(HostingNodeManager.class);
|
|
|
|
private static List<String> servletExcludes = Arrays.asList("default", "jsp");
|
|
|
|
private ResourceRegistryPublisher resourceRegistryPublisher;
|
|
|
|
private EService eService;
|
|
|
|
private ApplicationContext applicationContext;
|
|
|
|
public EServiceManager(ApplicationContext applicationContext) {
|
|
this.applicationContext = applicationContext;
|
|
this.resourceRegistryPublisher = ResourceRegistryPublisherFactory.create();
|
|
}
|
|
|
|
public void addEServiceToCurrentContext() throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
|
|
String currentToken = SecurityTokenProvider.instance.get();
|
|
UUID contextUUID = ContextUtility.getContextUUID(currentToken);
|
|
|
|
/* Trying to get a context which is not the current to properly invoke the addToContext without forcing the operation using addResourceToCurrentContext */
|
|
boolean anotherContextSet = false;
|
|
Set<String> startTokens = applicationContext.configuration().startTokens();
|
|
for (String token : startTokens) {
|
|
UUID anotherContextUUID = ContextUtility.getContextUUID(token);
|
|
if(anotherContextUUID.compareTo(contextUUID)!=0) {
|
|
ContextUtility.setContextFromToken(token);
|
|
anotherContextSet = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
UUID uuid = UUID.fromString(applicationContext.id());
|
|
try {
|
|
if(anotherContextSet) {
|
|
resourceRegistryPublisher.addResourceToContext(EService.NAME, uuid, contextUUID, false);
|
|
}else {
|
|
resourceRegistryPublisher.addResourceToCurrentContext(HostingNode.NAME, uuid, false);
|
|
}
|
|
logger.info("{} with UUID {} successfully added to context ({})", EService.NAME, uuid, ContextUtility.getCurrentContextName());
|
|
} catch (Exception e) {
|
|
logger.error("Unable to add {} with UUID {} to context ({})", EService.NAME, uuid, ContextUtility.getCurrentContextName(), e);
|
|
}finally {
|
|
ContextUtility.setContextFromToken(currentToken);
|
|
}
|
|
}
|
|
|
|
public void addHostingNodeToCurrentContext() throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
|
|
String currentToken = SecurityTokenProvider.instance.get();
|
|
UUID contextUUID = ContextUtility.getContextUUID(currentToken);
|
|
|
|
/* Trying to get a context which is not the current to properly invoke the addToContext without forcing the operation using addResourceToCurrentContext */
|
|
boolean anotherContextSet = false;
|
|
Set<String> startTokens = applicationContext.configuration().startTokens();
|
|
for (String token : startTokens) {
|
|
UUID anotherContextUUID = ContextUtility.getContextUUID(token);
|
|
if(anotherContextUUID.compareTo(contextUUID)!=0) {
|
|
ContextUtility.setContextFromToken(token);
|
|
anotherContextSet = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
UUID uuid = UUID.fromString(applicationContext.container().id());
|
|
try {
|
|
if(anotherContextSet) {
|
|
resourceRegistryPublisher.addResourceToContext(HostingNode.NAME, uuid, contextUUID, false);
|
|
}else {
|
|
resourceRegistryPublisher.addResourceToCurrentContext(HostingNode.NAME, uuid, false);
|
|
}
|
|
logger.info("{} with UUID {} successfully added to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName());
|
|
} catch (Exception e) {
|
|
logger.error("Unable to add {} with UUID {} to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName(), e);
|
|
}finally {
|
|
ContextUtility.setContextFromToken(currentToken);
|
|
}
|
|
}
|
|
|
|
public void addToContext(UUID contextUUID) throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
|
|
UUID uuid = UUID.fromString(applicationContext.container().id());
|
|
try {
|
|
resourceRegistryPublisher.addToContext(HostingNode.NAME, uuid, contextUUID, false);
|
|
logger.info("{} with UUID {} successfully added to context ({})", HostingNode.NAME, uuid, ContextUtility.getContextNameFromUUID(contextUUID));
|
|
} catch (Exception e) {
|
|
logger.error("Unable to add {} with UUID {} to context ({})", HostingNode.NAME, uuid, ContextUtility.getContextNameFromUUID(contextUUID), e);
|
|
}
|
|
}
|
|
|
|
public void removeFromCurrentContext()
|
|
throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
|
|
UUID uuid = UUID.fromString(applicationContext.container().id());
|
|
try {
|
|
resourceRegistryPublisher.removeResourceFromCurrentContext(HostingNode.NAME, uuid, false);
|
|
logger.info("{} with UUID {} successfully removed from context ({})", HostingNode.NAME, uuid,
|
|
ContextUtility.getCurrentContextName());
|
|
} catch (Exception e) {
|
|
logger.error("Unable to remove {} with UUID {} from context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName(), e);
|
|
}
|
|
}
|
|
|
|
public void removeFromContext(UUID contextUUID)
|
|
throws ResourceNotFoundException, ContextNotFoundException, ResourceRegistryException {
|
|
String contextFullName = ContextUtility.getContextNameFromUUID(contextUUID);
|
|
UUID uuid = UUID.fromString(applicationContext.container().id());
|
|
try {
|
|
resourceRegistryPublisher.removeResourceFromContext(HostingNode.NAME, uuid, contextUUID, false);
|
|
logger.info("{} with UUID {} successfully removed from context ({})", HostingNode.NAME, uuid, contextFullName);
|
|
} catch (Exception e) {
|
|
logger.error("Unable to remove {} from context ({})", HostingNode.NAME, uuid, contextFullName, e);
|
|
}
|
|
}
|
|
|
|
private String getBaseAddress() {
|
|
ApplicationConfiguration configuration = applicationContext.configuration();
|
|
ContainerConfiguration container = applicationContext.container().configuration();
|
|
String baseAddress;
|
|
if (configuration.proxied()) {
|
|
String protocol = configuration.proxyAddress().protocol();
|
|
String port = configuration.proxyAddress().port() != null ? ":" + configuration.proxyAddress().port() : "";
|
|
|
|
baseAddress = String.format("%s://%s%s%s", protocol, configuration.proxyAddress().hostname(), port,
|
|
applicationContext.application().getContextPath());
|
|
} else {
|
|
String protocol = container.protocol();
|
|
int port = container.port();
|
|
|
|
baseAddress = String.format("%s://%s:%d%s", protocol, container.hostname(), port,
|
|
applicationContext.application().getContextPath());
|
|
}
|
|
return baseAddress;
|
|
}
|
|
|
|
public String getState() {
|
|
return applicationContext.lifecycle().state().remoteForm().toLowerCase();
|
|
}
|
|
|
|
private StateFacet getStateFacet(StateFacet stateFacet, Date date) {
|
|
if (stateFacet == null) {
|
|
stateFacet = new StateFacetImpl();
|
|
}
|
|
String state = getState();
|
|
stateFacet.setValue(state);
|
|
stateFacet.setAdditionalProperty("date", date);
|
|
return stateFacet;
|
|
}
|
|
|
|
private EventFacet getEventFacet(Date date) {
|
|
EventFacet eventFacet = new EventFacetImpl();
|
|
eventFacet.setDate(date);
|
|
String state = getState();
|
|
eventFacet.setEvent(state);
|
|
return eventFacet;
|
|
}
|
|
|
|
private EService instantiateEService() {
|
|
logger.info("Creating {} for {}", EService.NAME, applicationContext.name());
|
|
|
|
ApplicationConfiguration applicationConfiguration = applicationContext.configuration();
|
|
String id = applicationContext.id();
|
|
|
|
UUID uuid = UUID.fromString(id);
|
|
EService eService = new EServiceImpl();
|
|
Header header = new HeaderImpl(uuid);
|
|
eService.setHeader(header);
|
|
|
|
SoftwareFacet softwareFacet = new SoftwareFacetImpl();
|
|
softwareFacet.setDescription(applicationConfiguration.description());
|
|
softwareFacet.setGroup(applicationConfiguration.serviceClass());
|
|
softwareFacet.setName(applicationConfiguration.name());
|
|
softwareFacet.setVersion(applicationConfiguration.version());
|
|
|
|
IsIdentifiedBy<EService, SoftwareFacet> isIdentifiedBy = new IsIdentifiedByImpl<EService, SoftwareFacet>(
|
|
eService, softwareFacet);
|
|
eService.addFacet(isIdentifiedBy);
|
|
|
|
String baseAddress = getBaseAddress();
|
|
for (ServletRegistration servlet : applicationContext.application().getServletRegistrations().values()) {
|
|
if (!servletExcludes.contains(servlet.getName())) {
|
|
for (String mapping : servlet.getMappings()) {
|
|
|
|
String address = baseAddress
|
|
+ (mapping.endsWith("*") ? mapping.substring(0, mapping.length() - 2) : mapping);
|
|
|
|
AccessPointFacet accessPointFacet = new AccessPointFacetImpl();
|
|
accessPointFacet.setEntryName(servlet.getName());
|
|
accessPointFacet.setEndpoint(URI.create(address));
|
|
ValueSchema valueSchema = new ValueSchemaImpl();
|
|
valueSchema.setValue("gcube-token");
|
|
|
|
accessPointFacet.setAuthorization(valueSchema);
|
|
|
|
eService.addFacet(accessPointFacet);
|
|
}
|
|
}
|
|
}
|
|
|
|
Date date = Calendar.getInstance().getTime();
|
|
|
|
StateFacet stateFacet = getStateFacet(null, date);
|
|
eService.addFacet(stateFacet);
|
|
|
|
EventFacet eventFacet = getEventFacet(date);;
|
|
eService.addFacet(eventFacet);
|
|
|
|
return eService;
|
|
}
|
|
|
|
public EService createEService() throws ResourceRegistryException {
|
|
ResourceRegistryClient resourceRegistryClient = ResourceRegistryClientFactory.create();
|
|
UUID eServiceUUID = UUID.fromString(applicationContext.id());
|
|
try {
|
|
ResourceRegistryClientFactory.includeContextsInInstanceHeader(true);
|
|
eService = resourceRegistryClient.getInstance(EService.class, eServiceUUID);
|
|
updateFacets();
|
|
} catch (NotFoundException e) {
|
|
eService = instantiateEService();
|
|
eService = createActivatesRelation(eService).getTarget();
|
|
} catch (AvailableInAnotherContextException e) {
|
|
addHostingNodeToCurrentContext();
|
|
try {
|
|
eService = resourceRegistryClient.getInstance(EService.class, eServiceUUID);
|
|
} catch (AvailableInAnotherContextException ex) {
|
|
addEServiceToCurrentContext();
|
|
eService = resourceRegistryClient.getInstance(EService.class, eServiceUUID);
|
|
// addToContext() is executed on HostingNode.
|
|
// If the EService is still not available we need to create activates
|
|
// relation because does not exists otherwise the EService should
|
|
// already be in the context due to propagation constraint.
|
|
eService = createActivatesRelation(eService).getTarget();
|
|
}
|
|
updateFacets();
|
|
} catch (ResourceRegistryException e) {
|
|
throw e;
|
|
}
|
|
return eService;
|
|
}
|
|
|
|
public EService updateFacets() throws ResourceRegistryException {
|
|
logger.debug("Updating {} for {}", EService.NAME, applicationContext.configuration().name());
|
|
|
|
StateFacet stateFacet = null;
|
|
EventFacet eventFacet = null;
|
|
|
|
Date date = Calendar.getInstance().getTime();
|
|
|
|
List<ConsistsOf<? extends Resource, ? extends Facet>> consistsOfToRemove = new ArrayList<>();
|
|
|
|
List<ConsistsOf<? extends Resource, ? extends Facet>> consistsOfList = eService.getConsistsOf();
|
|
for (ConsistsOf<? extends Resource, ? extends Facet> c : consistsOfList) {
|
|
if (c.getTarget() instanceof StateFacet) {
|
|
stateFacet = (StateFacet) c.getTarget();
|
|
stateFacet = getStateFacet(stateFacet, date);
|
|
continue;
|
|
}
|
|
|
|
if(c.getTarget() instanceof EventFacet) {
|
|
eventFacet = (EventFacet) c.getTarget();
|
|
String value = eventFacet.getEvent();
|
|
if(value.compareTo(getState())==0) {
|
|
// This facet must be updated (the date must be updated) so it must not be removed from udpate
|
|
eventFacet.setDate(date);
|
|
continue;
|
|
}else {
|
|
// This is not the event facet to be updated
|
|
// Setting the variable to null so it will be created if the event does not already exists.
|
|
eventFacet = null;
|
|
}
|
|
}
|
|
|
|
consistsOfToRemove.add(c);
|
|
|
|
}
|
|
|
|
// Resource Update has effect only on specified facets.
|
|
// Removing the ones that have not to be changed.
|
|
consistsOfList.removeAll(consistsOfToRemove);
|
|
|
|
|
|
if(eventFacet == null) {
|
|
eventFacet = getEventFacet(date);
|
|
eService.addFacet(eventFacet);
|
|
}
|
|
|
|
try {
|
|
logger.trace("Updating {} for {} : {}", EService.NAME, applicationContext.configuration().name(), ElementMapper.marshal(eService));
|
|
}catch (Exception e) {
|
|
|
|
}
|
|
|
|
try {
|
|
eService = resourceRegistryPublisher.updateResource(eService);
|
|
}catch (ResourceRegistryException e) {
|
|
logger.error("Error trying to publish hosting node", e);
|
|
}
|
|
|
|
return eService;
|
|
}
|
|
|
|
private Activates<HostingNode, EService> createActivatesRelation(EService eService)
|
|
throws ResourceRegistryException {
|
|
|
|
HostingNode hostingNode = ((HostingNodeManager) applicationContext.container().properties().lookup(Constants.HOSTING_NODE_MANAGER_PROPERTY).value()).getHostingNode();
|
|
|
|
PropagationConstraint propagationConstraint = new PropagationConstraintImpl();
|
|
propagationConstraint.setRemoveConstraint(RemoveConstraint.cascade);
|
|
propagationConstraint.setAddConstraint(AddConstraint.propagate);
|
|
Activates<HostingNode, EService> activates = new ActivatesImpl<>(hostingNode, eService, propagationConstraint);
|
|
|
|
try {
|
|
logger.trace("Going to create {} and {} for application {} : {}", Activates.NAME, EService.NAME, applicationContext.configuration().name(), ElementMapper.marshal(activates));
|
|
}catch (Exception e) {
|
|
|
|
}
|
|
|
|
try {
|
|
activates = resourceRegistryPublisher.createIsRelatedTo(activates);
|
|
hostingNode.attachResource(activates);
|
|
} catch (NotFoundException e) {
|
|
logger.error("THIS IS REALLY STRANGE. YOU SHOULD NOT BE HERE. Error while creating {}.", activates, e);
|
|
throw e;
|
|
} catch (ResourceRegistryException e) {
|
|
logger.error("Error while creating {}", activates, e);
|
|
throw e;
|
|
}
|
|
|
|
return activates;
|
|
|
|
}
|
|
|
|
// public void removeEService() throws ResourceRegistryException {
|
|
// try {
|
|
// resourceRegistryPublisher.delete(eService);
|
|
// } catch (ResourceRegistryException e) {
|
|
// logger.error("Unable to delete {}. Going to set the state to {}", applicationContext.name(), getState());
|
|
// updateFacets();
|
|
// }
|
|
// }
|
|
|
|
public Map<UUID,String> getContextsUUID() throws Exception {
|
|
return resourceRegistryPublisher.getResourceContexts(eService);
|
|
}
|
|
|
|
}
|