resource-registry/src/main/java/org/gcube/informationsystem/resourceregistry/instances/base/properties/PropertyElementManagement.java

212 lines
8.2 KiB
Java

package org.gcube.informationsystem.resourceregistry.instances.base.properties;
import java.security.Key;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
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.common.encryption.encrypter.StringEncrypter;
import org.gcube.informationsystem.base.reference.AccessType;
import org.gcube.informationsystem.base.reference.Element;
import org.gcube.informationsystem.base.reference.properties.PropertyElement;
import org.gcube.informationsystem.model.reference.properties.Encrypted;
import org.gcube.informationsystem.model.reference.properties.Metadata;
import org.gcube.informationsystem.model.reference.properties.Property;
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaNotFoundException;
import org.gcube.informationsystem.resourceregistry.dbinitialization.DatabaseEnvironment;
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagement;
import org.gcube.informationsystem.resourceregistry.types.CachedType;
import org.gcube.informationsystem.resourceregistry.types.TypesCache;
import org.gcube.informationsystem.resourceregistry.utils.EncryptedOrient;
import org.gcube.informationsystem.resourceregistry.utils.MetadataUtility;
import org.gcube.informationsystem.resourceregistry.utils.DBUtility;
import org.gcube.informationsystem.resourceregistry.utils.UUIDUtility;
import org.gcube.informationsystem.types.reference.properties.PropertyType;
import org.gcube.informationsystem.utils.TypeUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.arcadedb.database.Document;
import com.arcadedb.schema.DocumentType;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class PropertyElementManagement {
private static Logger logger = LoggerFactory.getLogger(PropertyElementManagement.class);
public static final Set<String> PROPERTY_IGNORE_KEYS;
public static final Set<String> PROPERTY_IGNORE_START_WITH_KEYS;
static {
PROPERTY_IGNORE_KEYS = new HashSet<String>();
PROPERTY_IGNORE_START_WITH_KEYS = new HashSet<String>();
PROPERTY_IGNORE_START_WITH_KEYS.add(ElementManagement.AT);
PROPERTY_IGNORE_START_WITH_KEYS.add(ElementManagement.UNDERSCORE);
}
public static Document getPropertyDocument(JsonNode jsonNodeOrig) throws ResourceRegistryException {
Document document = null;
if(jsonNodeOrig.isNull()) {
return null;
}
JsonNode jsonNode = jsonNodeOrig.deepCopy();
if(jsonNode.has(Element.SUPERTYPES_PROPERTY)) {
((ObjectNode) jsonNode).remove(Element.SUPERTYPES_PROPERTY);
}
String type = TypeUtility.getTypeName(jsonNode);
if(type!=null) {
// Complex type
DocumentType documentType = null;
try {
TypesCache typesCache = TypesCache.getInstance();
@SuppressWarnings("unchecked")
CachedType<PropertyType<PropertyElement>> cachedType = (CachedType<PropertyType<PropertyElement>>) typesCache.getCachedType(type);
documentType = cachedType.getDocumentType();
AccessType gotAccessType = cachedType.getAccessType();
if(!AccessType.PROPERTY_ELEMENT.getClass().isAssignableFrom(gotAccessType.getClass())) {
throw new SchemaException(type + " is not a " + AccessType.PROPERTY_ELEMENT.getName());
}
} catch(SchemaNotFoundException e) {
throw e;
}
try {
UUID uuid = UUIDUtility.getUUID(jsonNode);
if(uuid != null) {
throw new ResourceRegistryException("A property object cannot have an UUID");
}
} catch(Exception e) {
logger.warn("An invalid UUID has been provided. Anyway property object cannot have an UUID.");
throw new ResourceRegistryException("An property object cannot have an UUID");
}
try {
Metadata metadata = MetadataUtility.getMetadata(jsonNode);
if(metadata != null) {
throw new ResourceRegistryException("A property object cannot have a Metadata");
}
} catch(Exception e) {
logger.warn("An invalid Metadata has been provided. Anyway property object cannot have a Metadata.");
throw new ResourceRegistryException("An property object cannot have a Metadata");
}
/*
* In case it is an Encrypted type the Value received arrives encrypted with the Context Key
* Resource Registry must decrypt the value with the Context Key and Encrypt it with DB key.
* The opposite operation is done when the value is read by clients.
*/
if(documentType.isSubTypeOf(Encrypted.NAME)) {
EncryptedOrient encrypted = new EncryptedOrient();
document = encrypted;
document.fromJSON(jsonNode.toString());
try {
String contextEncryptedValue = encrypted.getEncryptedValue();
// Decrypting with Context Key (default key)
String decryptedValue = StringEncrypter.getEncrypter().decrypt(contextEncryptedValue);
encrypted.setDecryptedValue(decryptedValue, false);
} catch(Exception e) {
throw new ResourceRegistryException("Unable to manage " + Encrypted.NAME + " " + org.gcube.informationsystem.model.reference.properties.Property.NAME);
}
return document;
}
document = new Document(type);
} else {
document = new Document();
}
return document.fromJSON(jsonNode.toString());
}
public static JsonNode getJsonNode(Document oDocument) throws ResourceRegistryException {
try {
String type = oDocument.getTypeName();
String json = DBUtility.toJsonString(oDocument);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(json);
if(type==null) {
return jsonNode;
}
TypesCache typesCache = TypesCache.getInstance();
@SuppressWarnings("unchecked")
CachedType<PropertyType<PropertyElement>> cachedType = (CachedType<PropertyType<PropertyElement>>) typesCache.getCachedType(type);
DocumentType documentType = cachedType.getDocumentType();
AccessType gotAccessType = cachedType.getAccessType();
if(!AccessType.PROPERTY_ELEMENT.getClass().isAssignableFrom(gotAccessType.getClass())) {
throw new SchemaException(type + " is not a " + AccessType.PROPERTY_ELEMENT.getName());
}
Collection<String> superClasses = cachedType.getSuperTypes();
ArrayNode arrayNode = objectMapper.valueToTree(superClasses);
((ObjectNode) jsonNode).replace(Element.SUPERTYPES_PROPERTY, arrayNode);
/*
* In case it is an Encrypted type the value is encrypted with the DB Key
* Resource Registry must decrypt the value with the DB Key and Encrypt it with Context key.
* The opposite operation is done when the value is set from clients.
* see {@link PropertyManagement#getPropertyDocument(JsonNode) getPropertyDocument()}
*/
if(documentType.isSubTypeOf(Encrypted.NAME)) {
try {
EncryptedOrient encrypted = null;
String encryptedValue = (String) oDocument.getString(Encrypted.VALUE);
if(oDocument instanceof EncryptedOrient) {
encrypted = (EncryptedOrient) oDocument;
if(encrypted.getDbEncryptedValue().compareTo(encryptedValue)==0) {
((ObjectNode) jsonNode).put(Encrypted.VALUE, encrypted.getContextEncryptedValue());
}
}else {
encrypted = new EncryptedOrient();
oDocument = (Document) encrypted;
// Decrypting with DB Key
Key databaseKey = DatabaseEnvironment.getDatabaseKey();
String decryptedValue = StringEncrypter.getEncrypter().decrypt(encryptedValue, databaseKey);
// Encrypting with Context Key (default key)
String contextEncryptedValue = StringEncrypter.getEncrypter().encrypt(decryptedValue);
// Setting the value encrypted with DB key
((ObjectNode) jsonNode).put(Encrypted.VALUE, contextEncryptedValue);
}
}catch (Exception e) {
throw new ResourceRegistryException("Errror while managing " + EncryptedOrient.NAME+ " "+ Property.NAME, e);
}
}
return jsonNode;
} catch (ResourceRegistryException e) {
throw e;
} catch (Exception e) {
throw new ResourceRegistryException(e);
}
}
}