package org.gcube.informationsystem.resourceregistry.instances.model.entities; import java.util.ArrayList; 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 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.ArrayNode; import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode; import org.gcube.informationsystem.base.reference.AccessType; import org.gcube.informationsystem.contexts.reference.entities.Context; import org.gcube.informationsystem.model.reference.entities.Entity; import org.gcube.informationsystem.model.reference.entities.Facet; import org.gcube.informationsystem.model.reference.entities.Resource; import org.gcube.informationsystem.model.reference.relations.ConsistsOf; import org.gcube.informationsystem.model.reference.relations.Relation; 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.ContextException; import org.gcube.informationsystem.resourceregistry.api.exceptions.entities.EntityAlreadyPresentException; import org.gcube.informationsystem.resourceregistry.api.exceptions.queries.InvalidQueryException; import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaException; import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaViolationException; import org.gcube.informationsystem.resourceregistry.contexts.ContextUtility; import org.gcube.informationsystem.resourceregistry.contexts.ServerContextCache; import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext; import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext.PermissionMode; import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagement; import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagementUtility; import org.gcube.informationsystem.resourceregistry.instances.base.entities.EntityElementManagement; import org.gcube.informationsystem.resourceregistry.instances.model.ERManagement; import org.gcube.informationsystem.resourceregistry.instances.model.Operation; import org.gcube.informationsystem.resourceregistry.instances.model.relations.RelationManagement; import org.gcube.informationsystem.resourceregistry.types.TypesCache; import org.gcube.informationsystem.resourceregistry.utils.MetadataUtility; import org.gcube.informationsystem.resourceregistry.utils.DBUtility; import org.gcube.informationsystem.types.reference.entities.EntityType; import com.arcadedb.database.Document; import com.arcadedb.database.RID; import com.arcadedb.graph.Edge; import com.arcadedb.graph.MutableVertex; import com.arcadedb.graph.Vertex; import com.arcadedb.graph.Vertex.DIRECTION; import com.arcadedb.query.sql.executor.Result; import com.arcadedb.query.sql.executor.ResultSet; import com.arcadedb.remote.RemoteDatabase; import com.arcadedb.schema.DocumentType; /** * @author Luca Frosini (ISTI - CNR) */ public abstract class EntityManagement extends EntityElementManagement implements ERManagement { /** * The source context of an addToContex */ protected SecurityContext sourceSecurityContext; /** * The target context of an addToContex/RemoveFromContext */ protected SecurityContext targetSecurityContext; /** * By the default the system honour the propagation constraints * so this variable is initialised as true. * * To revert a previous operation or for particular a maintenance * we could request to the service do not honour the propagation * constraints but under certain conditions and with some limitation * only. * These limitation are required to keep the system in a consistent * state. * In fact, this directive is only valid for Resources and IsRelatedTo * relations. We need to take in account that to add an * IsRelatedTo to a context always the source and target * Resources must be in such a Context. * Please also take into account that adding a Resource * to a context always imply to honour the propagation constraints * of ConsistsOf relations. In fact, a resource must be characterised * least by one facet in any context it belongs. Giving that we * cannot made assumption on which facets must be used. * A way could be to consider just the facets are mandatory for such a * Resource Type, but the type could not have mandatory facets * (even every Resource Type in the gCube Model has one mandatory facet). * As counterpart, when a Resource is removed from a Context all the facets * charactering it must be removed. * * This option can also be used in conjunction with * {@link ElementManagement#dryRun}=true. * This allow to simulate a sharing operation which requires * do not honour the propagation constraints. */ protected boolean honourPropagationConstraintsInContextSharing; @Override public void setSourceSecurityContext(SecurityContext sourceSecurityContext) { this.sourceSecurityContext = sourceSecurityContext; } @Override public SecurityContext getSourceSecurityContext() { return sourceSecurityContext; } @Override public void setTargetSecurityContext(SecurityContext targetSecurityContext) { this.targetSecurityContext = targetSecurityContext; } @Override public SecurityContext getTargetSecurityContext() { return sourceSecurityContext; } @Override public boolean isHonourPropagationConstraintsInContextSharing() { return honourPropagationConstraintsInContextSharing; } @Override public void setHonourPropagationConstraintsInContextSharing(boolean honourPropagationConstraintsInContextSharing) { this.honourPropagationConstraintsInContextSharing = honourPropagationConstraintsInContextSharing; } /** * Provide a cache edge-internal-id -> RelationManagement * this avoid to recreate the relationManagement of already visited edges */ protected Map> relationManagements; /* The instance is added to the context even is not in source context */ protected boolean forceAddToContext; /* Indicate that AddToContext skipped the instance because it was not the source context */ protected boolean skipped; protected EntityManagement(AccessType accessType) { super(accessType); this.ignoreStartWithKeys.add(IN_PREFIX.toLowerCase()); this.ignoreStartWithKeys.add(OUT_PREFIX.toLowerCase()); this.ignoreStartWithKeys.add(IN_PREFIX.toUpperCase()); this.ignoreStartWithKeys.add(OUT_PREFIX.toUpperCase()); this.relationManagements = new HashMap<>(); /* * By the default the system honour the propagation constraints * so this variable is initialised as true. */ this.honourPropagationConstraintsInContextSharing = true; this.skipped = false; } @Override public Vertex getElement() throws NotFoundException, AvailableInAnotherContextException, ResourceRegistryException { try { element = super.getElement(); } catch(NotFoundException e) { try { retrieveElementFromAnyContext(); throw getSpecificAvailableInAnotherContextException(typeName == null ? accessType.getName() : typeName + " with ID " + uuid + " is available in another " + Context.class.getSimpleName()); } catch(AvailableInAnotherContextException e1) { throw e1; } catch(Exception e1) { throw e; } } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new ResourceRegistryException(e); } return element; } /* * It works perfectly in case of any kind of update. In case of use from create * the cache does not work by using the ID because until commit the edge has a * fake id starting with - (minus) sign. This not imply any collateral effect * but a better solution is a desiderata. */ protected RelationManagement getRelationManagement(Edge edge) throws ResourceRegistryException { String id = edge.getIdentity().toString(); RelationManagement relationManagement = relationManagements.get(id); if(relationManagement == null) { relationManagement = ElementManagementUtility.getRelationManagement(getWorkingContext(), database, edge); relationManagements.put(id, relationManagement); } return relationManagement; } public void addToRelationManagements(RelationManagement relationManagement) throws ResourceRegistryException { Edge elem = relationManagement.getElement(); String id = elem.getIdentity().toString(); if(relationManagements.get(id) != null && relationManagements.get(id) != relationManagement) { StringBuilder errorMessage = new StringBuilder(); errorMessage.append("Two different instance of "); errorMessage.append(relationManagement.getClass().getSimpleName()); errorMessage.append(" point to the same "); errorMessage.append(elem.getClass().getSimpleName()); errorMessage.append(". "); errorMessage.append(DBUtility.SHOULD_NOT_OCCUR_ERROR_MESSAGE); throw new ResourceRegistryException(errorMessage.toString()); } relationManagements.put(id, relationManagement); } protected static JsonNode addRelation(JsonNode sourceResource, JsonNode relation, String arrayKey) throws ResourceRegistryException { ObjectMapper objectMapper = new ObjectMapper(); ArrayNode relationArray = objectMapper.createArrayNode(); try { if(sourceResource.has(arrayKey)) { relationArray = (ArrayNode) sourceResource.get(arrayKey); } relationArray.add(relation); ((ObjectNode) sourceResource).replace(arrayKey, relationArray); } catch(Exception e) { throw new ResourceRegistryException(e); } return sourceResource; } @Override protected Vertex createVertex() throws EntityAlreadyPresentException, ResourceRegistryException { logger.trace("Going to create {} for {} ({}) using {}", Vertex.class.getSimpleName(), accessType.getName(), typeName, jsonNode); try { // TODO // if(documentType.isAbstract()) { // String error = String.format( // "Trying to create an instance of %s of type %s which is abstract. The operation will be aborted.", // accessType.getName(), typeName); // throw new SchemaViolationException(error); // } MutableVertex vertexEntity = database.newVertex(typeName); try { if(uuid != null) { Vertex v = getElement(); if(v != null) { String error = String.format("A %s with UUID %s already exist", typeName, uuid.toString()); throw getSpecificAlreadyPresentException(error); } } } catch(NotFoundException e) { try { Document el = ElementManagementUtility.getAnyElementByUUID(uuid); String error = String.format("UUID %s is already used by another %s. This is not allowed.", uuid.toString(), (el instanceof Vertex) ? Entity.NAME : Relation.NAME); throw getSpecificAvailableInAnotherContextException(error); } catch(NotFoundException e1) { // OK the UUID is not already used. } } catch(AvailableInAnotherContextException e) { throw e; } this.element = vertexEntity; if(accessType == AccessType.RESOURCE) { // Facet and relation are created in calling method } else { updateProperties(documentType, element, jsonNode, ignoreKeys, ignoreStartWithKeys); } logger.debug("Created {} is {}", Vertex.class.getSimpleName(), DBUtility.getAsStringForLogging((Vertex) element)); return element; } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { logger.trace("Error while creating {} for {} ({}) using {}", Vertex.class.getSimpleName(), accessType.getName(), typeName, jsonNode, e); throw new ResourceRegistryException("Error Creating " + typeName + " with " + jsonNode, e.getCause()); } } protected void reallyAddToContext() throws ContextException, ResourceRegistryException { if(!forceAddToContext && !sourceSecurityContext.isElementInContext(getElement())) { // The element in not in the source security context. It will be skipped skipped = true; return; } targetSecurityContext.addElement(getElement(), database); /* * DO NOT UNCOMMENT * // affectedInstances.put(uuid, serializeSelfOnly()); * the instance is added in internalAddToContext() function after * the update of Metadata i.e. modifiedBy, lastUpdateTime */ if(honourPropagationConstraintsInContextSharing) { Iterable edges = getElement().getEdges(DIRECTION.OUT); for(Edge edge : edges) { RelationManagement relationManagement = getRelationManagement(edge); relationManagement.setDryRun(dryRun); relationManagement.setHonourPropagationConstraintsInContextSharing(honourPropagationConstraintsInContextSharing); relationManagement.setSourceSecurityContext(sourceSecurityContext); relationManagement.setTargetSecurityContext(targetSecurityContext); relationManagement.internalAddToContext(); affectedInstances.putAll(relationManagement.getAffectedInstances()); } } } @Override public void internalAddToContext() throws ContextException, ResourceRegistryException { try { setOperation(Operation.ADD_TO_CONTEXT); reallyAddToContext(); if(!skipped) { MetadataUtility.updateModifiedByAndLastUpdate(element); // element.save(); affectedInstances.put(uuid, serializeAsAffectedInstance()); sanityCheck(); } } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new ResourceRegistryException( "Error Adding " + typeName + " to " + targetSecurityContext.toString(), e.getCause()); } } @Override public void addToContext(UUID contextUUID) throws SchemaViolationException, NotFoundException, ContextException, ResourceRegistryException { String contextFullName = ServerContextCache.getInstance().getContextFullNameByUUID(contextUUID); logger.info("Going to add {} with UUID {} to Context with UUID {} (i.e. {})", accessType.getName(), uuid, contextUUID, contextFullName); RemoteDatabase current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal(); try { workingContext = ContextUtility.getAdminSecurityContext(); database = workingContext.getRemoteDatabase(PermissionMode.WRITER); database.begin(); setAsEntryPoint(); sourceSecurityContext = ContextUtility.getCurrentSecurityContext(); targetSecurityContext = ContextUtility.getInstance().getSecurityContextByUUID(contextUUID); internalAddToContext(); if(!dryRun) { database.commit(); }else { database.rollback(); } logger.info("{} with UUID {} successfully added to Context with UUID {} (i.e. {})", typeName, uuid, contextUUID, contextFullName); } catch(ResourceRegistryException e) { logger.error("Unable to add {} with UUID {} to Context with UUID {} (i.e. {}) - Reason is {}", typeName, uuid, contextUUID, contextFullName, e.getMessage()); if(database != null) { database.rollback(); } throw e; } catch(Exception e) { logger.error("Unable to add {} with UUID {} to Context with UUID {} (i.e. {})", typeName, uuid, contextUUID, contextFullName, e); if(database != null) { database.rollback(); } throw new ContextException(e); } finally { if(database != null) { database.close(); } // if(current!=null) { // current.activateOnCurrentThread(); // } } } @Override public void internalRemoveFromContext() throws ContextException, ResourceRegistryException { try { setOperation(Operation.REMOVE_FROM_CONTEXT); reallyRemoveFromContext(); MetadataUtility.updateModifiedByAndLastUpdate(element); // element.save(); affectedInstances.put(uuid, serializeAsAffectedInstance()); sanityCheck(); } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new ResourceRegistryException( "Error Removing " + typeName + " from " + targetSecurityContext.toString(), e.getCause()); } } protected void reallyRemoveFromContext() throws ContextException, ResourceRegistryException { if(!targetSecurityContext.isElementInContext(getElement())) { // The element in not in the source security context. It will be skipped return; } if(honourPropagationConstraintsInContextSharing) { Iterable edges = getElement().getEdges(DIRECTION.OUT); for(Edge edge : edges) { RelationManagement relationManagement = getRelationManagement(edge); relationManagement.setDryRun(dryRun); relationManagement.setHonourPropagationConstraintsInContextSharing(honourPropagationConstraintsInContextSharing); // Not needed relationManagement.setSourceSecurityContext(sourceSecurityContext); relationManagement.setTargetSecurityContext(targetSecurityContext); relationManagement.internalRemoveFromContext(); addToRelationManagements(relationManagement); affectedInstances.putAll(relationManagement.getAffectedInstances()); } } targetSecurityContext.removeElement(getElement(), database); /* * DO NOT UNCOMMENT * the instance is added internalAddToContext() function after * the update of Metadata i.e. modifiedBy, lastUpdateTime * affectedInstances.put(uuid, serializeSelfOnly()); */ } @Override public void removeFromContext(UUID contextUUID) throws SchemaViolationException, NotFoundException, ContextException, ResourceRegistryException { logger.debug("Going to remove {} with UUID {} from Context with UUID {}", typeName, uuid, contextUUID); RemoteDatabase current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal(); try { workingContext = ContextUtility.getAdminSecurityContext(); database = workingContext.getRemoteDatabase(PermissionMode.WRITER); database.begin(); setAsEntryPoint(); // Not needed sourceSecurityContext = ContextUtility.getCurrentSecurityContext(); targetSecurityContext = ContextUtility.getInstance().getSecurityContextByUUID(contextUUID); internalRemoveFromContext(); if(!dryRun) { database.commit(); }else { database.rollback(); } logger.info("{} with UUID {} successfully removed from Context with UUID {}", typeName, uuid, contextUUID); } catch(ResourceRegistryException e) { logger.error("Unable to remove {} with UUID {} from Context with UUID {}", typeName, uuid, contextUUID); if(database != null) { database.rollback(); } throw e; } catch(Exception e) { logger.error("Unable to remove {} with UUID {} from Context with UUID {}", typeName, uuid, contextUUID, e); if(database != null) { database.rollback(); } throw new ContextException(e); } finally { if(database != null) { database.close(); } // if(current!=null) { // current.activateOnCurrentThread(); // } } } @Override public String reallyGetAll(boolean polymorphic) throws ResourceRegistryException { ObjectMapper objectMapper = new ObjectMapper(); ArrayNode arrayNode = objectMapper.createArrayNode(); Iterable iterable = database.browseClass(typeName, polymorphic); for(Document vertex : iterable) { EntityManagement entityManagement = ElementManagementUtility.getEntityManagement(getWorkingContext(), database, (Vertex) vertex); try { entityManagement.setAsEntryPoint(); JsonNode jsonNode = entityManagement.serializeAsJsonNode(); arrayNode.add(jsonNode); } catch(ResourceRegistryException e) { logger.error("Unable to correctly serialize {}. It will be excluded from results. {}", vertex.toString(), DBUtility.SHOULD_NOT_OCCUR_ERROR_MESSAGE); } } try { return objectMapper.writeValueAsString(arrayNode); } catch(JsonProcessingException e) { throw new ResourceRegistryException(e); } } public boolean propertyMatchRequestedValue(Vertex v, String key, String requestedValue, Object instanceValue) throws SchemaException, ResourceRegistryException { return requestedValue.compareTo(instanceValue.toString())==0; /* OClass documentType = ElementManagement.getOClass(v); OProperty oProperty = documentType.getProperty(key); if(oProperty==null){ // It is an additional property return requestedValue.compareTo(instanceValue.toString())==0; } OType oType = oProperty.getType(); switch (oType) { case BOOLEAN: Boolean requested = Boolean.valueOf(requestedValue.toLowerCase()); return requested == (Boolean) instanceValue; case STRING: return requestedValue.compareTo((String) instanceValue)==0; default: return false; } */ } /* public String reallyQuery(String relationType, String referenceType, UUID referenceUUID, DIRECTION direction, boolean polymorphic, Map constraint, boolean includeRelationInResult) throws ResourceRegistryException { */ public String reallyQuery(String relationType, String referenceType, UUID referenceUUID, DIRECTION direction, boolean polymorphic, Map constraint) throws ResourceRegistryException { ObjectMapper objectMapper = new ObjectMapper(); ArrayNode arrayNode = objectMapper.createArrayNode(); Iterable references = null; if(referenceUUID != null) { Document element = null; try { element = ElementManagementUtility.getAnyElementByUUID(database, referenceUUID); }catch (ResourceRegistryException e) { String error = String.format("No instace with UUID %s exists", referenceUUID.toString()); throw new InvalidQueryException(error); } if(element instanceof Vertex) { EntityManagement entityManagement = ElementManagementUtility.getEntityManagement(getWorkingContext(), database, (Vertex) element); String elementType = entityManagement.getTypeName(); if(elementType.compareTo(referenceType) != 0) { if(polymorphic && getDocumentType().isSubTypeOf(referenceType)) { // OK } else { String error = String.format("Referenced instace with UUID %s is not a %s", referenceUUID, referenceType); throw new InvalidQueryException(error); } } List vertexes = new ArrayList<>(); vertexes.add((Vertex) element); references = vertexes; } else { String error = String.format("Referenced instace with UUID %s is not a %s", referenceUUID, referenceType); throw new InvalidQueryException(error); } } else { references = database.browseClass(referenceType, polymorphic); } Set analysed = new HashSet<>(); for(Object r : references) { Vertex v = (Vertex) r; boolean skip = false; // checking if the constraints are satisfied for(String key : constraint.keySet()) { String value = constraint.get(key); Object o = v.get(key); if(value==null) { if(o==null) { //ok }else { skip = true; break; } }else { if(o==null) { // The vertex has not a required property to be tested // or the property is null skip = true; break; }else { skip = !propertyMatchRequestedValue(v, key, value, o); if(skip) { break; } } } } if(skip) { continue; } List directions = new ArrayList<>(); if(direction==DIRECTION.BOTH) { directions.add(DIRECTION.IN); directions.add(DIRECTION.OUT); }else { directions.add(direction); } for(DIRECTION d : directions) { Iterable edges = v.getEdges(ElementManagement.opposite(d), relationType); for(Edge edge : edges) { Vertex vertex = edge.getVertex(d); RID vertexRID = vertex.getIdentity(); if(analysed.contains(vertexRID)) { continue; } analysed.add(vertexRID); if(v.getIdentity().compareTo(vertexRID) == 0) { continue; } DocumentType documentType = ElementManagementUtility.getDocumentType(vertex); /* * If the requested type (i.e. elementType) * differs form the resulting type (i.e. documentType.getName()) * we need to evaluate if polymorphism is requested and * if the resulting type is a subclass of the requested type * */ if(documentType.getName().compareTo(typeName)!=0) { if(polymorphic && documentType.isSubTypeOf(typeName)) { // OK } else { // excluding from results continue; } } EntityManagement entityManagement = ElementManagementUtility.getEntityManagement(getWorkingContext(), database, vertex); try { if(referenceUUID!=null && entityManagement.getUUID().compareTo(referenceUUID) == 0) { continue; } /* JsonNode jsonNode; if(includeRelationInResult) { RelationManagement relationManagement = ElementManagementUtility.getRelationManagement(getWorkingContext(), database, edge); jsonNode = relationManagement.serializeAsJsonNode(); }else { jsonNode = entityManagement.serializeAsJsonNode(); } */ entityManagement.setAsEntryPoint(); JsonNode node = entityManagement.serializeAsJsonNode(); arrayNode.add(node); } catch(ResourceRegistryException e) { logger.error("Unable to correctly serialize {}. It will be excluded from results. {}", vertex.toString(), DBUtility.SHOULD_NOT_OCCUR_ERROR_MESSAGE); } } } } try { return objectMapper.writeValueAsString(arrayNode); } catch(JsonProcessingException e) { throw new ResourceRegistryException(e); } } public String reallyQueryTraversal(String relationType, String referenceType, UUID referenceUUID, DIRECTION direction, boolean polymorphic, Map constraint) throws ResourceRegistryException { ObjectMapper objectMapper = new ObjectMapper(); ArrayNode arrayNode = objectMapper.createArrayNode(); if(referenceUUID != null) { constraint.put(Entity.ID_PROPERTY, referenceUUID.toString()); } // TODO check types /* * SELECT FROM (TRAVERSE inE('isIdentifiedBy'), outV('EService') FROM (SELECT * FROM SoftwareFacet WHERE group='VREManagement' AND name='SmartExecutor')) * * WHERE type='EService' // Only is not polymorphic */ StringBuilder selectStringBuilder = new StringBuilder("SELECT FROM (TRAVERSE "); selectStringBuilder.append(direction.name().toLowerCase()); selectStringBuilder.append("E('"); selectStringBuilder.append(relationType); selectStringBuilder.append("'), "); selectStringBuilder.append(ElementManagement.opposite(direction).name().toLowerCase()); selectStringBuilder.append("V('"); selectStringBuilder.append(typeName); selectStringBuilder.append("') FROM (SELECT FROM "); selectStringBuilder.append(referenceType); boolean first = true; for(String key : constraint.keySet()) { if(first) { selectStringBuilder.append(" WHERE "); first = false; } else { selectStringBuilder.append(" AND "); } selectStringBuilder.append(key); selectStringBuilder.append("="); String value = constraint.get(key).trim(); selectStringBuilder.append("'"); selectStringBuilder.append(value); selectStringBuilder.append("'"); } selectStringBuilder.append(" ))"); if(!polymorphic) { selectStringBuilder.append(" WHERE type='"); selectStringBuilder.append(typeName); selectStringBuilder.append("'"); } String select = selectStringBuilder.toString(); logger.trace(select); ResultSet resultSet = database.command("sql", select); while(resultSet.hasNext()) { Result oResult = resultSet.next(); Document element = ElementManagementUtility.getElementFromOptional(oResult.getElement()); if(polymorphic) { DocumentType documentType = null; try { if(element instanceof Edge) { continue; } documentType = ElementManagementUtility.getDocumentType(element); } catch(Exception e) { String error = String.format("Unable to detect type of %s. %s", element.toString(), DBUtility.SHOULD_NOT_OCCUR_ERROR_MESSAGE); logger.error(error, e); throw new ResourceRegistryException(error); } if(documentType.isSubTypeOf(typeName)) { continue; } } Vertex vertex = (Vertex) element; EntityManagement entityManagement = ElementManagementUtility.getEntityManagement(getWorkingContext(), database, vertex); try { if(constraint.containsKey(Entity.ID_PROPERTY)) { String uuid = constraint.get(Entity.ID_PROPERTY); if(entityManagement.getUUID().compareTo(UUID.fromString(uuid)) == 0) { continue; } } entityManagement.setAsEntryPoint(); JsonNode jsonNode = entityManagement.serializeAsJsonNode(); arrayNode.add(jsonNode); } catch(ResourceRegistryException e) { logger.error("Unable to correctly serialize {}. It will be excluded from results. {}", vertex.toString(), DBUtility.SHOULD_NOT_OCCUR_ERROR_MESSAGE); } } try { return objectMapper.writeValueAsString(arrayNode); } catch(JsonProcessingException e) { throw new ResourceRegistryException(e); } } /* public String query(String relationType, String referenceType, UUID referenceUUID, ODirection direction, boolean polymorphic, Map constraint, boolean includeRelationInResult) throws ResourceRegistryException { */ public String query(String relationType, String referenceType, UUID referenceUUID, DIRECTION direction, boolean polymorphic, Map constraint) throws ResourceRegistryException { RemoteDatabase current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal(); try { workingContext = ContextUtility.getAdminSecurityContext(); database = workingContext.getRemoteDatabase(PermissionMode.READER); setAsEntryPoint(); setOperation(Operation.QUERY); TypesCache typesCache = TypesCache.getInstance(); AccessType relationAccessType = typesCache.getCachedType(relationType).getAccessType(); if(relationAccessType != AccessType.IS_RELATED_TO && relationAccessType != AccessType.CONSISTS_OF) { String error = String.format("%s must be a relation type", relationType); throw new ResourceRegistryException(error); } AccessType referenceAccessType = typesCache.getCachedType(referenceType).getAccessType(); if(referenceAccessType != AccessType.RESOURCE && referenceAccessType != AccessType.FACET) { String error = String.format("%s must be a en entity type", referenceType); throw new ResourceRegistryException(error); } if(constraint == null) { constraint = new HashMap<>(); } switch(accessType) { case RESOURCE: if(relationAccessType == AccessType.CONSISTS_OF) { if(direction != DIRECTION.OUT) { String error = String.format("%s can only goes %s from %s.", relationType, DIRECTION.OUT.name(), typeName); throw new InvalidQueryException(error); } else { if(referenceAccessType != AccessType.FACET) { String error = String.format("%s can only has as target a %s. Provided instead %s : %s", relationType, Facet.NAME, referenceAccessType, referenceType); throw new InvalidQueryException(error); } } } break; case FACET: if(relationAccessType != AccessType.CONSISTS_OF || direction != DIRECTION.IN || referenceAccessType != AccessType.RESOURCE) { String error = String.format("%s can only has %s %s from a %s.", typeName, DIRECTION.IN.name(), ConsistsOf.NAME, Resource.NAME); throw new InvalidQueryException(error); } break; default: break; } // return reallyQuery(relationType, referenceType, referenceUUID, direction, polymorphic, constraint, includeRelationInResult); return reallyQuery(relationType, referenceType, referenceUUID, direction, polymorphic, constraint); } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new ResourceRegistryException(e); } finally { if(database != null) { database.close(); } // if(current!=null) { // current.activateOnCurrentThread(); // } } } @Override public void setForceAddToContext(Boolean forceAddToContext) { this.forceAddToContext = forceAddToContext; } }