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.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 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 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 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.getCurrentContextName()); } catch (Exception e) { logger.error("Unable to add {} with UUID {} to context ({})", HostingNode.NAME, uuid, ContextUtility.getCurrentContextName(), 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 = ContextCache.getInstance().getContextFullNameByUUID(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 isIdentifiedBy = new IsIdentifiedByImpl( 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(); createActivatesRelation(eService); } 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. createActivatesRelation(eService); } 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> consistsOfToRemove = new ArrayList<>(); List> consistsOfList = eService.getConsistsOf(); for (ConsistsOf 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 { eService = resourceRegistryPublisher.updateResource(eService); }catch (ResourceRegistryException e) { logger.error("error trying to publish hosting node", e); } return eService; } private Activates 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 activates = new ActivatesImpl<>(hostingNode, eService, propagationConstraint); 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 getContextsUUID() throws Exception { return resourceRegistryPublisher.getResourceContexts(eService); } }