424 lines
15 KiB
Java
424 lines
15 KiB
Java
package org.gcube.informationsystem.resourceregistry.contexts.entities;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.UUID;
|
|
|
|
import org.gcube.informationsystem.base.reference.AccessType;
|
|
import org.gcube.informationsystem.context.reference.entities.Context;
|
|
import org.gcube.informationsystem.context.reference.relations.IsParentOf;
|
|
import org.gcube.informationsystem.model.reference.properties.Header;
|
|
import org.gcube.informationsystem.model.reference.relations.Relation;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.context.ContextAlreadyPresentException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.context.ContextException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.context.ContextNotFoundException;
|
|
import org.gcube.informationsystem.resourceregistry.api.exceptions.entity.EntityAvailableInAnotherContextException;
|
|
import org.gcube.informationsystem.resourceregistry.contexts.ContextUtility;
|
|
import org.gcube.informationsystem.resourceregistry.contexts.relations.IsParentOfManagement;
|
|
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext;
|
|
import org.gcube.informationsystem.resourceregistry.dbinitialization.DatabaseEnvironment;
|
|
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagement;
|
|
import org.gcube.informationsystem.resourceregistry.instances.base.entities.EntityElementManagement;
|
|
import org.gcube.informationsystem.resourceregistry.utils.Utility;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
|
import com.fasterxml.jackson.databind.node.NullNode;
|
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
|
|
import com.orientechnologies.orient.core.record.ODirection;
|
|
import com.orientechnologies.orient.core.record.OEdge;
|
|
import com.orientechnologies.orient.core.record.OVertex;
|
|
import com.orientechnologies.orient.core.record.impl.ODocument;
|
|
import com.orientechnologies.orient.core.sql.executor.OResultSet;
|
|
|
|
/**
|
|
* @author Luca Frosini (ISTI - CNR)
|
|
*/
|
|
public class ContextManagement extends EntityElementManagement<Context> {
|
|
|
|
private static Logger logger = LoggerFactory.getLogger(ContextManagement.class);
|
|
|
|
protected String name;
|
|
|
|
private void init() {
|
|
this.ignoreStartWithKeys.add(Context.PARENT_PROPERTY);
|
|
this.ignoreStartWithKeys.add(Context.CHILDREN_PROPERTY);
|
|
this.elementType = Context.NAME;
|
|
}
|
|
|
|
public ContextManagement() {
|
|
super(AccessType.CONTEXT);
|
|
init();
|
|
}
|
|
|
|
public ContextManagement(ODatabaseDocument oDatabaseDocument) throws ResourceRegistryException {
|
|
this();
|
|
this.oDatabaseDocument = oDatabaseDocument;
|
|
getWorkingContext();
|
|
}
|
|
|
|
public String getName() {
|
|
if(name == null) {
|
|
if(element == null) {
|
|
if(jsonNode != null) {
|
|
name = jsonNode.get(Context.NAME_PROPERTY).asText();
|
|
}
|
|
} else {
|
|
name = element.getProperty(Context.NAME_PROPERTY);
|
|
}
|
|
}
|
|
return name;
|
|
}
|
|
|
|
@Override
|
|
protected SecurityContext getWorkingContext() throws ResourceRegistryException {
|
|
if(workingContext == null) {
|
|
workingContext = ContextUtility.getInstance()
|
|
.getSecurityContextByUUID(DatabaseEnvironment.CONTEXT_SECURITY_CONTEXT_UUID);
|
|
}
|
|
return workingContext;
|
|
}
|
|
|
|
@Override
|
|
protected ContextNotFoundException getSpecificElementNotFoundException(NotFoundException e) {
|
|
return new ContextNotFoundException(e.getMessage(), e.getCause());
|
|
}
|
|
|
|
@Override
|
|
protected EntityAvailableInAnotherContextException getSpecificERAvailableInAnotherContextException(String message) {
|
|
return new EntityAvailableInAnotherContextException(message);
|
|
}
|
|
|
|
@Override
|
|
protected ContextAlreadyPresentException getSpecificERAlreadyPresentException(String message) {
|
|
return new ContextAlreadyPresentException(message);
|
|
}
|
|
|
|
protected void checkContext(ContextManagement parentContext)
|
|
throws ContextNotFoundException, ContextAlreadyPresentException, ResourceRegistryException {
|
|
|
|
if(parentContext != null) {
|
|
String parentId = parentContext.getElement().getIdentity().toString();
|
|
|
|
String select = "SELECT FROM (TRAVERSE out(" + IsParentOf.NAME + ") FROM " + parentId
|
|
+ " MAXDEPTH 1) WHERE " + Context.NAME_PROPERTY + "=\"" + getName() + "\" AND "
|
|
+ Context.HEADER_PROPERTY + "." + Header.UUID_PROPERTY + "<>\"" + parentContext.uuid + "\"";
|
|
|
|
logger.trace(select);
|
|
|
|
StringBuilder message = new StringBuilder();
|
|
message.append("A context with name (");
|
|
message.append(getName());
|
|
message.append(") has been already created as child of ");
|
|
message.append(parentContext.serializeSelfOnly().toString());
|
|
|
|
logger.trace("Checking if {} -> {}", message, select);
|
|
|
|
OResultSet resultSet = oDatabaseDocument.command(select, new HashMap<>());
|
|
|
|
if(resultSet != null && resultSet.hasNext()) {
|
|
throw new ContextAlreadyPresentException(message.toString());
|
|
}
|
|
|
|
} else {
|
|
String select = "SELECT FROM " + Context.NAME + " WHERE "
|
|
+ Context.NAME_PROPERTY + " = \"" + getName() + "\"" + " AND in(\"" + IsParentOf.NAME
|
|
+ "\").size() = 0";
|
|
|
|
OResultSet resultSet = oDatabaseDocument.command(select, new HashMap<>());
|
|
|
|
if(resultSet != null && resultSet.hasNext()) {
|
|
throw new ContextAlreadyPresentException(
|
|
"A root context with the same name (" + this.getName() + ") already exist");
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
|
public String serialize() throws ResourceRegistryException {
|
|
return serializeAsJson().toString();
|
|
}
|
|
|
|
@Override
|
|
public JsonNode serializeAsJson() throws ResourceRegistryException {
|
|
|
|
JsonNode context = serializeSelfOnly();
|
|
|
|
int count = 0;
|
|
Iterable<OEdge> parents = getElement().getEdges(ODirection.IN);
|
|
for(OEdge edge : parents) {
|
|
if(++count > 1) {
|
|
throw new ContextException("A " + Context.NAME + " can not have more than one parent");
|
|
}
|
|
try {
|
|
IsParentOfManagement isParentOfManagement = new IsParentOfManagement(oDatabaseDocument);
|
|
isParentOfManagement.setElement(edge);
|
|
JsonNode isParentOf = isParentOfManagement.serializeAsJson(true, false);
|
|
if(isParentOf!=null) {
|
|
((ObjectNode) context).replace(Context.PARENT_PROPERTY, isParentOf);
|
|
}
|
|
} catch(Exception e) {
|
|
logger.error("Unable to correctly serialize {}. {}", edge, Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
|
|
throw new ContextException("");
|
|
}
|
|
}
|
|
|
|
Iterable<OEdge> childrenEdges = getElement().getEdges(ODirection.OUT);
|
|
for(OEdge edge : childrenEdges) {
|
|
|
|
IsParentOfManagement isParentOfManagement = new IsParentOfManagement(oDatabaseDocument);
|
|
isParentOfManagement.setElement(edge);
|
|
try {
|
|
JsonNode isParentOf = isParentOfManagement.serializeAsJson();
|
|
context = addRelation(context, isParentOf, Context.CHILDREN_PROPERTY);
|
|
} catch(ResourceRegistryException e) {
|
|
logger.error("Unable to correctly serialize {}. {}", edge, Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
|
|
throw e;
|
|
} catch(Exception e) {
|
|
logger.error("Unable to correctly serialize {}. {}", edge, Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
|
|
throw new ResourceRegistryException(e);
|
|
}
|
|
}
|
|
|
|
return context;
|
|
}
|
|
|
|
@Override
|
|
protected OVertex reallyCreate() throws AlreadyPresentException, ResourceRegistryException {
|
|
SecurityContext securityContext = null;
|
|
SecurityContext parentSecurityContext = null;
|
|
|
|
try {
|
|
JsonNode isParentOfJsonNode = jsonNode.get(Context.PARENT_PROPERTY);
|
|
|
|
if(isParentOfJsonNode != null && !(isParentOfJsonNode instanceof NullNode)) {
|
|
|
|
JsonNode parentJsonNode = isParentOfJsonNode.get(Relation.SOURCE_PROPERTY);
|
|
ContextManagement parentContextManagement = new ContextManagement(oDatabaseDocument);
|
|
parentContextManagement.setJsonNode(parentJsonNode);
|
|
UUID parentUUID = parentContextManagement.uuid;
|
|
parentSecurityContext = ContextUtility.getInstance().getSecurityContextByUUID(parentUUID);
|
|
|
|
|
|
checkContext(parentContextManagement);
|
|
if(uuid == null) {
|
|
uuid = UUID.randomUUID();
|
|
}
|
|
|
|
createVertex();
|
|
|
|
IsParentOfManagement isParentOfManagement = new IsParentOfManagement(oDatabaseDocument);
|
|
isParentOfManagement.setJsonNode(isParentOfJsonNode);
|
|
isParentOfManagement.setSourceEntityManagement(parentContextManagement);
|
|
isParentOfManagement.setTargetEntityManagement(this);
|
|
|
|
isParentOfManagement.internalCreate();
|
|
|
|
} else {
|
|
checkContext(null);
|
|
createVertex();
|
|
}
|
|
|
|
securityContext = new SecurityContext(uuid);
|
|
securityContext.setParentSecurityContext(parentSecurityContext);
|
|
securityContext.create(oDatabaseDocument);
|
|
|
|
ContextUtility.getInstance().addSecurityContext(securityContext);
|
|
|
|
return getElement();
|
|
} catch(Exception e) {
|
|
oDatabaseDocument.rollback();
|
|
if(securityContext != null) {
|
|
securityContext.delete(oDatabaseDocument);
|
|
if(parentSecurityContext!=null && securityContext!=null) {
|
|
parentSecurityContext.getChildren().remove(securityContext);
|
|
}
|
|
ContextUtility.getInstance().removeFromCache(uuid, false);
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected OVertex reallyUpdate() throws NotFoundException, ResourceRegistryException {
|
|
|
|
boolean parentChanged = false;
|
|
boolean nameChanged = false;
|
|
|
|
OVertex parent = null;
|
|
boolean found = false;
|
|
|
|
Iterable<OVertex> iterable = getElement().getVertices(ODirection.IN, IsParentOf.NAME);
|
|
for(OVertex p : iterable) {
|
|
if(found) {
|
|
String message = String.format("{} has more than one parent. {}", Context.NAME,
|
|
Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
|
|
throw new ResourceRegistryException(message.toString());
|
|
}
|
|
parent = p;
|
|
found = true;
|
|
}
|
|
|
|
ContextManagement actualParentContextManagement = null;
|
|
if(parent != null) {
|
|
actualParentContextManagement = new ContextManagement(oDatabaseDocument);
|
|
actualParentContextManagement.setElement(parent);
|
|
}
|
|
|
|
ContextManagement newParentContextManagement = actualParentContextManagement;
|
|
|
|
JsonNode isParentOfJsonNode = jsonNode.get(Context.PARENT_PROPERTY);
|
|
JsonNode parentContextJsonNode = null;
|
|
if(isParentOfJsonNode != null && !(isParentOfJsonNode instanceof NullNode)) {
|
|
parentContextJsonNode = isParentOfJsonNode.get(Relation.SOURCE_PROPERTY);
|
|
}
|
|
|
|
if(parentContextJsonNode != null && !(parentContextJsonNode instanceof NullNode)) {
|
|
UUID parentUUID = org.gcube.informationsystem.utils.Utility.getUUIDFromJsonNode(parentContextJsonNode);
|
|
if(actualParentContextManagement != null) {
|
|
if(parentUUID.compareTo(actualParentContextManagement.uuid) != 0) {
|
|
parentChanged = true;
|
|
}
|
|
} else {
|
|
parentChanged = true;
|
|
}
|
|
|
|
if(parentChanged) {
|
|
newParentContextManagement = new ContextManagement(oDatabaseDocument);
|
|
newParentContextManagement.setJsonNode(parentContextJsonNode);
|
|
}
|
|
} else {
|
|
if(actualParentContextManagement != null) {
|
|
parentChanged = true;
|
|
newParentContextManagement = null;
|
|
}
|
|
|
|
}
|
|
|
|
String oldName = getElement().getProperty(Context.NAME_PROPERTY);
|
|
String newName = jsonNode.get(Context.NAME_PROPERTY).asText();
|
|
if(oldName.compareTo(newName) != 0) {
|
|
nameChanged = true;
|
|
name = newName;
|
|
}
|
|
|
|
if(parentChanged || nameChanged) {
|
|
checkContext(newParentContextManagement);
|
|
}
|
|
|
|
if(parentChanged) {
|
|
move(newParentContextManagement, false);
|
|
}
|
|
|
|
element = (OVertex) ElementManagement.updateProperties(oClass, getElement(), jsonNode, ignoreKeys,
|
|
ignoreStartWithKeys);
|
|
|
|
ContextUtility.getInstance().removeFromCache(uuid, (nameChanged && !parentChanged));
|
|
|
|
return element;
|
|
}
|
|
|
|
private void move(ContextManagement newParentContextManagement, boolean check)
|
|
throws ContextNotFoundException, ContextAlreadyPresentException, ResourceRegistryException {
|
|
if(check) {
|
|
checkContext(newParentContextManagement);
|
|
}
|
|
|
|
SecurityContext newParentSecurityContext = null;
|
|
|
|
// Removing the old parent relationship if any
|
|
Iterable<OEdge> edges = getElement().getEdges(ODirection.IN, IsParentOf.NAME);
|
|
if(edges != null && edges.iterator().hasNext()) {
|
|
Iterator<OEdge> edgeIterator = edges.iterator();
|
|
OEdge edge = edgeIterator.next();
|
|
IsParentOfManagement isParentOfManagement = new IsParentOfManagement();
|
|
isParentOfManagement.setElement(edge);
|
|
isParentOfManagement.internalDelete();
|
|
|
|
if(edgeIterator.hasNext()) {
|
|
throw new ContextException(
|
|
"Seems that the Context has more than one Parent. " + Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
|
|
}
|
|
}
|
|
|
|
if(newParentContextManagement != null) {
|
|
JsonNode isParentOfJsonNode = jsonNode.get(Context.PARENT_PROPERTY);
|
|
IsParentOfManagement isParentOfManagement = new IsParentOfManagement(oDatabaseDocument);
|
|
isParentOfManagement.setJsonNode(isParentOfJsonNode);
|
|
isParentOfManagement.setSourceEntityManagement(newParentContextManagement);
|
|
isParentOfManagement.setTargetEntityManagement(this);
|
|
isParentOfManagement.internalCreate();
|
|
newParentSecurityContext = ContextUtility.getInstance().getSecurityContextByUUID(newParentContextManagement.uuid);
|
|
}
|
|
|
|
SecurityContext thisSecurityContext = ContextUtility.getInstance().getSecurityContextByUUID(uuid);
|
|
thisSecurityContext.changeParentSecurityContext(newParentSecurityContext, oDatabaseDocument);
|
|
}
|
|
|
|
@Override
|
|
protected boolean reallyDelete() throws NotFoundException, ResourceRegistryException {
|
|
Iterable<OEdge> iterable = getElement().getEdges(ODirection.OUT);
|
|
Iterator<OEdge> iterator = iterable.iterator();
|
|
while(iterator.hasNext()) {
|
|
throw new ContextException("Cannot remove a " + Context.NAME + " having children");
|
|
}
|
|
|
|
element.delete();
|
|
|
|
ContextUtility contextUtility = ContextUtility.getInstance();
|
|
SecurityContext securityContext = contextUtility.getSecurityContextByUUID(uuid);
|
|
securityContext.delete(oDatabaseDocument);
|
|
|
|
contextUtility.removeFromCache(uuid, false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
@Override
|
|
public String reallyGetAll(boolean polymorphic) throws ResourceRegistryException {
|
|
ObjectMapper objectMapper = new ObjectMapper();
|
|
ArrayNode arrayNode = objectMapper.createArrayNode();
|
|
Iterable<ODocument> iterable = oDatabaseDocument.browseClass(elementType, polymorphic);
|
|
for(ODocument vertex : iterable) {
|
|
ContextManagement contextManagement = new ContextManagement();
|
|
contextManagement.setElement((OVertex) vertex);
|
|
try {
|
|
JsonNode jsonObject = contextManagement.serializeAsJson();
|
|
arrayNode.add(jsonObject);
|
|
} catch(ResourceRegistryException e) {
|
|
logger.error("Unable to correctly serialize {}. It will be excluded from results. {}",
|
|
vertex.toString(), Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
|
|
}
|
|
}
|
|
try {
|
|
return objectMapper.writeValueAsString(arrayNode);
|
|
} catch(JsonProcessingException e) {
|
|
throw new ResourceRegistryException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean reallyAddToContext(SecurityContext targetSecurityContext)
|
|
throws ContextException, ResourceRegistryException {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
protected boolean reallyRemoveFromContext(SecurityContext targetSecurityContext)
|
|
throws ContextException, ResourceRegistryException {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
}
|