package org.gcube.gcat.configuration.isproxies; import java.io.File; import java.io.FileReader; import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import javax.ws.rs.InternalServerErrorException; import org.gcube.com.fasterxml.jackson.core.JsonProcessingException; import org.gcube.com.fasterxml.jackson.databind.JsonNode; import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode; import org.gcube.gcat.api.configuration.CatalogueConfiguration; import org.gcube.gcat.configuration.service.FacetBasedISServiceCatalogueConfiguration; import org.gcube.gcat.configuration.service.ServiceCKANDB; import org.gcube.gcat.configuration.service.ServiceCatalogueConfiguration; import org.gcube.informationsystem.model.impl.properties.HeaderImpl; import org.gcube.informationsystem.model.impl.properties.PropagationConstraintImpl; import org.gcube.informationsystem.model.impl.relations.ConsistsOfImpl; import org.gcube.informationsystem.model.reference.entities.Entity; import org.gcube.informationsystem.model.reference.properties.Encrypted; 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.queries.templates.reference.entities.QueryTemplate; import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException; import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException; import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaViolationException; 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.resourceregistry.queries.templates.ResourceRegistryQueryTemplateClient; import org.gcube.informationsystem.resourceregistry.queries.templates.ResourceRegistryQueryTemplateClientFactory; import org.gcube.informationsystem.utils.ElementMapper; import org.gcube.resourcemanagement.model.impl.entities.facets.SimpleFacetImpl; import org.gcube.resourcemanagement.model.impl.entities.resources.EServiceImpl; import org.gcube.resourcemanagement.model.impl.relations.isrelatedto.CallsForImpl; import org.gcube.resourcemanagement.model.reference.entities.facets.AccessPointFacet; import org.gcube.resourcemanagement.model.reference.entities.facets.SimpleFacet; import org.gcube.resourcemanagement.model.reference.entities.resources.Configuration; import org.gcube.resourcemanagement.model.reference.entities.resources.EService; import org.gcube.resourcemanagement.model.reference.entities.resources.VirtualService; import org.gcube.resourcemanagement.model.reference.relations.isrelatedto.CallsFor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) */ public class FacetBasedISConfigurationProxy extends ISConfigurationProxy { private static Logger logger = LoggerFactory.getLogger(FacetBasedISConfigurationProxy.class); public static final String QUERY_TEMPLATE_DIRECTORY_NAME = "query-template"; public static final String GCAT_ESERVICE_UUID_VARNAME = "$uuid"; public static final String GET_CALLS_FOR_QUERY_TEMPLATE_FILENAME = "01-get-calls-for-query-template.json"; public static final String QUERY_DIRECTORY_NAME = "query"; public static final String GET_CATALOGUE_VIRTUAL_SERVICE_FILENAME = "01-get-catalogue-virtual-service.json"; public static final String GET_GCAT_CONFIGURATION_FILENAME = "02-get-gcat-configuration.json"; public static final String GET_SIMPLE_FACET_OF_GCAT_CONFIGURATION_FILENAME = "03-get-simple-facet-of-gcat-configuration.json"; public static final String GET_ACCESS_POINT_FACET_OF_CKAN_SERVICE_FILENAME = "05-get-access-point-facet-of-ckan-service.json"; public static final String GET_ACCESS_POINT_FACET_OF_POSTGRES_CKAN_DB_FILENAME = "07-get-access-point-facet-of-postgres-ckan-db.json"; public static final String GET_ACCESS_POINT_FACET_OF_SOLR_SERVICE_FILENAME = "09-get-access-point-facet-of-solr-service.json"; private static String queryTemplateName; static { ResourceRegistryQueryTemplateClient rrqtc = ResourceRegistryQueryTemplateClientFactory.create(); try { queryTemplateName = installQueryTemplate(rrqtc); } catch (Exception e) { throw new RuntimeException(e); } } protected static QueryTemplate getQueryTemplate() throws Exception { File queryTemplateFile = getJsonQueryTemplateFromFile(GET_CALLS_FOR_QUERY_TEMPLATE_FILENAME); QueryTemplate queryTemplate = ElementMapper.unmarshal(QueryTemplate.class, new FileReader(queryTemplateFile)); return queryTemplate; } protected static String installQueryTemplate(ResourceRegistryQueryTemplateClient rrqtc) throws Exception { QueryTemplate queryTemplate = getQueryTemplate(); /* * Going to create/update the query template. * No need to test if exists and/or if is the last version. */ queryTemplate = rrqtc.update(queryTemplate); return queryTemplate.getName(); } protected static File getFile(String directoryName, String filename) throws Exception { URL directoryURL = FacetBasedISConfigurationProxy.class.getClassLoader().getResource(directoryName); File directory = new File(directoryURL.toURI()); return new File(directory, filename); } protected static File getJsonQueryTemplateFromFile(String filename) throws Exception { return getFile(QUERY_TEMPLATE_DIRECTORY_NAME, filename); } protected static File getJsonQueryFromFile(String filename) throws Exception { return getFile(QUERY_DIRECTORY_NAME, filename); } // // Configuration // ---------------------- // IsCustomizedBy | | // -----------------> | gcat-configuration | // / | | // / ---------------------- // EService VirtualService / // ------------ ----------------------------- // | | CallsFor | | // | gcat | ------------> | catalogue-virtual-service | // | | | | // ------------ ----------------------------- // \ EService // \ -------------------- // \ Uses | | // \ ------------------> | postgres-ckan-db | // \ / | | // \ EService / -------------------- // \ ----------------- // \ CallsFor | | // -------------> | ckan | // | | // ----------------- EService // \ -------------------- // \ Uses | | // ------------------> | solr | // | | // -------------------- /* * Some resources are not needed to be queried and maintained. * Leaving comment to remember that is not an error * protected Configuration configuration; * * public static final String GET_CKAN_SERVICE_FILENAME = "04-get-ckan-service.json"; * protected EService ckanService; * * public static final String GET_POSTGRES_CKAN_DB_FILENAME = "06-get-postgres-ckan-db.json"; * protected EService solrService; * * public static final String GET_SOLR_SERVICE_FILENAME = "08-get-solr-service.json"; * protected EService ckanDB; * */ protected final ObjectMapper objectMapper; protected final ResourceRegistryClient resourceRegistryClient; protected final ResourceRegistryPublisher resourceRegistryPublisher; /* * We need to keep this resource because we want to create * an IsRelatedTo relation * i.e. EService(gcat) --CallsFor--> VirtualService(catalogue-virtual-service) */ protected VirtualService virtualService; protected SimpleFacet configurationSimpleFacet; protected String gcatEServiceID; public FacetBasedISConfigurationProxy(String context) { super(context); objectMapper = new ObjectMapper(); resourceRegistryClient = ResourceRegistryClientFactory.create(); resourceRegistryPublisher = ResourceRegistryPublisherFactory.create(); } public VirtualService getVirtualService() { if(virtualService==null) { virtualService = queryVirtualService(); } return virtualService; } public void setGcatEServiceID(String gcatEServiceID) { this.gcatEServiceID = gcatEServiceID; } public List> getCallsForToVirtualService() throws Exception { ResourceRegistryQueryTemplateClient rrqtc = ResourceRegistryQueryTemplateClientFactory.create(); ObjectNode objectNode = objectMapper.createObjectNode(); objectNode.put(GCAT_ESERVICE_UUID_VARNAME, gcatEServiceID); List> callsForList = rrqtc.run(queryTemplateName, objectNode); return callsForList; } public List> deleteCallsForToVirtualService(List> callsForList) throws SchemaViolationException, NotFoundException, ResourceRegistryException { for(CallsFor cf : callsForList) { resourceRegistryPublisher.delete(cf); } return callsForList; } public List> deleteCallsForToVirtualService() throws Exception { List> callsForList = getCallsForToVirtualService(); return deleteCallsForToVirtualService(callsForList); } public CallsFor createCallsForToVirtualService() throws Exception { List> callsForList = getCallsForToVirtualService(); CallsFor callsFor = null; int size = callsForList.size(); UUID gcatEServiceUUID = UUID.fromString(gcatEServiceID); if(size>1) { logger.warn("There are {} instances of {} relation beetween gcat Eservice with UUID {} and the {} (catalogue-virtual-service). This is very strange because there should be only one. We are going to delete them and recreated a new one.", callsForList.size(), CallsFor.NAME, gcatEServiceID, VirtualService.NAME); logger.trace("{} relation instances that are going to be deleted are {}", CallsFor.NAME, ElementMapper.marshal(callsForList)); deleteCallsForToVirtualService(callsForList); size = 0; } if(size==0) { PropagationConstraint propagationConstraint = new PropagationConstraintImpl(); propagationConstraint.setAddConstraint(AddConstraint.unpropagate); propagationConstraint.setRemoveConstraint(RemoveConstraint.keep); EService gcatEService = new EServiceImpl(); gcatEService.setHeader(new HeaderImpl(gcatEServiceUUID)); VirtualService virtualService = queryVirtualService(); callsFor = new CallsForImpl(gcatEService, virtualService, propagationConstraint); callsFor = resourceRegistryPublisher.create(callsFor); }else if(size==1){ callsFor = callsForList.get(0); } return callsFor; } protected List queryListOfEntities(String query) throws Exception { logger.trace("Going to request the following query:\n{}", query); String result = resourceRegistryClient.jsonQuery(query); logger.trace("The query:\n{}\nproduced the following result:\n{}", query, result); List entities = ElementMapper.unmarshalList(Entity.class, result); return entities; } protected JsonNode getQuery(File jsonQueryFile) throws Exception { JsonNode query = objectMapper.readTree(jsonQueryFile); return query; } protected E getUniqueEntity(List entities, String originalQuery) throws JsonProcessingException { int size = entities.size(); if(entities==null || size==0) { String message = String.format("No instance found with query:\n%s", originalQuery); logger.error(message); throw new InternalServerErrorException(message); } if(size>1) { String message = String.format( "Too many instances found (i.e. expected 1, found %d) with query:\n%s\nthe obtained result is:\n%s", size, originalQuery, ElementMapper.marshal(entities)); logger.error(message); throw new InternalServerErrorException(message); } return entities.get(0); } protected Entity queryEntity(String filename) throws Exception{ File jsonQueryFile = getJsonQueryFromFile(filename); JsonNode query = getQuery(jsonQueryFile); String jsonQueryAsString = objectMapper.writeValueAsString(query); List entities = queryListOfEntities(jsonQueryAsString); return getUniqueEntity(entities, jsonQueryAsString); } protected VirtualService queryVirtualService() throws InternalServerErrorException { try { VirtualService virtualService = (VirtualService) queryEntity(GET_CATALOGUE_VIRTUAL_SERVICE_FILENAME); return virtualService; }catch (Exception e) { throw new InternalServerErrorException(e); } } protected Configuration queryGcatConfiguration() throws Exception { Configuration configuration = (Configuration) queryEntity(GET_GCAT_CONFIGURATION_FILENAME); return configuration; } protected SimpleFacet queryConfigurationSimpleFacet() throws Exception { SimpleFacet configurationSimpleFacet = (SimpleFacet) queryEntity(GET_SIMPLE_FACET_OF_GCAT_CONFIGURATION_FILENAME); return configurationSimpleFacet; } protected AccessPointFacet queryCkanServiceAccessPointFacet() throws Exception { AccessPointFacet accessPointFacet = (AccessPointFacet) queryEntity(GET_ACCESS_POINT_FACET_OF_CKAN_SERVICE_FILENAME); return accessPointFacet; } protected AccessPointFacet queryPostgresCkanDBAccessPointFacet() throws Exception { AccessPointFacet accessPointFacet = (AccessPointFacet) queryEntity(GET_ACCESS_POINT_FACET_OF_POSTGRES_CKAN_DB_FILENAME); return accessPointFacet; } public AccessPointFacet querySolrServiceAccessPointFacet() throws Exception { AccessPointFacet accessPointFacet = (AccessPointFacet) queryEntity(GET_ACCESS_POINT_FACET_OF_SOLR_SERVICE_FILENAME); return accessPointFacet; } protected ServiceCatalogueConfiguration setConfigurationInfoFromSimpleFacet(SimpleFacet configurationSimpleFacet, ServiceCatalogueConfiguration catalogueConfiguration) throws Exception { Header header = configurationSimpleFacet.getHeader(); if(header!=null && header.getUUID()!=null) { catalogueConfiguration.setID(header.getUUID().toString()); } catalogueConfiguration.setModerationEnabled((boolean) configurationSimpleFacet.getAdditionalProperty(CatalogueConfiguration.MODERATION_ENABLED_KEY)); catalogueConfiguration.setNotificationToUsersEnabled((boolean) configurationSimpleFacet.getAdditionalProperty(CatalogueConfiguration.NOTIFICATION_TO_USER_ENABLED_KEY)); catalogueConfiguration.setSocialPostEnabled((boolean) configurationSimpleFacet.getAdditionalProperty(CatalogueConfiguration.SOCIAL_POST_ENABLED_KEY)); catalogueConfiguration.setDefaultOrganization((String) configurationSimpleFacet.getAdditionalProperty(CatalogueConfiguration.DEFAULT_ORGANIZATION_KEY)); Object supportedOrganizationsObj = configurationSimpleFacet.getAdditionalProperty(CatalogueConfiguration.SUPPORTED_ORGANIZATIONS_KEY); boolean forceUpdate = false; if(supportedOrganizationsObj!=null && supportedOrganizationsObj instanceof Collection) { @SuppressWarnings("unchecked") Set supportedOrganizations = new HashSet((Collection) supportedOrganizationsObj); catalogueConfiguration.setSupportedOrganizations(supportedOrganizations); }else { Set supportedOrganizations = new HashSet<>(); supportedOrganizations.add(catalogueConfiguration.getDefaultOrganization()); configurationSimpleFacet.setAdditionalProperty(CatalogueConfiguration.SUPPORTED_ORGANIZATIONS_KEY, supportedOrganizations); forceUpdate = true; catalogueConfiguration.setSupportedOrganizations(supportedOrganizations); } Map additionalProperties = new HashMap<>(configurationSimpleFacet.getAdditionalProperties()); for(String key : additionalProperties.keySet()) { if(!CatalogueConfiguration.KNOWN_PROPERTIES.contains(key)) { if(key.startsWith("@")) { continue; } Object value = additionalProperties.get(key); catalogueConfiguration.setAdditionalProperty(key, value); } } if(forceUpdate) { updateOnIS(); } return catalogueConfiguration; } public ServiceCatalogueConfiguration setCkanServiceInfo(ServiceCatalogueConfiguration catalogueConfiguration) throws Exception { AccessPointFacet ckanServiceAccessPointFacet = queryCkanServiceAccessPointFacet(); catalogueConfiguration.setCkanURL(ckanServiceAccessPointFacet.getEndpoint().toString()); Encrypted encrypted = (Encrypted) ckanServiceAccessPointFacet.getAdditionalProperty(CatalogueConfiguration.SYS_ADMIN_TOKEN_KEY); String encryptedPassword = encrypted.getEncryptedValue(); catalogueConfiguration.setSysAdminToken(encryptedPassword); return catalogueConfiguration; } public ServiceCatalogueConfiguration setCkanDBInfo(ServiceCatalogueConfiguration catalogueConfiguration) throws Exception { AccessPointFacet postgresCkanDBAccessPointFacet = queryPostgresCkanDBAccessPointFacet(); ServiceCKANDB ckanDB = new ServiceCKANDB(); String ckanDbURL = postgresCkanDBAccessPointFacet.getEndpoint().toString(); ckanDB.setUrl(ckanDbURL); Encrypted encrypted = (Encrypted) postgresCkanDBAccessPointFacet.getAdditionalProperty(ServiceCKANDB.PASSWORD_KEY); String encryptedPassword = encrypted.getEncryptedValue(); ckanDB.setEncryptedPassword(encryptedPassword); String username = (String) postgresCkanDBAccessPointFacet.getAdditionalProperty(ServiceCKANDB.USERNAME_KEY); ckanDB.setUsername(username); catalogueConfiguration.setCkanDB(ckanDB); return catalogueConfiguration; } public ServiceCatalogueConfiguration setSolrServiceInfo(ServiceCatalogueConfiguration catalogueConfiguration) throws Exception { AccessPointFacet solrServiceAccessPointFacet = querySolrServiceAccessPointFacet(); String solrURL = solrServiceAccessPointFacet.getEndpoint().toString(); catalogueConfiguration.setSolrURL(solrURL); return catalogueConfiguration; } protected SimpleFacet getSimpleFacetFromConfiguration(ServiceCatalogueConfiguration catalogueConfiguration) { SimpleFacet simpleFacet = new SimpleFacetImpl(); if(catalogueConfiguration.getID()!=null) { UUID uuid = null; try { uuid = UUID.fromString(catalogueConfiguration.getID()); simpleFacet.getHeader().setUUID(uuid); }catch (Exception e) { } } simpleFacet.setAdditionalProperty(CatalogueConfiguration.MODERATION_ENABLED_KEY, catalogueConfiguration.isModerationEnabled()); simpleFacet.setAdditionalProperty(CatalogueConfiguration.NOTIFICATION_TO_USER_ENABLED_KEY, catalogueConfiguration.isNotificationToUsersEnabled()); simpleFacet.setAdditionalProperty(CatalogueConfiguration.SOCIAL_POST_ENABLED_KEY, catalogueConfiguration.isSocialPostEnabled()); simpleFacet.setAdditionalProperty(CatalogueConfiguration.DEFAULT_ORGANIZATION_KEY, catalogueConfiguration.getDefaultOrganization()); simpleFacet.setAdditionalProperty(CatalogueConfiguration.SUPPORTED_ORGANIZATIONS_KEY, catalogueConfiguration.getSupportedOrganizations()); Map additionalProperties = new HashMap<>(catalogueConfiguration.getAdditionalProperties()); for(String key : additionalProperties.keySet()) { if(!CatalogueConfiguration.KNOWN_PROPERTIES.contains(key)) { Object value = additionalProperties.get(key); simpleFacet.setAdditionalProperty(key, value); } } return simpleFacet; } @Override protected ServiceCatalogueConfiguration readFromIS() { try { catalogueConfiguration = new FacetBasedISServiceCatalogueConfiguration(context, this); configurationSimpleFacet = getISResource(); if(configurationSimpleFacet==null) { configurationSimpleFacet = getSimpleFacetFromConfiguration(catalogueConfiguration); }else { catalogueConfiguration = setConfigurationInfoFromSimpleFacet(configurationSimpleFacet, catalogueConfiguration); } catalogueConfiguration = setCkanServiceInfo(catalogueConfiguration); catalogueConfiguration = setCkanDBInfo(catalogueConfiguration); catalogueConfiguration = setSolrServiceInfo(catalogueConfiguration); }catch (InternalServerErrorException e) { throw e; }catch (Exception e) { throw new InternalServerErrorException(e); } return catalogueConfiguration; } @Override public void delete() { SimpleFacet simpleFacet = getISResource(); if(simpleFacet!=null) { try { resourceRegistryPublisher.delete(simpleFacet); } catch (Exception e) { throw new InternalServerErrorException("Unable to delete SimpleFacet with UUID " + simpleFacet.getHeader().getUUID().toString(), e); } } } @Override protected ServiceCatalogueConfiguration createOnIS() throws Exception { UUID uuid = configurationSimpleFacet.getHeader().getUUID(); if(uuid==null) { Configuration gcatConfiguration = queryGcatConfiguration(); ConsistsOf co = new ConsistsOfImpl<>(gcatConfiguration, configurationSimpleFacet); co = resourceRegistryPublisher.create(co); configurationSimpleFacet = co.getTarget(); setConfigurationInfoFromSimpleFacet(configurationSimpleFacet, catalogueConfiguration); } return catalogueConfiguration; } @Override protected SimpleFacet getISResource() { if(configurationSimpleFacet==null) { try { configurationSimpleFacet = queryConfigurationSimpleFacet(); }catch (Exception e) { return null; } } return configurationSimpleFacet; } @Override protected ServiceCatalogueConfiguration updateOnIS() throws Exception { Header header = configurationSimpleFacet.getHeader(); if(header!=null && header.getUUID()!=null) { configurationSimpleFacet = getSimpleFacetFromConfiguration(catalogueConfiguration); configurationSimpleFacet = resourceRegistryPublisher.update(configurationSimpleFacet); setConfigurationInfoFromSimpleFacet(configurationSimpleFacet, catalogueConfiguration); } return catalogueConfiguration; } }