resource-registry/src/main/java/org/gcube/informationsystem/resourceregistry/contexts/entities/ContextManagement.java

461 lines
17 KiB
Java
Raw Normal View History

2020-01-27 17:07:37 +01:00
package org.gcube.informationsystem.resourceregistry.contexts.entities;
2020-11-05 12:12:19 +01:00
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
2020-11-05 12:12:19 +01:00
import java.util.List;
import java.util.Map;
import java.util.UUID;
2020-07-07 17:15:22 +02:00
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.NullNode;
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
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;
2020-11-05 12:12:19 +01:00
import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache;
import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCacheRenewal;
import org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException;
2020-11-05 12:12:19 +01:00
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.context.ContextAlreadyPresentException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.context.ContextException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.context.ContextNotFoundException;
2021-02-18 18:22:39 +01:00
import org.gcube.informationsystem.resourceregistry.api.exceptions.schema.SchemaViolationException;
2020-01-27 17:07:37 +01:00
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.entities.EntityElementManagement;
import org.gcube.informationsystem.resourceregistry.utils.Utility;
2021-02-22 16:36:19 +01:00
import org.gcube.informationsystem.types.reference.entities.EntityType;
2020-11-05 12:12:19 +01:00
import org.gcube.informationsystem.utils.ElementMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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)
*/
2021-02-22 16:36:19 +01:00
public class ContextManagement extends EntityElementManagement<Context, EntityType> {
2021-02-19 19:32:23 +01:00
private static Logger logger = LoggerFactory.getLogger(ContextManagement.class);
2021-02-19 19:32:23 +01:00
protected String name;
2021-02-19 19:32:23 +01:00
private void init() {
this.ignoreStartWithKeys.add(Context.PARENT_PROPERTY);
this.ignoreStartWithKeys.add(Context.CHILDREN_PROPERTY);
2021-02-18 09:42:51 +01:00
this.typeName = Context.NAME;
}
2021-02-19 19:32:23 +01:00
2020-11-05 12:12:19 +01:00
protected ContextCacheRenewal contextCacheRenewal = new ContextCacheRenewal() {
2021-02-19 19:32:23 +01:00
2020-11-05 12:12:19 +01:00
@Override
public List<Context> renew() throws ResourceRegistryException {
String contextsJsonString = allFromServer(false);
List<Context> contexts = null;
try {
contexts = ElementMapper.unmarshalList(contextsJsonString);
} catch (IOException e) {
2020-11-05 15:58:30 +01:00
logger.error("Unable to read contexts from DB", e);
2020-11-05 12:12:19 +01:00
}
return contexts;
}
2021-02-19 19:32:23 +01:00
};
public ContextManagement() {
super(AccessType.CONTEXT);
init();
2020-11-05 12:12:19 +01:00
ContextCache contextCache = ContextCache.getInstance();
contextCache.setContextCacheRenewal(contextCacheRenewal);
}
2021-02-19 19:32:23 +01:00
public ContextManagement(ODatabaseDocument oDatabaseDocument) throws ResourceRegistryException {
this();
this.oDatabaseDocument = oDatabaseDocument;
getWorkingContext();
}
2021-02-19 19:32:23 +01:00
@Override
public Map<UUID,JsonNode> getAffectedInstances() {
throw new UnsupportedOperationException();
}
public String getName() {
2021-02-19 19:32:23 +01:00
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;
}
2021-02-19 19:32:23 +01:00
@Override
protected SecurityContext getWorkingContext() throws ResourceRegistryException {
2021-02-19 19:32:23 +01:00
if (workingContext == null) {
workingContext = ContextUtility.getInstance()
.getSecurityContextByUUID(DatabaseEnvironment.CONTEXT_SECURITY_CONTEXT_UUID);
}
return workingContext;
}
2021-02-19 19:32:23 +01:00
@Override
2021-03-05 10:46:59 +01:00
protected ContextNotFoundException getSpecificNotFoundException(NotFoundException e) {
return new ContextNotFoundException(e.getMessage(), e.getCause());
}
2021-02-19 19:32:23 +01:00
@Override
2021-03-05 10:46:59 +01:00
protected ContextAlreadyPresentException getSpecificAlreadyPresentException(String message) {
return new ContextAlreadyPresentException(message);
}
2021-02-19 19:32:23 +01:00
protected void checkContext(ContextManagement parentContext)
throws ContextNotFoundException, ContextAlreadyPresentException, ResourceRegistryException {
2021-02-19 19:32:23 +01:00
if (parentContext != null) {
String parentId = parentContext.getElement().getIdentity().toString();
2021-02-19 19:32:23 +01:00
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 + "\"";
2021-02-19 19:32:23 +01:00
logger.trace(select);
2021-02-19 19:32:23 +01:00
StringBuilder message = new StringBuilder();
message.append("A context with name (");
message.append(getName());
message.append(") has been already created as child of ");
2021-02-17 11:29:43 +01:00
message.append(parentContext.getElement().toString());
2021-02-19 19:32:23 +01:00
logger.trace("Checking if {} -> {}", message, select);
2021-02-19 19:32:23 +01:00
OResultSet resultSet = oDatabaseDocument.command(select, new HashMap<>());
2021-02-19 19:32:23 +01:00
if (resultSet != null && resultSet.hasNext()) {
throw new ContextAlreadyPresentException(message.toString());
}
2021-02-19 19:32:23 +01:00
} else {
2021-02-19 19:32:23 +01:00
String select = "SELECT FROM " + Context.NAME + " WHERE " + Context.NAME_PROPERTY + " = \"" + getName()
+ "\"" + " AND in(\"" + IsParentOf.NAME + "\").size() = 0";
OResultSet resultSet = oDatabaseDocument.command(select, new HashMap<>());
2021-02-19 19:32:23 +01:00
if (resultSet != null && resultSet.hasNext()) {
throw new ContextAlreadyPresentException(
"A root context with the same name (" + this.getName() + ") already exist");
}
2021-02-19 19:32:23 +01:00
}
2021-02-19 19:32:23 +01:00
}
2021-02-19 19:32:23 +01:00
@Override
2021-02-17 11:29:43 +01:00
protected JsonNode createCompleteJsonNode() throws ResourceRegistryException {
2021-02-19 19:32:23 +01:00
2021-02-17 11:29:43 +01:00
JsonNode context = serializeSelfAsJsonNode();
2021-02-19 19:32:23 +01:00
int count = 0;
Iterable<OEdge> parents = getElement().getEdges(ODirection.IN);
2021-02-19 19:32:23 +01:00
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);
isParentOfManagement.includeSource(true);
isParentOfManagement.includeTarget(false);
JsonNode isParentOf = isParentOfManagement.createCompleteJsonNode();
2021-02-19 19:32:23 +01:00
if (isParentOf != null) {
((ObjectNode) context).replace(Context.PARENT_PROPERTY, isParentOf);
}
2021-02-19 19:32:23 +01:00
} catch (Exception e) {
logger.error("Unable to correctly serialize {}. {}", edge, Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
throw new ContextException("");
}
}
2021-02-19 19:32:23 +01:00
Iterable<OEdge> childrenEdges = getElement().getEdges(ODirection.OUT);
2021-02-19 19:32:23 +01:00
for (OEdge edge : childrenEdges) {
IsParentOfManagement isParentOfManagement = new IsParentOfManagement(oDatabaseDocument);
isParentOfManagement.setElement(edge);
try {
2021-02-17 11:29:43 +01:00
JsonNode isParentOf = isParentOfManagement.serializeAsJsonNode();
context = addRelation(context, isParentOf, Context.CHILDREN_PROPERTY);
2021-02-19 19:32:23 +01:00
} catch (ResourceRegistryException e) {
logger.error("Unable to correctly serialize {}. {}", edge, Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
throw e;
2021-02-19 19:32:23 +01:00
} catch (Exception e) {
logger.error("Unable to correctly serialize {}. {}", edge, Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
throw new ResourceRegistryException(e);
}
}
2021-02-19 19:32:23 +01:00
return context;
}
2021-02-19 19:32:23 +01:00
@Override
protected OVertex reallyCreate() throws AlreadyPresentException, ResourceRegistryException {
SecurityContext securityContext = null;
SecurityContext parentSecurityContext = null;
2021-02-19 19:32:23 +01:00
try {
JsonNode isParentOfJsonNode = jsonNode.get(Context.PARENT_PROPERTY);
2021-02-19 19:32:23 +01:00
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);
2021-02-19 19:32:23 +01:00
checkContext(parentContextManagement);
2021-02-19 19:32:23 +01:00
if (uuid == null) {
uuid = UUID.randomUUID();
}
2021-02-19 19:32:23 +01:00
createVertex();
2021-02-19 19:32:23 +01:00
IsParentOfManagement isParentOfManagement = new IsParentOfManagement(oDatabaseDocument);
isParentOfManagement.setJsonNode(isParentOfJsonNode);
isParentOfManagement.setSourceEntityManagement(parentContextManagement);
isParentOfManagement.setTargetEntityManagement(this);
2021-02-19 19:32:23 +01:00
isParentOfManagement.internalCreate();
2021-02-19 19:32:23 +01:00
} else {
checkContext(null);
createVertex();
}
2021-02-19 19:32:23 +01:00
securityContext = new SecurityContext(uuid);
securityContext.setParentSecurityContext(parentSecurityContext);
securityContext.create(oDatabaseDocument);
2021-02-19 19:32:23 +01:00
ContextUtility.getInstance().addSecurityContext(securityContext);
2021-02-19 19:32:23 +01:00
return getElement();
2021-02-19 19:32:23 +01:00
} catch (Exception e) {
oDatabaseDocument.rollback();
2021-02-19 19:32:23 +01:00
if (securityContext != null) {
securityContext.delete(oDatabaseDocument);
2021-02-19 19:32:23 +01:00
if (parentSecurityContext != null && securityContext != null) {
parentSecurityContext.getChildren().remove(securityContext);
}
2020-11-05 12:12:19 +01:00
ContextCache.getInstance().cleanCache();
}
throw e;
}
}
2021-02-19 19:32:23 +01:00
@Override
protected OVertex reallyUpdate() throws NotFoundException, ResourceRegistryException {
2021-02-19 19:32:23 +01:00
boolean parentChanged = false;
boolean nameChanged = false;
2021-02-19 19:32:23 +01:00
OVertex parent = null;
boolean found = false;
2021-02-19 19:32:23 +01:00
Iterable<OVertex> iterable = getElement().getVertices(ODirection.IN, IsParentOf.NAME);
2021-02-19 19:32:23 +01:00
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;
}
2021-02-19 19:32:23 +01:00
ContextManagement actualParentContextManagement = null;
2021-02-19 19:32:23 +01:00
if (parent != null) {
actualParentContextManagement = new ContextManagement(oDatabaseDocument);
actualParentContextManagement.setElement(parent);
}
2021-02-19 19:32:23 +01:00
ContextManagement newParentContextManagement = actualParentContextManagement;
2021-02-19 19:32:23 +01:00
JsonNode isParentOfJsonNode = jsonNode.get(Context.PARENT_PROPERTY);
JsonNode parentContextJsonNode = null;
2021-02-19 19:32:23 +01:00
if (isParentOfJsonNode != null && !(isParentOfJsonNode instanceof NullNode)) {
parentContextJsonNode = isParentOfJsonNode.get(Relation.SOURCE_PROPERTY);
}
2021-02-19 19:32:23 +01:00
if (parentContextJsonNode != null && !(parentContextJsonNode instanceof NullNode)) {
UUID parentUUID = org.gcube.informationsystem.utils.Utility.getUUIDFromJsonNode(parentContextJsonNode);
2021-02-19 19:32:23 +01:00
if (actualParentContextManagement != null) {
if (parentUUID.compareTo(actualParentContextManagement.uuid) != 0) {
parentChanged = true;
}
} else {
parentChanged = true;
}
2021-02-19 19:32:23 +01:00
if (parentChanged) {
newParentContextManagement = new ContextManagement(oDatabaseDocument);
newParentContextManagement.setJsonNode(parentContextJsonNode);
}
} else {
2021-02-19 19:32:23 +01:00
if (actualParentContextManagement != null) {
parentChanged = true;
newParentContextManagement = null;
}
2021-02-19 19:32:23 +01:00
}
2021-02-19 19:32:23 +01:00
String oldName = getElement().getProperty(Context.NAME_PROPERTY);
String newName = jsonNode.get(Context.NAME_PROPERTY).asText();
2021-02-19 19:32:23 +01:00
if (oldName.compareTo(newName) != 0) {
nameChanged = true;
name = newName;
}
2021-02-19 19:32:23 +01:00
if (parentChanged || nameChanged) {
checkContext(newParentContextManagement);
}
2021-02-19 19:32:23 +01:00
if (parentChanged) {
move(newParentContextManagement, false);
}
2021-02-19 19:32:23 +01:00
element = (OVertex) updateProperties(oClass, getElement(), jsonNode, ignoreKeys, ignoreStartWithKeys);
2020-11-05 12:12:19 +01:00
ContextCache.getInstance().cleanCache();
2021-02-19 19:32:23 +01:00
return element;
}
2021-02-19 19:32:23 +01:00
private void move(ContextManagement newParentContextManagement, boolean check)
throws ContextNotFoundException, ContextAlreadyPresentException, ResourceRegistryException {
2021-02-19 19:32:23 +01:00
if (check) {
checkContext(newParentContextManagement);
}
2021-02-19 19:32:23 +01:00
SecurityContext newParentSecurityContext = null;
2021-02-19 19:32:23 +01:00
// Removing the old parent relationship if any
Iterable<OEdge> edges = getElement().getEdges(ODirection.IN, IsParentOf.NAME);
2021-02-19 19:32:23 +01:00
if (edges != null && edges.iterator().hasNext()) {
Iterator<OEdge> edgeIterator = edges.iterator();
OEdge edge = edgeIterator.next();
IsParentOfManagement isParentOfManagement = new IsParentOfManagement();
isParentOfManagement.setElement(edge);
isParentOfManagement.internalDelete();
2021-02-19 19:32:23 +01:00
if (edgeIterator.hasNext()) {
throw new ContextException(
"Seems that the Context has more than one Parent. " + Utility.SHOULD_NOT_OCCUR_ERROR_MESSAGE);
}
}
2021-02-19 19:32:23 +01:00
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();
2021-02-19 19:32:23 +01:00
newParentSecurityContext = ContextUtility.getInstance()
.getSecurityContextByUUID(newParentContextManagement.uuid);
}
2021-02-19 19:32:23 +01:00
SecurityContext thisSecurityContext = ContextUtility.getInstance().getSecurityContextByUUID(uuid);
thisSecurityContext.changeParentSecurityContext(newParentSecurityContext, oDatabaseDocument);
}
2021-02-19 19:32:23 +01:00
@Override
protected void reallyDelete() throws NotFoundException, ResourceRegistryException {
Iterable<OEdge> iterable = getElement().getEdges(ODirection.OUT);
Iterator<OEdge> iterator = iterable.iterator();
2021-02-19 19:32:23 +01:00
while (iterator.hasNext()) {
throw new ContextException("Cannot remove a " + Context.NAME + " having children");
}
2021-02-19 19:32:23 +01:00
element.delete();
2021-02-19 19:32:23 +01:00
ContextUtility contextUtility = ContextUtility.getInstance();
SecurityContext securityContext = contextUtility.getSecurityContextByUUID(uuid);
securityContext.delete(oDatabaseDocument);
2021-02-19 19:32:23 +01:00
2020-11-05 12:12:19 +01:00
ContextCache.getInstance().cleanCache();
}
2021-02-19 19:32:23 +01:00
@Override
public String reallyGetAll(boolean polymorphic) throws ResourceRegistryException {
ObjectMapper objectMapper = new ObjectMapper();
ArrayNode arrayNode = objectMapper.createArrayNode();
2021-02-18 09:42:51 +01:00
Iterable<ODocument> iterable = oDatabaseDocument.browseClass(typeName, polymorphic);
2021-02-19 19:32:23 +01:00
for (ODocument vertex : iterable) {
ContextManagement contextManagement = new ContextManagement();
contextManagement.setElement((OVertex) vertex);
try {
2021-02-17 15:16:25 +01:00
JsonNode jsonObject = contextManagement.serializeAsJsonNode();
arrayNode.add(jsonObject);
2021-02-19 19:32:23 +01:00
} 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);
2021-02-19 19:32:23 +01:00
} catch (JsonProcessingException e) {
throw new ResourceRegistryException(e);
}
}
2020-11-05 12:12:19 +01:00
public String allFromServer(boolean polymorphic) throws ResourceRegistryException {
return super.all(polymorphic);
}
2021-02-19 19:32:23 +01:00
2020-11-05 12:12:19 +01:00
@Override
public String all(boolean polymorphic) throws ResourceRegistryException {
try {
ContextCache contextCache = ContextCache.getInstance();
return ElementMapper.marshal(contextCache.getContexts());
} catch (JsonProcessingException | ResourceRegistryException e) {
return allFromServer(polymorphic);
}
}
2021-02-19 19:32:23 +01:00
public String readFromServer()
throws NotFoundException, AvailableInAnotherContextException, ResourceRegistryException {
2021-02-05 17:50:16 +01:00
return super.read().toString();
2020-11-05 12:12:19 +01:00
}
2021-02-19 19:32:23 +01:00
public String readAsString()
throws NotFoundException, AvailableInAnotherContextException, ResourceRegistryException {
2020-11-05 12:12:19 +01:00
try {
ContextCache contextCache = ContextCache.getInstance();
return ElementMapper.marshal(contextCache.getContextByUUID(uuid));
} catch (JsonProcessingException | ResourceRegistryException e) {
return readFromServer();
}
}
2021-02-19 19:32:23 +01:00
2021-02-18 18:22:39 +01:00
@Override
2021-02-19 19:32:23 +01:00
public void sanityCheck() throws SchemaViolationException, ResourceRegistryException {
2021-02-18 18:22:39 +01:00
// Nothing to do
}
}