Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete event and annotations #330

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
123 changes: 119 additions & 4 deletions phis2-ws/src/main/java/opensilex/service/dao/AnnotationDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import opensilex.service.dao.exception.DAOPersistenceException;

import org.apache.jena.arq.querybuilder.ExprFactory;
import org.apache.jena.arq.querybuilder.UpdateBuilder;
import org.apache.jena.arq.querybuilder.WhereBuilder;
import org.apache.jena.datatypes.xsd.XSDDatatype;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.rdf.model.Literal;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.ResourceFactory;
import org.apache.jena.sparql.core.TriplePath;
import org.apache.jena.sparql.path.Path;
import org.apache.jena.sparql.path.PathFactory;
import org.apache.jena.vocabulary.DCTerms;
import org.apache.jena.vocabulary.RDF;
import org.eclipse.rdf4j.query.BindingSet;
Expand All @@ -27,6 +35,9 @@
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.query.Update;
import org.eclipse.rdf4j.query.UpdateExecutionException;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
Expand Down Expand Up @@ -501,10 +512,114 @@ private ArrayList<Annotation> getAnnotationsWithoutBodyValuesFromResult(TupleQue
return annotations;
}

@Override
public void delete(List<Annotation> objects) throws DAOPersistenceException, Exception {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* @return an {@link UpdateBuilder} producing a SPARQL query which remove all annotation having only
* the given annotation as target.
* @example
* <pre>
* DELETE { ?src_a ?src_a_pred ?src_a_obj . }
* WHERE {
* ?src_a oa:hasTarget+ "http://www.phenome-fppn.fr/test/id/annotation/1e331ca4-2e63-4728-8373-050a2b51c3dc".
* ?src_a ?src_a_pred ?src_a_obj
* MINUS {
* ?src_a oa:hasTarget ?s2, ?s3 .
* FILTER( ?s2 != ?s3)
* }
* }
* </pre>
* @param annotationUri : the annotation on which we check if there exist an another annotation
* @throws RepositoryException
* @throws UpdateExecutionException
*/
protected UpdateBuilder getRemoveAllSuperAnnotationQuery(String annotationUri) throws RepositoryException, UpdateExecutionException {

Node srcAnnotation = NodeFactory.createVariable("src_a"),
srcAnnotationTarget = NodeFactory.createVariable("src_a_target"),
srcAnnotationTarget2 = NodeFactory.createVariable("src_a_target2"),
srcAnnotationPredicate = NodeFactory.createVariable("src_a_pred"),
srcAnnotationObject = NodeFactory.createVariable("src_a_obj"),
oaTargetPred = NodeFactory.createURI(Oa.RELATION_HAS_TARGET.toString()),
targetAnnotation = NodeFactory.createURI(annotationUri);

Path oaTargetPath = PathFactory.pathOneOrMore1(PathFactory.pathLink(oaTargetPred)); // create the property path (oa:target)+
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commentaire sur sa ligne propre


return new UpdateBuilder()
.addDelete(srcAnnotation, srcAnnotationPredicate, srcAnnotationObject)
.addWhere(new TriplePath(srcAnnotation, oaTargetPath, targetAnnotation) )
.addWhere(srcAnnotation, srcAnnotationPredicate, srcAnnotationObject)

// add the minus clause in order to check if the annotation has more than one target
.addMinus(new WhereBuilder()
.addWhere(srcAnnotation, oaTargetPred, srcAnnotationTarget)
.addWhere(srcAnnotation, oaTargetPred, srcAnnotationTarget2)
.addFilter(new ExprFactory().ne(srcAnnotationTarget, srcAnnotationTarget2))
);
}

/**
* @return an {@link UpdateBuilder} producing a SPARQL query which remove all incoming and outcoming
* annotation triples
* @example
* <pre>
* DELETE {
* http://www.phenome-fppn.fr/test/id/annotation/1e331ca4-2e63-4728-8373-050a2b51c3dc ?p ?o .
* ?s ?p1 http://www.phenome-fppn.fr/test/id/annotation/1e331ca4-2e63-4728-8373-050a2b51c3dc
* } WHERE {
* { http://www.phenome-fppn.fr/test/id/annotation/1e331ca4-2e63-4728-8373-050a2b51c3dc ?p ?o }
* UNION
* {?s ?p1 http://www.phenome-fppn.fr/test/id/annotation/1e331ca4-2e63-4728-8373-050a2b51c3dc }
* }
* </pre>
* @param annotationUri : the URI of the {@link Annotation} to delete
* @throws RepositoryException
*/
protected UpdateBuilder getRemoveAllAnnotationTripleQuery(String annotationUri) throws RepositoryException {

Node subject = NodeFactory.createVariable("s"),
outPredicate = NodeFactory.createVariable("p_out"),
inPredicate = NodeFactory.createVariable("p_in"),
object = NodeFactory.createVariable("o"),
annotation = NodeFactory.createURI(annotationUri);

return new UpdateBuilder()
.addDelete(annotation,outPredicate,object)
.addDelete(subject,inPredicate,annotation)
.addWhere(annotation, outPredicate, object)
.addUnion(new WhereBuilder().addWhere(subject,inPredicate,annotation));
}

/**
* @apiNote
* WARNING : delete an annotation trigger the deletion of all annotation which only have the annotation as target .
*/
@Override
protected void deleteAll(List<String> annotationUris) throws RepositoryException, UpdateExecutionException {

RepositoryConnection conn = getConnection();

for(String uri : annotationUris) {

String removeIncomingsAnnotationQuery = getRemoveAllSuperAnnotationQuery(uri).buildRequest().toString();
String removeAnnotationQuery = getRemoveAllAnnotationTripleQuery(uri).buildRequest().toString();

// first delete all annotation which has the annotationUri as target
Update update = conn.prepareUpdate(QueryLanguage.SPARQL,removeIncomingsAnnotationQuery);
update.execute();
// then delete the annotation itself
update = conn.prepareUpdate(QueryLanguage.SPARQL,removeAnnotationQuery);
update.execute();
}
}

@Override
public void delete(List<Annotation> annotations) throws DAOPersistenceException, Exception, IllegalAccessException, IllegalAccessException {

// get all annotation URIs into an ArrayList via Stream API
ArrayList<String> uris = annotations.stream()
.map(annotation -> annotation.getUri())
.collect(Collectors.toCollection(ArrayList::new));
checkAndDeleteAll(uris);
}

@Override
public List<Annotation> update(List<Annotation> objects) throws DAOPersistenceException, Exception {
Expand Down
134 changes: 131 additions & 3 deletions phis2-ws/src/main/java/opensilex/service/dao/EventDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@
package opensilex.service.dao;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.jena.arq.querybuilder.ExprFactory;
import org.apache.jena.arq.querybuilder.SelectBuilder;
import org.apache.jena.arq.querybuilder.UpdateBuilder;
import org.apache.jena.arq.querybuilder.WhereBuilder;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.rdf.model.Resource;
Expand All @@ -21,6 +27,8 @@
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.query.Update;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -33,6 +41,7 @@
import opensilex.service.dao.manager.Rdf4jDAO;
import opensilex.service.model.User;
import opensilex.service.ontology.Contexts;
import opensilex.service.ontology.Oa;
import opensilex.service.ontology.Oeev;
import opensilex.service.ontology.Rdf;
import opensilex.service.ontology.Rdfs;
Expand Down Expand Up @@ -634,10 +643,129 @@ public void addDeleteWhenUpdatingToUpdateBuilder(UpdateBuilder updateBuilder, Ev
Oeev.concerns.getURI(),
event.getConcernedItems());
}

@Override
public void delete(List<Event> objects) throws DAOPersistenceException, Exception {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
public void delete(List<Event> events) throws DAOPersistenceException, Exception {

// get all events URIs into an ArrayList via Stream API
List<String> uris = events.stream()
.map(event -> event.getUri())
.collect(Collectors.toCollection(ArrayList::new));
checkAndDeleteAll(uris);
}

/**
* @apiNote
* WARNING : delete an event trigger the deletion of all annotation which only have the event as target .
*/
@Override
protected void deleteAll(List<String> uris) throws RepositoryException {

AnnotationDAO annotationDAO = new AnnotationDAO(user);
RepositoryConnection conn = getConnection();

// make sure the two DAO use the same connection
annotationDAO.setConnection(conn);

for(String eventUri : uris) {

// get all annotation on event before deleting the event itself
List<String> annotationUris = getAllAnnotationUrisWithEventAsTarget(eventUri);

UpdateBuilder deleteEventQuery = deleteEventTriples(eventUri);
Update deleteEventUpdate = conn.prepareUpdate(QueryLanguage.SPARQL,deleteEventQuery.build().toString());
deleteEventUpdate.execute();

// delete all annotation which have the given event as target
if(! annotationUris.isEmpty())
annotationDAO.deleteAll(annotationUris);
}
}

/**
* @return the {@link List} of {@link Annotation} which only have the given event uri as target.
* @example
* SELECT DISTINCT ?a
* WHERE {
* ?annotation oa:hasTarget "http://www.phenome-fppn.fr/id/event/5a1b3c0d-58af-4cfb-811e-e141b11453b1".
* MINUS {
* ?annotation oa:hasTarget ?target.
* FILTER ("http://www.phenome-fppn.fr/id/event/5a1b3c0d-58af-4cfb-811e-e141b11453b1" = ?target)
* }
*
* }
* @param eventUri
*/
protected List<String> getAllAnnotationUrisWithEventAsTarget(String eventUri) {

Node annotation = NodeFactory.createVariable("annotation"),
target = NodeFactory.createVariable("target"),
oaTargetPred = NodeFactory.createURI(Oa.RELATION_HAS_TARGET.toString()),
event = NodeFactory.createURI(eventUri),
annotationGraph = NodeFactory.createURI(Contexts.ANNOTATIONS.toString());

String removeAnnotationQuery = new SelectBuilder()
.addVar(annotation)
.addGraph(annotationGraph, new WhereBuilder()
.addWhere(annotation,oaTargetPred,event)
.addMinus(new WhereBuilder()
.addWhere(annotation,oaTargetPred,target)
.addFilter(new ExprFactory().ne(event, target)))
)
.buildString();

List<String> annotationUris = new LinkedList<>();
TupleQuery getAnnotationQuery = getConnection().prepareTupleQuery(removeAnnotationQuery);
TupleQueryResult res = getAnnotationQuery.evaluate();

while(res.hasNext()) {
BindingSet bs = res.next();
annotationUris.add(bs.getValue(annotation.getName()).stringValue());
}
return annotationUris;
}

/**
* @return an {@link UpdateBuilder} producing a SPARQL query which remove all event triples
* @example
* <pre>
* DELETE {
* "http://www.phenome-fppn.fr/id/event/5a1b3c0d-58af-4cfb-811e-e141b11453b1" ?p ?o .
* ?s ?p_in "http://www.phenome-fppn.fr/id/event/5a1b3c0d-58af-4cfb-811e-e141b11453b1" .
* ?time ?time_pred ?time_object
* } WHERE {
* { "http://www.phenome-fppn.fr/id/event/5a1b3c0d-58af-4cfb-811e-e141b11453b1" ?p_out ?o ;
* time:hasTime ?time.
* ?time ?time_pred ?time_object . }
* UNION { ?s ?p_in "http://www.phenome-fppn.fr/id/event/5a1b3c0d-58af-4cfb-811e-e141b11453b1" }
* }
* }
* </pre>
* @param eventUri : the URI of the {@link Event} to delete
*/
protected UpdateBuilder deleteEventTriples(String eventUri) {

Node outPredicate = NodeFactory.createVariable("p_out"),
object = NodeFactory.createVariable("o"),
subject = NodeFactory.createVariable("s"),
inPredicate = NodeFactory.createVariable("p_in"),
time = NodeFactory.createVariable("time"),
timePred = NodeFactory.createVariable("time_pred"),
timeObj = NodeFactory.createVariable("time_object");

Node hasTimePred = NodeFactory.createURI(Time.hasTime.getURI()),
eventNode = NodeFactory.createURI(eventUri);

return new UpdateBuilder()
.addDelete(eventNode,outPredicate,object)
.addDelete(time,timePred,timeObj)
.addDelete(subject,inPredicate,eventNode)

.addWhere(eventNode,outPredicate,object)
.addWhere(eventNode,hasTimePred,time)
.addWhere(time,timePred,timeObj)
.addUnion(
new WhereBuilder().addWhere(subject,inPredicate,eventNode));
}

@Override
Expand Down
17 changes: 17 additions & 0 deletions phis2-ws/src/main/java/opensilex/service/dao/manager/DAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ public abstract class DAO<T> {
*/
public String remoteUserAdress;
public User user;


public String getRemoteUserAdress() {
return remoteUserAdress;
}

public void setRemoteUserAdress(String remoteUserAdress) {
this.remoteUserAdress = remoteUserAdress;
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

/**
* Creates in the storage the list of objects given.
Expand Down
Loading