diff --git a/java/converters/rdf2Graph/src/main/java/io/opensaber/utils/converters/RDF2Graph.java b/java/converters/rdf2Graph/src/main/java/io/opensaber/utils/converters/RDF2Graph.java index 22aa9671b..0cbb95d9a 100644 --- a/java/converters/rdf2Graph/src/main/java/io/opensaber/utils/converters/RDF2Graph.java +++ b/java/converters/rdf2Graph/src/main/java/io/opensaber/utils/converters/RDF2Graph.java @@ -74,7 +74,7 @@ private static void updateGraph(Value subjectValue, IRI property, Value objectVa } valueList.add(literal.getLabel()); s.property(property.toString(), valueList).property("@type",datatype); - + }else{ s.property(property.toString(), literal.getLabel()).property("@type",datatype); } @@ -88,7 +88,7 @@ private static void updateGraph(Value subjectValue, IRI property, Value objectVa s.addEdge(property.toString(), o); } } - + private static Vertex getExistingVertexOrAdd(String label, Graph graph){ GraphTraversalSource t = graph.traversal(); GraphTraversal traversal = t.V(); @@ -119,73 +119,38 @@ private static void extractModelFromVertex(ModelBuilder builder, Vertex s) { builder.subject(s.label()); Iterator> propertyIter = s.properties(); while (propertyIter.hasNext()){ - VertexProperty property = propertyIter.next(); + VertexProperty property = propertyIter.next(); logger.debug("ADDING Property "+property.label()+": "+property.value()); - String literal = property.value(); + Object object = property.value(); Property metaProperty = property.property("@type"); String type = null; if(metaProperty.isPresent()){ - type = metaProperty.value().toString(); - } - Object object = literal; + type = metaProperty.value().toString(); + } logger.debug("TYPE is: "+type); - if(type!=null){ - switch(type){ - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#boolean": - logger.debug("Found boolean"); - object=vf.createLiteral(XMLDatatypeUtil.parseBoolean(literal)); - break; - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#byte": - object=vf.createLiteral(XMLDatatypeUtil.parseByte(literal)); - logger.debug("Found byte"); - break; - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#short": - object=vf.createLiteral(XMLDatatypeUtil.parseShort(literal)); - logger.debug("Found short"); - break; - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#int": - object=vf.createLiteral(XMLDatatypeUtil.parseInt(literal)); - logger.debug("Found int"); - break; - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#long": - object=vf.createLiteral(XMLDatatypeUtil.parseLong(literal)); - logger.debug("Found long"); - break; - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#float": - object=vf.createLiteral(XMLDatatypeUtil.parseFloat(literal)); - logger.debug("Found float"); - break; - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#double": - object=vf.createLiteral(XMLDatatypeUtil.parseDouble(literal)); - logger.debug("Found double"); - break; - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#integer": - object=vf.createLiteral(XMLDatatypeUtil.parseInteger(literal)); - logger.debug("Found integer"); - break; - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#decimal": - object=vf.createLiteral(XMLDatatypeUtil.parseDecimal(literal)); - logger.debug("Found decimal"); - break; - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#dateTime": - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#time": - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#date": - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gYearMonth": - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gMonthDay": - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gYear": - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gMonth": - case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gDay": - object=vf.createLiteral(XMLDatatypeUtil.parseCalendar(literal)); - logger.debug("Found date"); - break; -// case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#duration": -// object=vf.createLiteral(XMLDatatypeUtil.parseDuration(literal)); -// logger.info("Found duration"); -// break; - } - } - logger.debug("OBJECT ADDED is "+object+"-"+object.getClass().getName()); - builder.add(property.label(), object); + //Object object = literal; + if(object instanceof List){ + for(Object ob:(List)object){ + String literal = (String)ob; + Object finalObj = literal; + if(type!=null){ + finalObj = matchAndAddStatements(type, literal, vf); + } + builder.add(property.label(), finalObj); + + } + }else{ + String literal = (String)object; + Object finalObj = literal; + if(type!=null){ + finalObj = matchAndAddStatements(type, literal, vf); + } + builder.add(property.label(), finalObj); + } + + logger.debug("OBJECT ADDED is "+object+"-"+object.getClass().getName()); + //builder.add(property.label(), object); + } Iterator edgeIter = s.edges(Direction.OUT); Edge edge; @@ -193,7 +158,7 @@ private static void extractModelFromVertex(ModelBuilder builder, Vertex s) { while(edgeIter.hasNext()){ edge = edgeIter.next(); s = edge.inVertex(); -// builder.add(edge.label(), bNode); + // builder.add(edge.label(), bNode); Resource node; if(s.label().startsWith("_:")){ logger.debug("ADDING NODE - BLANK"); @@ -211,4 +176,63 @@ private static void extractModelFromVertex(ModelBuilder builder, Vertex s) { extractModelFromVertex(builder,s); } } + + private static Object matchAndAddStatements(String type, String literal, ValueFactory vf){ + Object object = literal; + switch(type){ + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#boolean": + logger.debug("Found boolean"); + + object=vf.createLiteral(XMLDatatypeUtil.parseBoolean(literal)); + break; + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#byte": + object=vf.createLiteral(XMLDatatypeUtil.parseByte(literal)); + logger.debug("Found byte"); + break; + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#short": + object=vf.createLiteral(XMLDatatypeUtil.parseShort(literal)); + logger.debug("Found short"); + break; + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#int": + object=vf.createLiteral(XMLDatatypeUtil.parseInt(literal)); + logger.debug("Found int"); + break; + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#long": + object=vf.createLiteral(XMLDatatypeUtil.parseLong(literal)); + logger.debug("Found long"); + break; + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#float": + object=vf.createLiteral(XMLDatatypeUtil.parseFloat(literal)); + logger.debug("Found float"); + break; + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#double": + object=vf.createLiteral(XMLDatatypeUtil.parseDouble(literal)); + logger.debug("Found double"); + break; + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#integer": + object=vf.createLiteral(XMLDatatypeUtil.parseInteger(literal)); + logger.debug("Found integer"); + break; + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#decimal": + object=vf.createLiteral(XMLDatatypeUtil.parseDecimal(literal)); + logger.debug("Found decimal"); + break; + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#dateTime": + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#time": + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#date": + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gYearMonth": + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gMonthDay": + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gYear": + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gMonth": + case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#gDay": + object=vf.createLiteral(XMLDatatypeUtil.parseCalendar(literal)); + logger.debug("Found date"); + break; + // case XMLConstants.W3C_XML_SCHEMA_NS_URI+"#duration": + // object=vf.createLiteral(XMLDatatypeUtil.parseDuration(literal)); + // logger.info("Found duration"); + // break; + } + return object; + } } diff --git a/java/cukes/src/test/java/io/opensaber/registry/test/RegistryIntegrationSteps.java b/java/cukes/src/test/java/io/opensaber/registry/test/RegistryIntegrationSteps.java index c4a93d2eb..969e66c10 100644 --- a/java/cukes/src/test/java/io/opensaber/registry/test/RegistryIntegrationSteps.java +++ b/java/cukes/src/test/java/io/opensaber/registry/test/RegistryIntegrationSteps.java @@ -6,6 +6,8 @@ import java.io.IOException; import java.io.StringReader; +import java.net.URLEncoder; +import java.util.HashMap; import java.util.Map; import com.fasterxml.jackson.databind.ObjectMapper; @@ -44,6 +46,7 @@ public class RegistryIntegrationSteps extends RegistryTestBase{ private static final String VALID_JSONLD= "school.jsonld"; //private static final String VALID_NEWJSONLD= "newSchool.jsonld"; private static final String VALID_NEWJSONLD= "teacher.jsonld"; + private static final String ENTITY_JSONLD= "basicProficiencyLevel.jsonld"; private static final String INVALID_LABEL_JSONLD = "invalid-label.jsonld"; private static final String INVALID_NEWJSONLD= "invalid-teacher.jsonld"; private static final String ADD_ENTITY = "add"; @@ -73,6 +76,12 @@ public void jsonldData(){ assertNotNull(jsonld); } + @Given("^an id for a non-existent record") + public void non_existent_record(){ + id=generateRandomId(); + updateId=id; + } + @Given("^a record with invalid type") public void invalidTypeJsonldData(){ setJsonld(INVALID_LABEL_JSONLD); @@ -109,6 +118,23 @@ public void setMissingAuthToken(){ public void addEntity(){ response = callRegistryCreateAPI(); } + + @When("^an entity for the record is issued into the registry$") + public void add_entity_to_existing_record_in_registry(){ + jsonldData(ENTITY_JSONLD); + response = callRegistryCreateAPI(baseUrl+updateId,baseUrl+"basicProficiencyLevel"); + } + + @When("^the same entity for the record is issued into the registry$") + public void add_existing_entity_to_existing_record_in_registry(){ + response = callRegistryCreateAPI(baseUrl+updateId,baseUrl+"basicProficiencyLevel"); + } + + public void jsonldData(String filename){ + setJsonld(filename); + id=setJsonldWithNewRootLabel(); + assertNotNull(jsonld); + } private ResponseEntity callRegistryCreateAPI() { headers.setContentType(MediaType.APPLICATION_JSON); @@ -120,6 +146,20 @@ private ResponseEntity callRegistryCreateAPI() { return response; } + private ResponseEntity callRegistryCreateAPI(String entityLabel, String property) { + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity(jsonld,headers); + Map uriVariables = new HashMap(); + uriVariables.put("id", entityLabel); + uriVariables.put("prop", property); + ResponseEntity response = restTemplate.postForEntity( + baseUrl+ADD_ENTITY+"?id={id}&prop={prop}", + entity, + Response.class, + uriVariables); + return response; + } + @Then("^record issuing should be successful") public void verifySuccessfulResponse() throws JsonParseException, JsonMappingException, IOException{ checkSuccessfulResponse(); @@ -210,6 +250,7 @@ public void retrieving_the_record_from_the_registry(){ response = callRegistryReadAPI(); } + private ResponseEntity callRegistryReadAPI() { HttpEntity entity = new HttpEntity<>(headers); ResponseEntity response = restTemplate.exchange(baseUrl+"/"+id, HttpMethod.GET,entity,Response.class); diff --git a/java/cukes/src/test/java/io/opensaber/registry/test/create.feature b/java/cukes/src/test/java/io/opensaber/registry/test/create.feature index 79484d0da..1f0f688ed 100644 --- a/java/cukes/src/test/java/io/opensaber/registry/test/create.feature +++ b/java/cukes/src/test/java/io/opensaber/registry/test/create.feature @@ -46,4 +46,26 @@ Feature: Inserting a record into the registry And a valid auth token When issuing the record into the registry Then record issuing should be unsuccessful - And error message is Data validation failed! \ No newline at end of file + And error message is Data validation failed! + + Scenario: Adding an entity for an existing record + Given a record issued into the registry + And a valid auth token + When an entity for the record is issued into the registry + Then record issuing should be successful + And fetching the record from the registry should match the issued record + + Scenario: Adding a duplicate entity for an existing record + Given a record issued into the registry + And an entity for the record is issued into the registry + And a valid auth token + When the same entity for the record is issued into the registry + Then record issuing should be unsuccessful + And error message is Cannot insert duplicate record + + Scenario: Adding an entity for an non-existent record + Given an id for a non-existent record + And a valid auth token + When an entity for the record is issued into the registry + Then record issuing should be unsuccessful + And error message is Entity does not exist \ No newline at end of file diff --git a/java/cukes/src/test/resources/basicProficiencyLevel.jsonld b/java/cukes/src/test/resources/basicProficiencyLevel.jsonld new file mode 100644 index 000000000..d6d25b131 --- /dev/null +++ b/java/cukes/src/test/resources/basicProficiencyLevel.jsonld @@ -0,0 +1,35 @@ +{ + "id": "open-saber.registry.create", + "ver": "1.0", + "ets": "11234", + "params": + { + "did": "", + "key": "", + "msgid": "" + }, + + "request": + { + "@context": + { + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", + "teacher": "http://localhost:8080/", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "@vocab": "http://localhost:8080/" + }, + + "@id": "<@id>", + "@type": "BasicProficiencyLevel", + "proficiencySubject": + { + "@id": "teacher:SubjectCode-PHYSICS" + }, + + "proficiencyAcademicQualification": + { + "@id": "teacher:AcademicQualificationTypeCode-PHD" + } + } +} \ No newline at end of file diff --git a/java/registry/src/main/java/io/opensaber/registry/config/GenericConfiguration.java b/java/registry/src/main/java/io/opensaber/registry/config/GenericConfiguration.java index e3169d8e8..b5b33d5ba 100644 --- a/java/registry/src/main/java/io/opensaber/registry/config/GenericConfiguration.java +++ b/java/registry/src/main/java/io/opensaber/registry/config/GenericConfiguration.java @@ -156,11 +156,11 @@ public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthorizationInterceptor(authorizationFilter(), gson())) .addPathPatterns("/**").excludePathPatterns("/health", "/error").order(1); registry.addInterceptor(new RDFConversionInterceptor(rdfConverter(), gson())) - .addPathPatterns("/create", "/update/{id}","/add", "/update").order(2); + .addPathPatterns("/add", "/update").order(2); registry.addInterceptor(new RDFValidationMappingInterceptor(rdfValidationMapper(), gson())) - .addPathPatterns("/create", "/update/{id}","/add", "/update").order(3); + .addPathPatterns("/add", "/update").order(3); registry.addInterceptor(new RDFValidationInterceptor(rdfValidator(), gson())) - .addPathPatterns("/create", "/update/{id}", "/add", "/update").order(4); + .addPathPatterns("/add", "/update").order(4); /*registry.addInterceptor(new JSONLDConversionInterceptor(jsonldConverter())) .addPathPatterns("/read/{id}").order(2);*/ } diff --git a/java/registry/src/main/java/io/opensaber/registry/controller/RegistryController.java b/java/registry/src/main/java/io/opensaber/registry/controller/RegistryController.java index 4adf99d92..658b9038e 100644 --- a/java/registry/src/main/java/io/opensaber/registry/controller/RegistryController.java +++ b/java/registry/src/main/java/io/opensaber/registry/controller/RegistryController.java @@ -48,7 +48,7 @@ public class RegistryController { @Value("${registry.context.base}") private String registryContext; - @RequestMapping(value = "/create", method = RequestMethod.POST) + /*@RequestMapping(value = "/create", method = RequestMethod.POST) public ResponseEntity addEntity(@RequestAttribute Request requestModel) { Model rdf = (Model) requestModel.getRequestMap().get("rdf"); ResponseParams responseParams = new ResponseParams(); @@ -70,13 +70,12 @@ public ResponseEntity addEntity(@RequestAttribute Request requestModel responseParams.setErrmsg(e.getMessage()); } return new ResponseEntity<>(response, HttpStatus.OK); - } + }*/ @RequestMapping(value = "/add", method = RequestMethod.POST) public ResponseEntity addToExistingEntity(@RequestAttribute Request requestModel, @RequestParam(value="id", required = false) String id, @RequestParam(value="prop", required = false) String property) { - Model rdf = (Model) requestModel.getRequestMap().get("rdf"); ResponseParams responseParams = new ResponseParams(); Response response = new Response(Response.API_ID.CREATE, "OK", responseParams); @@ -99,7 +98,7 @@ public ResponseEntity addToExistingEntity(@RequestAttribute Request re return new ResponseEntity<>(response, HttpStatus.OK); } - @RequestMapping(value = "/read/{id}", method = RequestMethod.GET) + /*@RequestMapping(value = "/read/{id}", method = RequestMethod.GET) public ResponseEntity getEntity(@PathVariable("id") String id) { id = registryContext + id; ResponseParams responseParams = new ResponseParams(); @@ -110,8 +109,8 @@ public ResponseEntity getEntity(@PathVariable("id") String id) { logger.debug("FETCHED: " + entityModel); String jenaJSON = registryService.frameEntity(entityModel); JSONObject jenaObj = new JSONObject(jenaJSON); - /*Map resultMap = new HashMap(); - resultMap.put(Constants.RESPONSE_ATTRIBUTE, entityModel);*/ + Map resultMap = new HashMap(); + resultMap.put(Constants.RESPONSE_ATTRIBUTE, entityModel); response.setResult(jenaObj.toMap()); responseParams.setStatus(Response.Status.SUCCCESSFUL); } catch (RecordNotFoundException e) { @@ -125,7 +124,7 @@ public ResponseEntity getEntity(@PathVariable("id") String id) { logger.error("ERROR!", e); } return new ResponseEntity<>(response, HttpStatus.OK); - } + }*/ @RequestMapping(value = "/{id}", method = RequestMethod.GET) public ResponseEntity readEntity(@PathVariable("id") String id) { @@ -155,7 +154,7 @@ public ResponseEntity readEntity(@PathVariable("id") String id) { return new ResponseEntity<>(response, HttpStatus.OK); } - @ResponseBody + /*@ResponseBody @RequestMapping(value = "/update/{id}", method = RequestMethod.PATCH) public ResponseEntity updateEntity(@RequestAttribute Request requestModel, @PathVariable("id") String id) { @@ -179,7 +178,7 @@ public ResponseEntity updateEntity(@RequestAttribute Request requestMo logger.error("ERROR!", e); } return new ResponseEntity<>(response, HttpStatus.OK); - } + }*/ @ResponseBody @RequestMapping(value = "/update", method = RequestMethod.POST) @@ -190,7 +189,7 @@ public ResponseEntity update(@RequestAttribute Request requestModel) { Response response = new Response(Response.API_ID.UPDATE, "OK", responseParams); try { - registryService.updateEntity(rdf, null); + registryService.updateEntity(rdf); responseParams.setErrmsg(""); responseParams.setStatus(Response.Status.SUCCCESSFUL); } catch (RecordNotFoundException | EntityCreationException e) { diff --git a/java/registry/src/main/java/io/opensaber/registry/dao/impl/RegistryDaoImpl.java b/java/registry/src/main/java/io/opensaber/registry/dao/impl/RegistryDaoImpl.java index f41b62073..007176739 100644 --- a/java/registry/src/main/java/io/opensaber/registry/dao/impl/RegistryDaoImpl.java +++ b/java/registry/src/main/java/io/opensaber/registry/dao/impl/RegistryDaoImpl.java @@ -40,23 +40,23 @@ public class RegistryDaoImpl implements RegistryDao { public static final String META = "meta."; private static Logger logger = LoggerFactory.getLogger(RegistryDaoImpl.class); - + @Autowired private DatabaseProvider databaseProvider; @Autowired private EncryptionService encryptionService; - + @Value("${registry.context.base}") private String registryContext; - + @Autowired SchemaConfigurator schemaConfigurator; @Autowired ApplicationContext appContext; - + @Value("${feature.toggling}") private Boolean featureToggling; @@ -70,38 +70,58 @@ public List getEntityList() { public String addEntity(Graph entity, String label) throws DuplicateRecordException, NoSuchElementException, EncryptionException, AuditFailedException, RecordNotFoundException{ logger.debug("Database Provider features: \n" + databaseProvider.getGraphStore().features()); Graph graphFromStore = databaseProvider.getGraphStore(); - GraphTraversalSource traversalSource = graphFromStore.traversal(); - if (traversalSource.clone().V().hasLabel(label).hasNext()) { - // closeGraph(graphFromStore); + GraphTraversalSource dbGraphTraversalSource = graphFromStore.traversal(); + if (dbGraphTraversalSource.clone().V().hasLabel(label).hasNext()) { + //closeGraph(graphFromStore); throw new DuplicateRecordException(Constants.DUPLICATE_RECORD_MESSAGE); } - + String rootNodeLabel; TinkerGraph graph = (TinkerGraph) entity; - String rootNodeLabel = createOrUpdateEntity(graph, label, "create"); + GraphTraversalSource traversal = graph.traversal(); + if (graphFromStore.features().graph().supportsTransactions()) { + org.apache.tinkerpop.gremlin.structure.Transaction tx = graphFromStore.tx(); + tx.onReadWrite(org.apache.tinkerpop.gremlin.structure.Transaction.READ_WRITE_BEHAVIOR.AUTO); + //rootNodeLabel = createOrUpdateEntity(dbGraphTraversalSource, graph, label, "create"); + rootNodeLabel = addOrUpdateVerticesAndEdges(dbGraphTraversalSource, traversal, label, "create"); + tx.commit(); + }else{ + rootNodeLabel = addOrUpdateVerticesAndEdges(dbGraphTraversalSource, traversal, label, "create"); + } logger.info("Successfully created entity with label " + rootNodeLabel); // closeGraph(graphFromStore); return rootNodeLabel; } - - + + @Override public String addEntity(Graph entity, String label, String rootNodeLabel, String property) throws DuplicateRecordException, RecordNotFoundException, NoSuchElementException, EncryptionException, AuditFailedException{ logger.debug("Database Provider features: \n" + databaseProvider.getGraphStore().features()); Graph graphFromStore = databaseProvider.getGraphStore(); - GraphTraversalSource traversalSource = graphFromStore.traversal(); - if (rootNodeLabel!=null && property!=null && !traversalSource.clone().V().hasLabel(rootNodeLabel).hasNext()) { - // closeGraph(graphFromStore); + GraphTraversalSource dbGraphTraversalSource = graphFromStore.traversal(); + if (rootNodeLabel!=null && property!=null && !dbGraphTraversalSource.clone().V().hasLabel(rootNodeLabel).hasNext()) { + //closeGraph(graphFromStore); throw new RecordNotFoundException(Constants.ENTITY_NOT_FOUND); - } else if (traversalSource.clone().V().hasLabel(label).hasNext()) { - // closeGraph(graphFromStore); + } else if (dbGraphTraversalSource.clone().V().hasLabel(label).hasNext()) { + //closeGraph(graphFromStore); throw new DuplicateRecordException(Constants.DUPLICATE_RECORD_MESSAGE); } TinkerGraph graph = (TinkerGraph) entity; - label = createOrUpdateEntity(graph, label, "create"); - - if (rootNodeLabel != null && property != null) { - connectNodes(rootNodeLabel, label, property); + GraphTraversalSource traversal = graph.traversal(); + if (graphFromStore.features().graph().supportsTransactions()) { + org.apache.tinkerpop.gremlin.structure.Transaction tx = graphFromStore.tx(); + tx.onReadWrite(org.apache.tinkerpop.gremlin.structure.Transaction.READ_WRITE_BEHAVIOR.AUTO); + //label = createOrUpdateEntity(graph, label, "create"); + label = addOrUpdateVerticesAndEdges(dbGraphTraversalSource, traversal, label, "create"); + if (rootNodeLabel!=null && property!=null){ + connectNodes(rootNodeLabel, label, property); + } + tx.commit(); + }else{ + label = addOrUpdateVerticesAndEdges(dbGraphTraversalSource, traversal, label, "create"); + if (rootNodeLabel!=null && property!=null){ + connectNodes(rootNodeLabel, label, property); + } } logger.info("Successfully created entity with label " + label); // closeGraph(graphFromStore); @@ -117,31 +137,24 @@ private void closeGraph(Graph graph) { } } */ - + private void connectNodes(String rootLabel, String label, String property) throws RecordNotFoundException, NoSuchElementException, EncryptionException, AuditFailedException { Graph graphFromStore = databaseProvider.getGraphStore(); GraphTraversalSource traversalSource = graphFromStore.traversal(); - + if (!traversalSource.clone().V().hasLabel(rootLabel).hasNext()) { // closeGraph(graphFromStore); throw new RecordNotFoundException(Constants.ENTITY_NOT_FOUND); } - + if (!traversalSource.clone().V().hasLabel(label).hasNext()) { // closeGraph(graphFromStore); throw new RecordNotFoundException(Constants.ENTITY_NOT_FOUND); } - - if (graphFromStore.features().graph().supportsTransactions()) { - org.apache.tinkerpop.gremlin.structure.Transaction tx = graphFromStore.tx(); - tx.onReadWrite(org.apache.tinkerpop.gremlin.structure.Transaction.READ_WRITE_BEHAVIOR.AUTO); - connectRootToEntity(traversalSource, rootLabel, label, property); - tx.commit(); - } else { - connectRootToEntity(traversalSource, rootLabel, label, property); - } + connectRootToEntity(traversalSource, rootLabel, label, property); + } - + private void connectRootToEntity(GraphTraversalSource dbTraversalSource, String rootLabel, String label, String property) throws RecordNotFoundException, NoSuchElementException, EncryptionException, AuditFailedException { GraphTraversal rootGts = dbTraversalSource.clone().V().hasLabel(rootLabel); GraphTraversal entityGts = dbTraversalSource.clone().V().hasLabel(label); @@ -164,10 +177,8 @@ private void connectRootToEntity(GraphTraversalSource dbTraversalSource, String * @throws EncryptionException * @throws NoSuchElementException */ - private String createOrUpdateEntity(Graph entity, String rootLabel, String methodOrigin) - throws NoSuchElementException, EncryptionException, AuditFailedException, RecordNotFoundException { - Graph graphFromStore = databaseProvider.getGraphStore(); - GraphTraversalSource dbGraphTraversalSource = graphFromStore.traversal(); + + /*private String createOrUpdateEntity(GraphTraversalSource dbGraphTraversalSource, Graph entity, String rootLabel, String methodOrigin) throws NoSuchElementException, EncryptionException, AuditFailedException, RecordNotFoundException{ TinkerGraph graph = (TinkerGraph) entity; GraphTraversalSource traversal = graph.traversal(); @@ -185,9 +196,9 @@ private String createOrUpdateEntity(Graph entity, String rootLabel, String metho rootNodeLabel = addOrUpdateVerticesAndEdges(dbGraphTraversalSource, traversal, rootLabel, methodOrigin); } - return rootNodeLabel; + return addOrUpdateVerticesAndEdges(dbGraphTraversalSource, traversal, rootLabel, methodOrigin); - } + }*/ /** * This method creates the root node of the entity if it already isn't present in the graph store @@ -214,7 +225,7 @@ private String addOrUpdateVerticesAndEdges(GraphTraversalSource dbTraversalSourc logger.info(String.format("Root node label %s already exists. Updating properties for the root node.", rootLabel)); Vertex existingVertex = hasLabel.next(); //if(!methodOrigin.equalsIgnoreCase("upsert")){ - copyProperties(v, existingVertex, methodOrigin); + copyProperties(v, existingVertex, methodOrigin); //} addOrUpdateVertexAndEdge(v, existingVertex, dbTraversalSource, methodOrigin); } else { @@ -258,7 +269,7 @@ private void addOrUpdateVertexAndEdge(Vertex v, Vertex dbVertex, GraphTraversalS } } logger.info("Matching list size:"+edgeVertexMatchList.size()); - + while(edges.hasNext()) { Edge e = edges.next(); Vertex ver = e.inVertex(); @@ -314,10 +325,10 @@ private void addOrUpdateVertexAndEdge(Vertex v, Vertex dbVertex, GraphTraversalS } - + /*private void deleteEdgeAndNode(Vertex dbVertex, Edge e, Optional edgeAlreadyExists,List edgeVertexMatchList, String methodOrigin) throws AuditFailedException, RecordNotFoundException{ - + Graph graphFromStore = databaseProvider.getGraphStore(); GraphTraversalSource traversalSource = graphFromStore.traversal(); GraphTraversal dbHasLabel = traversalSource.clone().V().hasLabel(dbVertex.label()); @@ -337,7 +348,7 @@ private void addOrUpdateVertexAndEdge(Vertex v, Vertex dbVertex, GraphTraversalS } } }*/ - + /** * This method checks if deletion of edge and node is required based on criteria and invokes deleteEdgeAndNode method * @param dbSourceVertex @@ -351,18 +362,18 @@ private void verifyAndDelete(Vertex dbSourceVertex, Edge e, Optional edgeA throws AuditFailedException{ boolean isSingleValued = schemaConfigurator.isSingleValued(e.label()); if((edgeAlreadyExists.isPresent() && methodOrigin.equalsIgnoreCase("update")) || isSingleValued){ - Iterator edgeIter = dbSourceVertex.edges(Direction.OUT, e.label()); - while(edgeIter.hasNext()){ - Edge edge = edgeIter.next(); - Optional existingEdgeVertex = - edgeVertexMatchList.stream().filter(ed -> ed.label().equalsIgnoreCase(edge.label()) && ed.inVertex().label().equalsIgnoreCase(edge.inVertex().label())).findFirst(); - if(!existingEdgeVertex.isPresent()){ - deleteEdgeAndNode(dbSourceVertex, edge, null); - } + Iterator edgeIter = dbSourceVertex.edges(Direction.OUT, e.label()); + while(edgeIter.hasNext()){ + Edge edge = edgeIter.next(); + Optional existingEdgeVertex = + edgeVertexMatchList.stream().filter(ed -> ed.label().equalsIgnoreCase(edge.label()) && ed.inVertex().label().equalsIgnoreCase(edge.inVertex().label())).findFirst(); + if(!existingEdgeVertex.isPresent()){ + deleteEdgeAndNode(dbSourceVertex, edge, null); } + } } } - + /** * This method deletes the edge and node if the node is an orphan node and if not, deletes only the edge * @param v @@ -372,15 +383,15 @@ private void verifyAndDelete(Vertex dbSourceVertex, Edge e, Optional edgeA */ private void deleteEdgeAndNode(Vertex v, Edge dbEdgeToBeRemoved, Vertex dbVertexToBeDeleted) throws AuditFailedException{ logger.info("Deleting edge and node:"+dbEdgeToBeRemoved.label()); - if(dbVertexToBeDeleted == null){ - dbVertexToBeDeleted = dbEdgeToBeRemoved.inVertex(); - } - Iterator inEdgeIter = dbVertexToBeDeleted.edges(Direction.IN); + if(dbVertexToBeDeleted == null){ + dbVertexToBeDeleted = dbEdgeToBeRemoved.inVertex(); + } + Iterator inEdgeIter = dbVertexToBeDeleted.edges(Direction.IN); Iterator outEdgeIter = dbVertexToBeDeleted.edges(Direction.OUT); if((inEdgeIter.hasNext() && IteratorUtils.count(inEdgeIter) > 1) || outEdgeIter.hasNext()){ logger.info("Deleting edge only:"+dbEdgeToBeRemoved.label()); dbEdgeToBeRemoved.remove(); - + }else{ logger.info("Deleting edge and node:"+dbEdgeToBeRemoved.label()+":"+dbVertexToBeDeleted.label()); dbVertexToBeDeleted.remove(); @@ -395,8 +406,9 @@ private void deleteEdgeAndNode(Vertex v, Edge dbEdgeToBeRemoved, Vertex dbVertex .oldObject(dbVertexToBeDeleted.label()) .newObject(null) .record(databaseProvider); - - } + + } + /** * Blank nodes are no longer supported. If the input data has a blank node, which is identified @@ -411,13 +423,13 @@ private String generateBlankNodeLabel(String label) { return label; } - private boolean isBlankNode(String label){ + /*private boolean isBlankNode(String label){ if(label.startsWith("_:")) { return true; } return false; } - +*/ private boolean isIRI(String label){ UrlValidator urlValidator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS); if(urlValidator.isValid(label)) { @@ -436,15 +448,24 @@ public boolean updateEntity(Graph entityForUpdate, String rootNodeLabel, String Graph graphFromStore = databaseProvider.getGraphStore(); GraphTraversalSource dbGraphTraversalSource = graphFromStore.traversal(); TinkerGraph graphForUpdate = (TinkerGraph) entityForUpdate; - + GraphTraversalSource traversal = graphForUpdate.traversal(); // Check if the root node being updated exists in the database GraphTraversal hasRootLabel = dbGraphTraversalSource.clone().V().hasLabel(rootNodeLabel); if (!hasRootLabel.hasNext()) { // closeGraph(graphFromStore); throw new RecordNotFoundException(Constants.ENTITY_NOT_FOUND); } else { - createOrUpdateEntity(graphForUpdate, rootNodeLabel, methodOrigin); - // closeGraph(graphFromStore); + if (graphFromStore.features().graph().supportsTransactions()) { + org.apache.tinkerpop.gremlin.structure.Transaction tx = graphFromStore.tx(); + tx.onReadWrite(org.apache.tinkerpop.gremlin.structure.Transaction.READ_WRITE_BEHAVIOR.AUTO); + //createOrUpdateEntity(graphForUpdate, rootNodeLabel, methodOrigin); + addOrUpdateVerticesAndEdges(dbGraphTraversalSource, traversal, rootNodeLabel, methodOrigin); + tx.commit(); + }else{ + addOrUpdateVerticesAndEdges(dbGraphTraversalSource, traversal, rootNodeLabel, methodOrigin); + //createOrUpdateEntity(graphForUpdate, rootNodeLabel, methodOrigin); + } + //closeGraph(graphFromStore); } return false; } @@ -457,18 +478,18 @@ public Graph getEntityById(String label) throws RecordNotFoundException, NoSuchE GraphTraversal hasLabel = traversalSource.clone().V().hasLabel(label); Graph parsedGraph = TinkerGraph.open(); if (!hasLabel.hasNext()) { - // closeGraph(graphFromStore); + //closeGraph(graphFromStore); throw new RecordNotFoundException(Constants.ENTITY_NOT_FOUND); } else { Vertex subject = hasLabel.next(); Vertex newSubject = parsedGraph.addVertex(subject.label()); copyProperties(subject, newSubject,"read"); extractGraphFromVertex(parsedGraph,newSubject,subject); - // closeGraph(graphFromStore); + // closeGraph(graphFromStore); } return parsedGraph; } - + private void copyProperties(Vertex subject, Vertex newSubject, String methodOrigin) throws NoSuchElementException, EncryptionException, AuditFailedException { @@ -508,31 +529,31 @@ private void copyProperties(Vertex subject, Vertex newSubject, String methodOrig setMetaPropertyFromMap(newSubject, propertyMetaPropertyMap); } - private boolean isaMetaProperty(String key) { - return key.startsWith(META); - } + private boolean isaMetaProperty(String key) { + return key.startsWith(META); + } - private void setProperty(Vertex v, String key, Object newValue, String methodOrigin) throws AuditFailedException { - VertexProperty vp = v.property(key); - Object oldValue = vp.isPresent() ? vp.value() : null; - if(oldValue!=null && !methodOrigin.equalsIgnoreCase("update") && !schemaConfigurator.isSingleValued(key)){ - List valueList = new ArrayList(); + private void setProperty(Vertex v, String key, Object newValue, String methodOrigin) throws AuditFailedException { + VertexProperty vp = v.property(key); + Object oldValue = vp.isPresent() ? vp.value() : null; + if(oldValue!=null && !methodOrigin.equalsIgnoreCase("update") && !schemaConfigurator.isSingleValued(key)){ + List valueList = new ArrayList(); if(oldValue instanceof List){ valueList = (List)oldValue; } else{ String valueStr = (String)oldValue; valueList.add(valueStr); } - + if(newValue instanceof List){ valueList.addAll((List)newValue); } else{ valueList.add(newValue); } newValue = valueList; - } - v.property(key, newValue); - /*if(schemaConfigurator.isSingleValued(key)){ + } + v.property(key, newValue); + /*if(schemaConfigurator.isSingleValued(key)){ System.out.println("Printing value for single-valued:"+newValue); v.property(key, newValue); }else if(oldValue!=null && !methodOrigin.equalsIgnoreCase("update")){ @@ -551,83 +572,83 @@ private void setProperty(Vertex v, String key, Object newValue, String methodOri System.out.println("Printing value for else case:"+newValue); v.property(key, newValue); }*/ - if (!isaMetaProperty(key) && !Objects.equals(oldValue, newValue)) { - GraphTraversal configTraversal = - v.graph().traversal().clone().V().has(T.label, Constants.GRAPH_GLOBAL_CONFIG); - if (configTraversal.hasNext() - && configTraversal.next().property(Constants.PERSISTENT_GRAPH).value().equals(true)) { - - AuditRecord record = appContext.getBean(AuditRecord.class); - record - .subject(v.label()) - .predicate(key) - .oldObject(oldValue) - .newObject(newValue) - .record(databaseProvider); - } else { - // System.out.println("NOT AUDITING"); - } - } else { - // System.out.println("NO CHANGE!"); - } - } + if (!isaMetaProperty(key) && !Objects.equals(oldValue, newValue)) { + GraphTraversal configTraversal = + v.graph().traversal().clone().V().has(T.label, Constants.GRAPH_GLOBAL_CONFIG); + if (configTraversal.hasNext() + && configTraversal.next().property(Constants.PERSISTENT_GRAPH).value().equals(true)) { - private void setMetaPropertyFromMap(Vertex newSubject, HashMap> propertyMetaPropertyMap) { - Iterator propertyIter = propertyMetaPropertyMap.entrySet().iterator(); - while(propertyIter.hasNext()){ - Map.Entry pair = (Map.Entry)propertyIter.next(); + AuditRecord record = appContext.getBean(AuditRecord.class); + record + .subject(v.label()) + .predicate(key) + .oldObject(oldValue) + .newObject(newValue) + .record(databaseProvider); + } else { + // System.out.println("NOT AUDITING"); + } + } else { + // System.out.println("NO CHANGE!"); + } + } + + private void setMetaPropertyFromMap(Vertex newSubject, HashMap> propertyMetaPropertyMap) { + Iterator propertyIter = propertyMetaPropertyMap.entrySet().iterator(); + while(propertyIter.hasNext()){ + Map.Entry pair = (Map.Entry)propertyIter.next(); logger.info("PROPERTY <- " + pair.getKey()); - HashMap _mpmap = (HashMap) pair.getValue(); - Iterator _mpmapIter = _mpmap.entrySet().iterator(); - while(_mpmapIter.hasNext()) { - Map.Entry _pair = (Map.Entry)_mpmapIter.next(); + HashMap _mpmap = (HashMap) pair.getValue(); + Iterator _mpmapIter = _mpmap.entrySet().iterator(); + while(_mpmapIter.hasNext()) { + Map.Entry _pair = (Map.Entry)_mpmapIter.next(); logger.info("META PROPERTY <- " + _pair.getKey() + "|" + _pair.getValue()); - newSubject.property(pair.getKey().toString()).property(_pair.getKey().toString(),_pair.getValue().toString()); - } - } - } - - private void setMetaProperty(Vertex subject, Vertex newSubject, VertexProperty property, String methodOrigin) throws AuditFailedException { - if(subject.graph().features().vertex().supportsMetaProperties()) { - Iterator> metaPropertyIter = property.properties(); - while (metaPropertyIter.hasNext()) { - Property metaProperty = metaPropertyIter.next(); - if (newSubject.graph().features().vertex().supportsMetaProperties()) { - newSubject.property(property.key()).property(metaProperty.key(), metaProperty.value()); - } else { - String metaKey = getMetaKey(property, metaProperty); - setProperty(newSubject,metaKey, metaProperty.value(), methodOrigin); - } - } - } - } - - private String getMetaKey(VertexProperty property, Property metaProperty) { - return META + property.key() + "." + metaProperty.key(); - } - - private void buildPropertyMetaMap(HashMap> propertyMetaPropertyMap, VertexProperty property) { - HashMap metaPropertyMap; - logger.info("META PROPERTY "+property); - Pattern pattern = Pattern.compile("meta\\.(.*)\\.(.*)"); - Matcher match = pattern.matcher(property.key().toString()); - if(match.find()){ - String _property = match.group(1); - String _meta_property = match.group(2); - logger.info("MATCHED meta property "+match.group(1)+ " "+match.group(2)); - if(propertyMetaPropertyMap.containsKey(property.key())){ - logger.info("FOUND in propertyMetaPropertyMap"); - metaPropertyMap = propertyMetaPropertyMap.get(property.key()); - } else { - logger.info("CREATING metaPropertyMap in propertyMetaPropertyMap"); - metaPropertyMap = new HashMap<>(); - propertyMetaPropertyMap.put(_property,metaPropertyMap); - } - metaPropertyMap.put(_meta_property,property.value().toString()); - } - } - - /*@Override + newSubject.property(pair.getKey().toString()).property(_pair.getKey().toString(),_pair.getValue().toString()); + } + } + } + + private void setMetaProperty(Vertex subject, Vertex newSubject, VertexProperty property, String methodOrigin) throws AuditFailedException { + if(subject.graph().features().vertex().supportsMetaProperties()) { + Iterator> metaPropertyIter = property.properties(); + while (metaPropertyIter.hasNext()) { + Property metaProperty = metaPropertyIter.next(); + if (newSubject.graph().features().vertex().supportsMetaProperties()) { + newSubject.property(property.key()).property(metaProperty.key(), metaProperty.value()); + } else { + String metaKey = getMetaKey(property, metaProperty); + setProperty(newSubject,metaKey, metaProperty.value(), methodOrigin); + } + } + } + } + + private String getMetaKey(VertexProperty property, Property metaProperty) { + return META + property.key() + "." + metaProperty.key(); + } + + private void buildPropertyMetaMap(HashMap> propertyMetaPropertyMap, VertexProperty property) { + HashMap metaPropertyMap; + logger.info("META PROPERTY "+property); + Pattern pattern = Pattern.compile("meta\\.(.*)\\.(.*)"); + Matcher match = pattern.matcher(property.key().toString()); + if(match.find()){ + String _property = match.group(1); + String _meta_property = match.group(2); + logger.info("MATCHED meta property "+match.group(1)+ " "+match.group(2)); + if(propertyMetaPropertyMap.containsKey(property.key())){ + logger.info("FOUND in propertyMetaPropertyMap"); + metaPropertyMap = propertyMetaPropertyMap.get(property.key()); + } else { + logger.info("CREATING metaPropertyMap in propertyMetaPropertyMap"); + metaPropertyMap = new HashMap<>(); + propertyMetaPropertyMap.put(_property,metaPropertyMap); + } + metaPropertyMap.put(_meta_property,property.value().toString()); + } + } + + /*@Override public boolean deleteEntity (Graph entity, String rootLabel) throws RecordNotFoundException,AuditFailedException { Graph graphFromStore = databaseProvider.getGraphStore(); GraphTraversalSource traversalSource = graphFromStore.traversal(); @@ -635,7 +656,7 @@ public boolean deleteEntity (Graph entity, String rootLabel) throws RecordNotFou if (!dbHasLabel.hasNext()) { throw new RecordNotFoundException(Constants.ENTITY_NOT_FOUND); } - + GraphTraversal hasNestedLabel = traversalSource.clone().V().hasLabel(labelToBeDeleted); if (!hasNestedLabel.hasNext()) { throw new RecordNotFoundException(Constants.ENTITY_NOT_FOUND); @@ -643,7 +664,7 @@ public boolean deleteEntity (Graph entity, String rootLabel) throws RecordNotFou TinkerGraph graph = (TinkerGraph) entity; GraphTraversalSource traversal = graph.traversal(); GraphTraversal gts = traversal.clone().V().hasLabel(rootLabel); - + if (graphFromStore.features().graph().supportsTransactions()) { org.apache.tinkerpop.gremlin.structure.Transaction tx; tx = graphFromStore.tx(); @@ -658,7 +679,7 @@ public boolean deleteEntity (Graph entity, String rootLabel) throws RecordNotFou return false; }*/ - /*private void deleteEdgeAndNode(Vertex v, GraphTraversal gts) throws AuditFailedException{ + /*private void deleteEdgeAndNode(Vertex v, GraphTraversal gts) throws AuditFailedException{ List dbEdgesForVertex = ImmutableList.copyOf(v.edges(Direction.OUT)); if(gts.hasNext()){ Vertex vertex = gts.next(); @@ -695,8 +716,8 @@ public boolean deleteEntity (Graph entity, String rootLabel) throws RecordNotFou } }*/ - - + + private void extractGraphFromVertex(Graph parsedGraph,Vertex parsedGraphSubject,Vertex s) throws NoSuchElementException, EncryptionException, AuditFailedException { Iterator edgeIter = s.edges(Direction.OUT); @@ -721,7 +742,7 @@ private void extractGraphFromVertex(Graph parsedGraph,Vertex parsedGraphSubject, } } - private void dump_graph(Graph parsedGraph, String filename) { + /*private void dump_graph(Graph parsedGraph, String filename) { try { parsedGraph.io(IoCore.graphson()).writeGraph(filename); } catch (IOException e) { @@ -731,5 +752,5 @@ private void dump_graph(Graph parsedGraph, String filename) { private AuthInfo getCurrentUserInfo() { return (AuthInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - } + }*/ } diff --git a/java/registry/src/main/java/io/opensaber/registry/service/RegistryService.java b/java/registry/src/main/java/io/opensaber/registry/service/RegistryService.java index 0177fec27..f2cb9bf2d 100644 --- a/java/registry/src/main/java/io/opensaber/registry/service/RegistryService.java +++ b/java/registry/src/main/java/io/opensaber/registry/service/RegistryService.java @@ -12,12 +12,12 @@ public interface RegistryService { public List getEntityList(); - public String addEntity(Model rdfModel) throws DuplicateRecordException, EntityCreationException, EncryptionException, AuditFailedException, MultipleEntityException, RecordNotFoundException; + //public String addEntity(Model rdfModel) throws DuplicateRecordException, EntityCreationException, EncryptionException, AuditFailedException, MultipleEntityException, RecordNotFoundException; public String addEntity(Model rdfModel, String subject, String property) throws DuplicateRecordException, EntityCreationException, EncryptionException, AuditFailedException, MultipleEntityException, RecordNotFoundException; - public boolean updateEntity(Model entity, String rootNodeLabel) throws RecordNotFoundException, EntityCreationException, EncryptionException, AuditFailedException, MultipleEntityException; + public boolean updateEntity(Model entity) throws RecordNotFoundException, EntityCreationException, EncryptionException, AuditFailedException, MultipleEntityException; public org.eclipse.rdf4j.model.Model getEntityById(String id) throws RecordNotFoundException, EncryptionException, AuditFailedException; diff --git a/java/registry/src/main/java/io/opensaber/registry/service/impl/RegistryServiceImpl.java b/java/registry/src/main/java/io/opensaber/registry/service/impl/RegistryServiceImpl.java index 26ccaa716..7232b3c00 100644 --- a/java/registry/src/main/java/io/opensaber/registry/service/impl/RegistryServiceImpl.java +++ b/java/registry/src/main/java/io/opensaber/registry/service/impl/RegistryServiceImpl.java @@ -61,15 +61,15 @@ public class RegistryServiceImpl implements RegistryService { @Autowired EncryptionService encryptionService; - @org.springframework.beans.factory.annotation.Value("${feature.toggling}") - private Boolean featureToggling; + /*@org.springframework.beans.factory.annotation.Value("${feature.toggling}") + private Boolean featureToggling;*/ @Override public List getEntityList(){ return registryDao.getEntityList(); } - @Override + /*@Override public String addEntity(Model rdfModel) throws DuplicateRecordException, EntityCreationException, EncryptionException, AuditFailedException, MultipleEntityException, RecordNotFoundException { try { // Append _: to the root node label to create the entity as Apache Jena removes the _: for the root node label @@ -84,7 +84,7 @@ public String addEntity(Model rdfModel) throws DuplicateRecordException, EntityC logger.error("Exception when creating entity: ", ex); throw ex; } - } + }*/ @Override public String addEntity(Model rdfModel, String subject, String property) throws DuplicateRecordException, EntityCreationException, @@ -106,7 +106,7 @@ public String addEntity(Model rdfModel, String subject, String property) throws } @Override - public boolean updateEntity(Model entity, String rootNodeLabel) throws RecordNotFoundException, EntityCreationException, EncryptionException, AuditFailedException, MultipleEntityException { + public boolean updateEntity(Model entity) throws RecordNotFoundException, EntityCreationException, EncryptionException, AuditFailedException, MultipleEntityException { String label = getRootLabel(entity); Graph graph = generateGraphFromRDF(entity); return registryDao.updateEntity(graph, label,"update"); diff --git a/java/registry/src/test/java/io/opensaber/registry/controller/RegistryControllerTest.java b/java/registry/src/test/java/io/opensaber/registry/controller/RegistryControllerTest.java index 40637ef39..c2027a523 100644 --- a/java/registry/src/test/java/io/opensaber/registry/controller/RegistryControllerTest.java +++ b/java/registry/src/test/java/io/opensaber/registry/controller/RegistryControllerTest.java @@ -1,6 +1,8 @@ package io.opensaber.registry.controller; import static org.junit.Assert.*; + +import io.opensaber.converters.JenaRDF4J; import io.opensaber.pojos.HealthCheckResponse; import io.opensaber.registry.app.OpenSaberApplication; import io.opensaber.registry.authorization.AuthorizationToken; @@ -12,8 +14,11 @@ import io.opensaber.registry.sink.DatabaseProvider; import io.opensaber.registry.tests.utility.TestHelper; import io.opensaber.registry.util.RDFUtil; +import io.opensaber.validators.shex.shaclex.ShaclexValidator; + import org.apache.jena.rdf.model.ResourceFactory; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; +import org.assertj.core.util.Arrays; import org.junit.*; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; @@ -23,6 +28,7 @@ import static org.mockito.Mockito.when; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; @@ -43,8 +49,11 @@ import io.opensaber.registry.service.RegistryService; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.Resource; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest(classes = {OpenSaberApplication.class, RegistryController.class, @@ -54,9 +63,13 @@ public class RegistryControllerTest extends RegistryTestBase { private static final String VALID_JSONLD = "school.jsonld"; + private static final String VALIDNEW_JSONLD = "school1.jsonld"; private static final String CONTEXT_CONSTANT = "sample:"; private boolean isInitialized = false; + + @Value("${registry.context.base}") + private String registryContextBase; @Autowired private RegistryService registryService; @@ -111,7 +124,7 @@ public void initialize() { @Test public void test_adding_a_new_record() throws DuplicateRecordException, EntityCreationException, EncryptionException, AuditFailedException, MultipleEntityException, RecordNotFoundException{ Model model = getNewValidRdf(VALID_JSONLD, CONTEXT_CONSTANT); - registryService.addEntity(model); + registryService.addEntity(model,null,null); assertEquals(5, IteratorUtils.count(databaseProvider.getGraphStore().traversal().clone().V() .filter(v -> !v.get().label().equalsIgnoreCase(Constants.GRAPH_GLOBAL_CONFIG)) @@ -123,10 +136,10 @@ public void test_adding_duplicate_record() throws DuplicateRecordException, Enti expectedEx.expect(DuplicateRecordException.class); expectedEx.expectMessage(Constants.DUPLICATE_RECORD_MESSAGE); Model model = getNewValidRdf(VALID_JSONLD, CONTEXT_CONSTANT); - String entityId = registryService.addEntity(model); + String entityId = registryService.addEntity(model,null,null); RDFUtil.updateRdfModelNodeId(model, ResourceFactory.createResource("http://example.com/voc/teacher/1.0.0/School"), entityId); - registryService.addEntity(model); + registryService.addEntity(model,null,null); } @Test @@ -134,7 +147,7 @@ public void test_adding_record_with_no_entity() throws Exception { Model model = ModelFactory.createDefaultModel(); expectedEx.expect(EntityCreationException.class); expectedEx.expectMessage(Constants.NO_ENTITY_AVAILABLE_MESSAGE); - registryService.addEntity(model); + registryService.addEntity(model,null,null); closeDB(); } @@ -144,7 +157,7 @@ public void test_adding_record_with_more_than_one_entity() throws Exception { model.add(getNewValidRdf(VALID_JSONLD, CONTEXT_CONSTANT)); expectedEx.expect(MultipleEntityException.class); expectedEx.expectMessage(Constants.ADD_UPDATE_MULTIPLE_ENTITIES_MESSAGE); - registryService.addEntity(model); + registryService.addEntity(model,null,null); closeDB(); } @@ -171,9 +184,25 @@ public void test_health_check_down_scenario() throws Exception { } }); } + + @Test + public void test_adding_record_with_multi_valued_literal_properties() throws Exception { + Model model = getNewValidRdf(VALIDNEW_JSONLD); + List roots = RDFUtil.getRootLabels(model); + String[] ct = {"I","II","III","IV"}; + List classesTaught = Arrays.asList(ct); + for(Object obj : classesTaught){ + model.add(roots.get(0), ResourceFactory.createProperty(registryContextBase+"classesTaught"), (String)obj); + } + String response = registryService.addEntity(model,null,null); + assertTrue(ShaclexValidator.parse(registryService.frameEntity(registryService.getEntityById(response)),"JSON-LD").isIsomorphicWith(model)); + closeDB(); + } public void closeDB() throws Exception{ databaseProvider.shutdown(); } + + } diff --git a/java/registry/src/test/java/io/opensaber/registry/controller/RegistryTestBase.java b/java/registry/src/test/java/io/opensaber/registry/controller/RegistryTestBase.java index f33870726..3d6a74293 100644 --- a/java/registry/src/test/java/io/opensaber/registry/controller/RegistryTestBase.java +++ b/java/registry/src/test/java/io/opensaber/registry/controller/RegistryTestBase.java @@ -98,6 +98,7 @@ public Model getNewValidRdf(String fileName, String contextConstant){ public Model getNewValidRdf(String fileName){ setJsonld(fileName); + setJsonldWithNewRootLabel(); return ShaclexValidator.parse(jsonld, FORMAT); } @@ -127,6 +128,12 @@ public void setJsonldWithNewRootLabel(String label){ jsonld = jsonld.replace(REPLACING_SUBJECT_LABEL, label); } + public void setJsonldWithNewRootLabel(){ + while (jsonld.contains(REPLACING_SUBJECT_LABEL)) { + jsonld = jsonld.replaceFirst(REPLACING_SUBJECT_LABEL, CONTEXT_CONSTANT+generateRandomId()); + } + } + public static String generateRandomId(){ return UUID.randomUUID().toString(); } diff --git a/java/registry/src/test/java/io/opensaber/registry/dao/impl/RegistryDaoImplTest.java b/java/registry/src/test/java/io/opensaber/registry/dao/impl/RegistryDaoImplTest.java index 563b04de8..32e67e61f 100644 --- a/java/registry/src/test/java/io/opensaber/registry/dao/impl/RegistryDaoImplTest.java +++ b/java/registry/src/test/java/io/opensaber/registry/dao/impl/RegistryDaoImplTest.java @@ -690,15 +690,8 @@ public void test_add_iri_node_to_existing_entity() String response = registryDao.addEntity(graph, "_:"+rootLabel); Graph entity = registryDao.getEntityById(response); Model updateRdfModel = getNewValidRdf("add_node.jsonld"); - /*// Remove literal properties from update - removeStatementFromModel(updateRdfModel, ResourceFactory.createProperty("http://example.com/voc/teacher/1.0.0/clusterResourceCentre")); - removeStatementFromModel(updateRdfModel, ResourceFactory.createProperty("http://example.com/voc/teacher/1.0.0/revenueBlock")); - removeStatementFromModel(updateRdfModel, ResourceFactory.createProperty("http://example.com/voc/teacher/1.0.0/revenueBlock")); - // Update new rdf model with the labels generated for School and Address nodes - updateNodeLabel(updateRdfModel, "http://example.com/voc/teacher/1.0.0/School"); - updateNodeLabel(updateRdfModel, "http://example.com/voc/teacher/1.0.0/IndianUrbanPostalAddress");*/ - // Call update entity + // Call add entity Graph updateGraph = TinkerGraph.open(); String label = getRootLabel(updateRdfModel); generateGraphFromRDF(updateGraph, updateRdfModel); @@ -706,7 +699,6 @@ public void test_add_iri_node_to_existing_entity() Graph newUpdatedGraphResult = registryDao.getEntityById(newResponse); assertEquals(2, IteratorUtils.count(newUpdatedGraphResult.traversal().clone().V())); Graph updatedGraphResult = registryDao.getEntityById(response); - /*Model updateRdfModelWithoutType = getModelwithOnlyUpdateFacts(rdfModel, updateRdfModel,Arrays.asList("http://example.com/voc/teacher/1.0.0/address")); checkIfAuditRecordsAreRight(updatedGraphResult,generateUpdateMapFromRDF(updateRdfModelWithoutType));*/ Model addedModel = JenaRDF4J.asJenaModel(RDF2Graph.convertGraph2RDFModel(entity, response)); @@ -731,7 +723,7 @@ public void test_add_iri_node_to_existing_entity() assertThat(result, hasSize(5)); } - @Test @Ignore + @Test public void test_update_iri_node_and_literal_nodes() throws DuplicateRecordException, RecordNotFoundException, EncryptionException, NoSuchElementException, AuditFailedException, LabelCannotBeNullException, MultipleEntityException, EntityCreationException { @@ -741,9 +733,22 @@ public void test_update_iri_node_and_literal_nodes() String rootLabel = updateGraphFromRdf(rdfModel, graph); String response = registryDao.addEntity(graph, "_:"+rootLabel); Graph entity = registryDao.getEntityById(response); - Model updateRdfModel = createRdfFromFile("update_node.jsonld", rootLabel); - /*updateNodeLabel(updateRdfModel, "http://example.com/voc/teacher/1.0.0/School"); - updateNodeLabel(updateRdfModel, "http://example.com/voc/teacher/1.0.0/IndianUrbanPostalAddress");*/ + Model addedModel = JenaRDF4J.asJenaModel(RDF2Graph.convertGraph2RDFModel(entity, response)); + Model updateRdfModel = createRdfFromFile("update_node.jsonld", response); + StmtIterator stmt = addedModel.listStatements(ResourceFactory.createResource(response), ResourceFactory.createProperty("http://example.com/voc/teacher/1.0.0/address"),(RDFNode)null); + while(stmt.hasNext()){ + Statement s = stmt.next(); + Resource subject = s.getSubject(); + Property predicate = s.getPredicate(); + if(subject.toString().equals(response) && predicate.toString().equalsIgnoreCase("http://example.com/voc/teacher/1.0.0/address")){ + RDFNode rdfNode = s.getObject(); + updateRdfModel.add(s); + updateRdfModel.add((Resource)rdfNode, + ResourceFactory.createProperty("http://example.com/voc/teacher/1.0.0/mohalla"), "Updated Sector 14"); + updateRdfModel.add((Resource)rdfNode, + ResourceFactory.createProperty("http://example.com/voc/teacher/1.0.0/municipality"), "Updated MCG"); + } + } Graph updateGraph = TinkerGraph.open(); //String label = getRootLabel(updateRdfModel); @@ -754,7 +759,7 @@ public void test_update_iri_node_and_literal_nodes() /*Model updateRdfModelWithoutType = getModelwithOnlyUpdateFacts(rdfModel, updateRdfModel,Arrays.asList("http://example.com/voc/teacher/1.0.0/address")); checkIfAuditRecordsAreRight(updatedGraphResult,generateUpdateMapFromRDF(updateRdfModelWithoutType));*/ - Model addedModel = JenaRDF4J.asJenaModel(RDF2Graph.convertGraph2RDFModel(entity, response)); + Model updateRdfModelWithoutType = getModelwithOnlyUpdateFacts(addedModel, updateRdfModel,Arrays.asList()); Model deletedFacts = getModelwithDeletedFacts(addedModel, updateRdfModel, updateRdfModelWithoutType); checkIfAuditRecordsAreRight(updatedGraphResult,generateUpdateMapFromRDF(updateRdfModelWithoutType, deletedFacts)); diff --git a/java/registry/src/test/resources/school1.jsonld b/java/registry/src/test/resources/school1.jsonld new file mode 100644 index 000000000..04ea49766 --- /dev/null +++ b/java/registry/src/test/resources/school1.jsonld @@ -0,0 +1,30 @@ +{ + "@id":"!samp131d", + "sample:academicCalendarYearEnd": "2018", + "sample:academicCalendarYearStart": "2017", + "sample:assemblyConstituency": "Gurgaon", + "@type": "sample:School", + "sample:schoolName": "Bluebells", + "sample:udiseNumber": "9876", + "sample:clusterResourceCentre": "some Cluster Resource", + "sample:address": { + "@id":"!samp131d", + "sample:district": "Gurgaon", + "@type": "sample:IndianUrbanPostalAddress", + "sample:mohalla": "Sector 14", + "sample:municipality": "MCG", + "sample:city": "Gurgaon", + "sample:pinCode": "122001", + "sample:wardNumber": "456" + }, + "sample:area": { + "@id": "sample:AreaTypeCode-URBAN" + }, + "sample:revenueBlock": "some block", + "@context": { + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", + "sample": "http://example.com/voc/teacher/1.0.0/" + } +}