Changed the management of instance property to properly support Map,

List and Set
This commit is contained in:
Luca Frosini 2021-10-26 20:49:58 +02:00
parent 2578a7cecb
commit b025d08099
6 changed files with 277 additions and 88 deletions

View File

@ -876,7 +876,7 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
return null; return null;
} }
public static Object getObjectFromElement(JsonNode value) public static Object getObjectFromJsonNode(JsonNode value)
throws UnsupportedDataTypeException, ResourceRegistryException { throws UnsupportedDataTypeException, ResourceRegistryException {
JsonNodeType jsonNodeType = value.getNodeType(); JsonNodeType jsonNodeType = value.getNodeType();
@ -885,23 +885,8 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
return PropertyElementManagement.getPropertyDocument(value); return PropertyElementManagement.getPropertyDocument(value);
case ARRAY: case ARRAY:
List<Object> list = new ArrayList<Object>(); break;
Iterator<JsonNode> arrayElement = value.elements();
while(arrayElement.hasNext()) {
JsonNode arrayNode = arrayElement.next();
Object objectNode = getObjectFromElement(arrayNode);
if(objectNode != null) {
list.add(objectNode);
}
}
return list;
/*
* List/Set support is currently disabled due to OrientDB bug see https://github.com/orientechnologies/orientdb/issues/7354
*
throw new UnsupportedDataTypeException(
"List/Set support is currently disabled due to OrientDB bug see https://github.com/orientechnologies/orientdb/issues/7354");
*/
case BINARY: case BINARY:
break; break;
@ -940,10 +925,10 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
return null; return null;
} }
public Map<String,Object> getPropertyMap(JsonNode jsonNode, Set<String> ignoreKeys, public Map<String,JsonNode> getPropertyMap(JsonNode jsonNode, Set<String> ignoreKeys,
Set<String> ignoreStartWith) throws JsonProcessingException, IOException { Set<String> ignoreStartWith) throws JsonProcessingException, IOException {
Map<String,Object> map = new HashMap<>(); Map<String, JsonNode> map = new HashMap<>();
if(ignoreKeys == null) { if(ignoreKeys == null) {
ignoreKeys = new HashSet<>(); ignoreKeys = new HashSet<>();
@ -971,15 +956,7 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
} }
JsonNode value = entry.getValue(); JsonNode value = entry.getValue();
Object object = null; map.put(key, value);
try {
object = getObjectFromElement(value);
if(object != null) {
map.put(key, object);
}
} catch(ResourceRegistryException e) {
logger.warn("An invalidy property has been provided. It will be ignored.");
}
} }
@ -991,7 +968,7 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
Set<String> oldKeys = element.getPropertyNames(); Set<String> oldKeys = element.getPropertyNames();
Map<String,Object> properties; Map<String,JsonNode> properties;
try { try {
properties = getPropertyMap(jsonNode, ignoreKeys, ignoreStartWithKeys); properties = getPropertyMap(jsonNode, ignoreKeys, ignoreStartWithKeys);
} catch(IOException e) { } catch(IOException e) {
@ -1000,33 +977,88 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
oldKeys.removeAll(properties.keySet()); oldKeys.removeAll(properties.keySet());
getOClass();
for(String key : properties.keySet()) { for(String key : properties.keySet()) {
try { try {
Object object = properties.get(key); JsonNode value = properties.get(key);
boolean set = false; OProperty oProperty = oClass.getProperty(key);
if(object instanceof ODocument) { if(oProperty==null) {
ODocument oDocument = (ODocument) object; Object object = getObjectFromJsonNode(value);
element.setProperty(key, oDocument, OType.EMBEDDED); if(object != null) {
set = true; if(object instanceof ODocument) {
} element.setProperty(key, object, OType.EMBEDDED);
}else {
/* element.setProperty(key, object);
* List/Set support is currently disabled due to OrientDB bug see https://github.com/orientechnologies/orientdb/issues/7354 }
*/ }
if(object instanceof Set) { }else {
element.setProperty(key, object, OType.EMBEDDEDSET); switch (oProperty.getType()) {
set = true; case EMBEDDED:
} ODocument oDocument = PropertyElementManagement.getPropertyDocument(value);
if(object instanceof List) { element.setProperty(key, oDocument, OType.EMBEDDED);
element.setProperty(key, object, OType.EMBEDDEDLIST); break;
set = true;
} case EMBEDDEDLIST:
List<Object> list = new ArrayList<Object>();
if(!set) { Iterator<JsonNode> arrayElement = value.elements();
element.setProperty(key, object); while(arrayElement.hasNext()) {
JsonNode elementOfArray = arrayElement.next();
Object object = null;
if(oProperty.getLinkedType()!=null) {
object = getObjectFromJsonNode(elementOfArray);
}else {
object = PropertyElementManagement.getPropertyDocument(elementOfArray);
}
list.add(object);
}
element.setProperty(key, list, OType.EMBEDDEDLIST);
break;
case EMBEDDEDSET:
Set<Object> set = new HashSet<Object>();
Iterator<JsonNode> setElement = value.elements();
while(setElement.hasNext()) {
JsonNode elementOfSet = setElement.next();
Object object = null;
if(oProperty.getLinkedType()!=null) {
object = getObjectFromJsonNode(elementOfSet);
}else {
object = PropertyElementManagement.getPropertyDocument(elementOfSet);
}
set.add(object);
}
element.setProperty(key, set, OType.EMBEDDEDSET);
break;
case EMBEDDEDMAP:
Map<String, Object> map = new HashMap<>();
Iterator<String> fieldNames = value.fieldNames();
while(fieldNames.hasNext()) {
String fieldKey = fieldNames.next();
Object object = null;
if(oProperty.getLinkedType()!=null) {
object = getObjectFromJsonNode(value.get(fieldKey));
}else {
object = PropertyElementManagement.getPropertyDocument(value.get(fieldKey));
}
map.put(fieldKey, object);
}
element.setProperty(key, map, OType.EMBEDDEDMAP);
break;
default:
Object object = getObjectFromJsonNode(value);
if(object != null) {
element.setProperty(key, object);
}
break;
}
} }
} catch(Exception e) { } catch(Exception e) {
@ -1035,6 +1067,7 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
logger.error(error); logger.error(error);
throw new ResourceRegistryException(error, e); throw new ResourceRegistryException(error, e);
} }
} }
OUTER_FOR: for(String key : oldKeys) { OUTER_FOR: for(String key : oldKeys) {
@ -1118,16 +1151,26 @@ public abstract class ElementManagement<El extends OElement, T extends Type> {
ArrayNode arrayNode = objectMapper.createArrayNode(); ArrayNode arrayNode = objectMapper.createArrayNode();
for(Object o : collection) { for(Object o : collection) {
Object obj = getPropertyForJson("PLACEHOLDER", o); JsonNode obj = getPropertyForJson("PLACEHOLDER", o);
if(obj!=null) { if(obj!=null) {
arrayNode.add((JsonNode) obj); arrayNode.add(obj);
} }
} }
return arrayNode; return arrayNode;
} }
if(object instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) object;
ObjectNode objectNode = objectMapper.createObjectNode();
for(String k : map.keySet()) {
JsonNode obj = getPropertyForJson("PLACEHOLDER", map.get(k));
objectNode.set(k, obj);
}
return objectNode;
}
return new TextNode(object.toString()); return new TextNode(object.toString());
} catch(Exception e) { } catch(Exception e) {

View File

@ -51,6 +51,10 @@ public class PropertyElementManagement {
public static ODocument getPropertyDocument(JsonNode jsonNode) throws ResourceRegistryException { public static ODocument getPropertyDocument(JsonNode jsonNode) throws ResourceRegistryException {
ODocument oDocument = null; ODocument oDocument = null;
if(jsonNode.isNull()) {
return null;
}
if(jsonNode.has(Element.CLASS_PROPERTY)) { if(jsonNode.has(Element.CLASS_PROPERTY)) {
// Complex type // Complex type
String type = ElementManagement.getClassProperty(jsonNode); String type = ElementManagement.getClassProperty(jsonNode);

View File

@ -46,6 +46,7 @@ public class JsonQuery {
protected ObjectMapper objectMapper; protected ObjectMapper objectMapper;
protected JsonNode jsonQuery; protected JsonNode jsonQuery;
protected JsonQueryERElement entryPoint; protected JsonQueryERElement entryPoint;
protected ODatabaseDocument oDatabaseDocument;
public JsonQuery() { public JsonQuery() {
this.objectMapper = new ObjectMapper(); this.objectMapper = new ObjectMapper();
@ -105,7 +106,7 @@ public class JsonQuery {
public String query() throws InvalidQueryException, ResourceRegistryException { public String query() throws InvalidQueryException, ResourceRegistryException {
ODatabaseDocument current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal(); ODatabaseDocument current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal();
ODatabaseDocument oDatabaseDocument = null; oDatabaseDocument = null;
try { try {
Integer limit = AccessPath.UNBOUNDED; Integer limit = AccessPath.UNBOUNDED;

View File

@ -7,7 +7,6 @@ import org.gcube.com.fasterxml.jackson.databind.JsonNode;
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; 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.ArrayNode;
import org.gcube.informationsystem.base.reference.AccessType; import org.gcube.informationsystem.base.reference.AccessType;
import org.gcube.informationsystem.contexts.reference.entities.Context;
import org.gcube.informationsystem.queries.templates.reference.entities.QueryTemplate; import org.gcube.informationsystem.queries.templates.reference.entities.QueryTemplate;
import org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException; import org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException; import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException;
@ -16,21 +15,25 @@ import org.gcube.informationsystem.resourceregistry.api.exceptions.queries.Inval
import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaViolationException; import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaViolationException;
import org.gcube.informationsystem.resourceregistry.contexts.security.QueryTemplatesSecurityContext; import org.gcube.informationsystem.resourceregistry.contexts.security.QueryTemplatesSecurityContext;
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext; import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext;
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagementUtility;
import org.gcube.informationsystem.resourceregistry.instances.base.entities.EntityElementManagement; import org.gcube.informationsystem.resourceregistry.instances.base.entities.EntityElementManagement;
import org.gcube.informationsystem.resourceregistry.queries.json.JsonQuery;
import org.gcube.informationsystem.resourceregistry.utils.Utility; import org.gcube.informationsystem.resourceregistry.utils.Utility;
import org.gcube.informationsystem.types.reference.entities.EntityType; import org.gcube.informationsystem.types.reference.entities.EntityType;
import org.gcube.informationsystem.utils.ElementMapper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument; import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.record.OVertex; import com.orientechnologies.orient.core.record.OVertex;
import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.executor.OResult;
import com.orientechnologies.orient.core.sql.executor.OResultSet; import com.orientechnologies.orient.core.sql.executor.OResultSet;
/** /**
* @author Luca Frosini (ISTI - CNR) * @author Luca Frosini (ISTI - CNR)
*/ */
public class QueryTemplateManagement extends EntityElementManagement<Context, EntityType> { public class QueryTemplateManagement extends EntityElementManagement<QueryTemplate, EntityType> {
private static Logger logger = LoggerFactory.getLogger(QueryTemplateManagement.class); private static Logger logger = LoggerFactory.getLogger(QueryTemplateManagement.class);
@ -52,18 +55,36 @@ public class QueryTemplateManagement extends EntityElementManagement<Context, En
getOClass(); getOClass();
} }
public void setName(String name) { protected void checkNameMatch() throws ResourceRegistryException {
if(jsonNode!=null && name!=null) {
String jsonName = jsonNode.get(QueryTemplate.NAME_PROPERTY).asText();
if(name.compareTo(jsonName)!=0) {
String error = String.format(
"Name provided in json (%s) differs from the one (%s) used to identify the %s instance",
jsonName, name, typeName);
throw new ResourceRegistryException(error);
}
}
}
public void setName(String name) throws ResourceRegistryException {
this.name = name; this.name = name;
checkNameMatch();
}
protected void checkJsonNode() throws ResourceRegistryException {
super.checkJsonNode();
checkNameMatch();
} }
public String getName() { public String getName() {
if (name == null) { if (name == null) {
if (element == null) { if (element == null) {
if (jsonNode != null) { if (jsonNode != null) {
name = jsonNode.get(Context.NAME_PROPERTY).asText(); name = jsonNode.get(QueryTemplate.NAME_PROPERTY).asText();
} }
} else { } else {
name = element.getProperty(Context.NAME_PROPERTY); name = element.getProperty(QueryTemplate.NAME_PROPERTY);
} }
} }
return name; return name;
@ -83,7 +104,7 @@ public class QueryTemplateManagement extends EntityElementManagement<Context, En
return queryTemplate; return queryTemplate;
} }
protected void checkIfNameAlreadyExists() throws AlreadyPresentException { protected StringBuffer getSelectQuery() {
StringBuffer select = new StringBuffer(); StringBuffer select = new StringBuffer();
select.append("SELECT FROM "); select.append("SELECT FROM ");
select.append(QueryTemplate.NAME); select.append(QueryTemplate.NAME);
@ -93,6 +114,11 @@ public class QueryTemplateManagement extends EntityElementManagement<Context, En
select.append("\""); select.append("\"");
select.append(getName()); select.append(getName());
select.append("\""); select.append("\"");
return select;
}
protected void checkIfNameAlreadyExists() throws AlreadyPresentException {
StringBuffer select = getSelectQuery();
StringBuffer errorMessage = new StringBuffer(); StringBuffer errorMessage = new StringBuffer();
errorMessage.append("A "); errorMessage.append("A ");
@ -110,8 +136,47 @@ public class QueryTemplateManagement extends EntityElementManagement<Context, En
} }
} }
protected void tryTemplate() throws InvalidQueryException { protected void tryTemplate() throws Exception {
QueryTemplate queryTemplate = ElementMapper.unmarshal(QueryTemplate.class, jsonNode.toString());
JsonNode jsonQueryNode = queryTemplate.getJsonQuery();
JsonQuery jsonQuery = new JsonQuery();
jsonQuery.setJsonQuery(jsonQueryNode);
try {
jsonQuery.query();
}catch (ResourceRegistryException e) {
throw e;
}catch (Exception e) {
throw new ResourceRegistryException(e);
}
}
@Override
public OVertex retrieveElement() throws NotFoundException, ResourceRegistryException {
try {
StringBuffer select = getSelectQuery();
OResultSet resultSet = oDatabaseDocument.query(select.toString(), new HashMap<>());
if(resultSet == null || !resultSet.hasNext()) {
throw new NotFoundException("Error retrieving " + QueryTemplate.NAME + " with name " + getName());
}
OResult oResult = resultSet.next();
OVertex queryTemplate = ElementManagementUtility.getElementFromOptional(oResult.getVertex());
logger.trace("{} representing vertex is {}", QueryTemplate.NAME, Utility.toJsonString(queryTemplate, true));
if(resultSet.hasNext()) {
throw new NotFoundException("Found more than one " + QueryTemplate.NAME + " with name " + name + ". This should not occur, please contact the administrator");
}
return queryTemplate;
} catch(NotFoundException e) {
throw getSpecificNotFoundException(e);
} catch(ResourceRegistryException e) {
throw e;
} catch(Exception e) {
throw new ResourceRegistryException(e);
}
} }
@Override @Override
@ -198,17 +263,27 @@ public class QueryTemplateManagement extends EntityElementManagement<Context, En
} }
public void setParams(JsonNode params) throws ResourceRegistryException { public void setParams(JsonNode params) throws ResourceRegistryException {
// TODO checks here
this.params = params; this.params = params;
} }
/** /**
* Run the query after having replaced query parameter with the provided values * Run the query after having replaced query parameter with the provided values
* @return * @return
* @throws Exception
*/ */
public String run() { public String run() throws ResourceRegistryException {
// TODO Auto-generated method stub try {
return null; String read = read();
QueryTemplate queryTemplate = ElementMapper.unmarshal(QueryTemplate.class, read);
JsonNode jsonNode = queryTemplate.getJsonQuery(params);
JsonQuery jsonQuery = new JsonQuery();
jsonQuery.setJsonQuery(jsonNode);
return jsonQuery.query();
} catch (ResourceRegistryException e) {
throw e;
} catch (Exception e) {
throw new ResourceRegistryException(e);
}
} }
public void sanityCheck() throws SchemaViolationException, ResourceRegistryException { public void sanityCheck() throws SchemaViolationException, ResourceRegistryException {

View File

@ -9,6 +9,7 @@ import org.gcube.informationsystem.queries.templates.impl.entities.QueryTemplate
import org.gcube.informationsystem.queries.templates.impl.properties.TemplateVariableImpl; import org.gcube.informationsystem.queries.templates.impl.properties.TemplateVariableImpl;
import org.gcube.informationsystem.queries.templates.reference.entities.QueryTemplate; import org.gcube.informationsystem.queries.templates.reference.entities.QueryTemplate;
import org.gcube.informationsystem.queries.templates.reference.properties.TemplateVariable; import org.gcube.informationsystem.queries.templates.reference.properties.TemplateVariable;
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
import org.gcube.informationsystem.resourceregistry.queries.JsonQueryTest; import org.gcube.informationsystem.resourceregistry.queries.JsonQueryTest;
import org.gcube.informationsystem.utils.ElementMapper; import org.gcube.informationsystem.utils.ElementMapper;
import org.junit.Test; import org.junit.Test;
@ -27,11 +28,11 @@ public class QueryTemplateManagementTest {
} }
@Test @Test
public void testCreate() throws Exception { public void completeTest() throws Exception {
File queryTemplatesDirectory = getQueryTemplatesDirectory(); File queryTemplatesDirectory = getQueryTemplatesDirectory();
File jsonQueryTemaplateFile = new File(queryTemplatesDirectory, "queryTemplate" + 1 + ".json"); File jsonQueryTemplateFile = new File(queryTemplatesDirectory, "queryTemplate" + 1 + ".json");
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(jsonQueryTemaplateFile); JsonNode jsonNode = objectMapper.readTree(jsonQueryTemplateFile);
String name = "Test"; String name = "Test";
@ -56,31 +57,73 @@ public class QueryTemplateManagementTest {
groupTemplateVariable.setName("$group"); groupTemplateVariable.setName("$group");
groupTemplateVariable.setDescription("SoftwareFacet group"); groupTemplateVariable.setDescription("SoftwareFacet group");
groupTemplateVariable.setDefaultValue("information-system"); groupTemplateVariable.setDefaultValue("information-system");
queryTemplate.addTemplateVariable(nameTemplateVariable); queryTemplate.addTemplateVariable(groupTemplateVariable);
String json = ElementMapper.marshal(queryTemplate); String json = ElementMapper.marshal(queryTemplate);
logger.info("Going to create {}: {}", QueryTemplate.NAME, json);
QueryTemplate gotQueryTemplate = ElementMapper.unmarshal(QueryTemplate.class, json); QueryTemplate gotQueryTemplate = ElementMapper.unmarshal(QueryTemplate.class, json);
logger.info("Going to create {} - {}", QueryTemplate.NAME, ElementMapper.marshal(gotQueryTemplate));
JsonNode gotTemplate = gotQueryTemplate.getTemplate(); JsonNode gotTemplate = gotQueryTemplate.getTemplate();
logger.info("{}", gotTemplate.toString()); logger.info("Template is {}", gotTemplate.toString());
// QueryTemplateManagement queryTemplateManagement = new QueryTemplateManagement(); logger.info("Query template is {}.\nQuery with default values is {}", gotTemplate.toString(), queryTemplate.getJsonQuery().toString());
// queryTemplateManagement.setName("Test");
// queryTemplateManagement.setJson(json);
// String created = queryTemplateManagement.create();
// logger.debug(created);
}
@Test
public void testUpdate() {
}
@Test
public void testDelete() {
QueryTemplateManagement queryTemplateManagement = new QueryTemplateManagement();
queryTemplateManagement.setName(name);
queryTemplateManagement.setJson(json);
try {
String created = queryTemplateManagement.create();
logger.info("Created {} is {}", QueryTemplate.NAME, created);
queryTemplateManagement = new QueryTemplateManagement();
queryTemplateManagement.setName("Test");
String read = queryTemplateManagement.read();
QueryTemplate readQueryTemplate = ElementMapper.unmarshal(QueryTemplate.class, read);
logger.info("Read {} is {}", QueryTemplate.NAME, ElementMapper.marshal(readQueryTemplate));
gotTemplate = readQueryTemplate.getTemplate();
logger.info("Read Template is {}", gotTemplate.toString());
try {
readQueryTemplate.setName("AnotheName");
queryTemplateManagement = new QueryTemplateManagement();
queryTemplateManagement.setName(name);
queryTemplateManagement.setJson(ElementMapper.marshal(readQueryTemplate));
queryTemplateManagement.update();
throw new Exception("It should not be possibile to update the " + QueryTemplate.NAME + " with json name different from the name used to identify the instance");
}catch (ResourceRegistryException e) {
// OK
logger.debug("{}", e);
}
// Restoring correct name
readQueryTemplate.setName(name);
jsonQueryTemplateFile = new File(queryTemplatesDirectory, "queryTemplate" + 1 + "-bis.json");
jsonNode = objectMapper.readTree(jsonQueryTemplateFile);
readQueryTemplate.setTemplate(jsonNode);
queryTemplateManagement = new QueryTemplateManagement();
queryTemplateManagement.setName(name);
queryTemplateManagement.setJson(ElementMapper.marshal(readQueryTemplate));
String updatedString = queryTemplateManagement.update();
QueryTemplate updatedQueryTemplate = ElementMapper.unmarshal(QueryTemplate.class, updatedString);
logger.info("Updated {} is {}", QueryTemplate.NAME, ElementMapper.marshal(updatedQueryTemplate));
gotTemplate = updatedQueryTemplate.getTemplate();
logger.info("Updated Template is {}", gotTemplate.toString());
queryTemplateManagement = new QueryTemplateManagement();
queryTemplateManagement.setName(name);
// TODO Set Values
queryTemplateManagement.run();
}finally {
queryTemplateManagement.delete();
}
} }
} }

View File

@ -0,0 +1,23 @@
{
"@class": "EService",
"consistsOf": [
{
"@class": "ConsistsOf",
"propagationConstraint" : {
"add": "propagate"
},
"target": {
"@class": "StateFacet",
"value": "$state"
}
},
{
"@class": "IsIdentifiedBy",
"target": {
"@class": "SoftwareFacet",
"group": "$group",
"name": "$name"
}
}
]
}