source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 6:6dfbe2400f64

Last change on this file since 6:6dfbe2400f64 was 6:6dfbe2400f64, checked in by casties, 12 years ago

delete annotation should work now.

File size: 10.8 KB
Line 
1/**
2 *
3 */
4package de.mpiwg.itgroup.annotations.neo4j;
5
6import java.util.ArrayList;
7import java.util.Calendar;
8import java.util.List;
9
10import org.apache.log4j.Logger;
11import org.neo4j.graphdb.Direction;
12import org.neo4j.graphdb.GraphDatabaseService;
13import org.neo4j.graphdb.Node;
14import org.neo4j.graphdb.Relationship;
15import org.neo4j.graphdb.RelationshipType;
16import org.neo4j.graphdb.Transaction;
17import org.neo4j.graphdb.index.Index;
18import org.neo4j.graphdb.index.IndexHits;
19
20import de.mpiwg.itgroup.annotations.Annotation;
21import de.mpiwg.itgroup.annotations.Annotation.FragmentTypes;
22
23/**
24 * @author casties
25 *
26 */
27public class AnnotationStore {
28
29        protected static Logger logger = Logger.getLogger(AnnotationStore.class);
30
31        protected GraphDatabaseService graphDb;
32       
33        public static enum NodeTypes {
34                ANNOTATION, PERSON, TARGET
35        }
36
37        protected List<Index<Node>> nodeIndexes;
38       
39        public static enum RelationTypes implements RelationshipType {
40                ANNOTATES, CREATED
41        }
42
43        public static String ANNOTATION_URI_BASE = "http://entities.mpiwg-berlin.mpg.de/annotations/";
44
45        public AnnotationStore(GraphDatabaseService graphDb) {
46                super();
47                this.graphDb = graphDb;
48                nodeIndexes = new ArrayList<Index<Node>>(3);
49                // List.set(enum.ordinal(), val) seems not to work.
50                nodeIndexes.add(NodeTypes.ANNOTATION.ordinal(), graphDb.index().forNodes("annotations"));
51                nodeIndexes.add(NodeTypes.PERSON.ordinal(), graphDb.index().forNodes("persons"));
52                nodeIndexes.add(NodeTypes.TARGET.ordinal(), graphDb.index().forNodes("targets"));
53        }
54
55        protected Index<Node> getNodeIndex(NodeTypes type) {
56                return nodeIndexes.get(type.ordinal());
57        }
58       
59        /**
60         * Returns the Annotation with the given id.
61         *
62         * @param id
63         * @return
64         */
65        public Annotation getAnnotationById(String id) {
66                Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id).getSingle();
67                Annotation annot = createAnnotation(annotNode);
68                return annot;
69        }
70
71        /**
72         * Returns an Annotation object from an annotation-Node.
73         *
74         * @param annotNode
75         * @return
76         */
77        public Annotation createAnnotation(Node annotNode) {
78                Annotation annot = new Annotation();
79                annot.setUri((String) annotNode.getProperty("id", null));
80                annot.setBodyText((String) annotNode.getProperty("bodyText", null));
81                annot.setBodyUri((String) annotNode.getProperty("bodyUri", null));
82                // get annotation target from relation
83                Iterable<Relationship> targetRels = annotNode
84                                .getRelationships(RelationTypes.ANNOTATES);
85                for (Relationship targetRel : targetRels) {
86                        Node target = targetRel.getEndNode();
87                        annot.setTargetBaseUri((String) target.getProperty("uri", null));
88                        // just the first one
89                        break;
90                }
91                annot.setTargetFragment((String) annotNode.getProperty(
92                                "targetFragment", null));
93                String ft = (String) annotNode.getProperty("fragmentType", null);
94                if (ft != null) {
95                        annot.setFragmentType(FragmentTypes.valueOf(ft));
96                }
97                // get creator form relation
98                Iterable<Relationship> creatorRels = annotNode
99                                .getRelationships(RelationTypes.CREATED);
100                for (Relationship creatorRel : creatorRels) {
101                        Node creator = creatorRel.getStartNode();
102                        annot.setCreatorUri((String) creator.getProperty("uri", null));
103                        annot.setCreatorName((String) creator.getProperty("name", null));
104                        // just the first one
105                        break;
106                }
107                annot.setCreated((String) annotNode.getProperty("created", null));
108                return annot;
109        }
110
111        /**
112         * Store a new annotation in the store or update an existing one. Returns
113         * the stored annotation.
114         *
115         * @param annot
116         * @return
117         */
118        public Annotation storeAnnotation(Annotation annot) {
119                Node annotNode = null;
120                Transaction tx = graphDb.beginTx();
121                try {
122                        /*
123                         * create or get the annotation
124                         */
125                        String id = annot.getUri();
126                        if (id == null) {
127                                id = createRessourceURI("annot:");
128                        }
129                        annotNode = getOrCreateAnnotationNode(id);
130
131                        /*
132                         * the annotation body
133                         */
134                        String bodyText = annot.getBodyText();
135                        if (bodyText != null) {
136                                annotNode.setProperty("bodyText", bodyText);
137                        }
138                        String bodyUri = annot.getBodyUri();
139                        if (bodyUri != null) {
140                                annotNode.setProperty("bodyUri", bodyUri);
141                        }
142
143                        /*
144                         * the annotation target
145                         */
146                        String targetBaseUri = annot.getTargetBaseUri();
147                        if (targetBaseUri != null) {
148                                Node target = getOrCreateTargetNode(targetBaseUri);
149                                getOrCreateRelation(annotNode, RelationTypes.ANNOTATES, target);
150                        }
151
152                        /*
153                         * The fragment part of the annotation target.
154                         */
155                        String targetFragment = annot.getTargetFragment();
156                        FragmentTypes fragmentType = annot.getFragmentType();
157                        if (targetFragment != null) {
158                                annotNode.setProperty("targetFragment", targetFragment);
159                                annotNode.setProperty("fragmentType", fragmentType.name());
160                        }
161
162                        /*
163                         * The name of the creator of this annotation.
164                         */
165                        String creatorName = annot.getCreatorName();
166
167                        /*
168                         * The URI of the creator of this annotation.
169                         */
170                        String creatorUri = annot.getCreatorUri();
171                        if (creatorUri != null) {
172                                Node creator = getOrCreatePersonNode(creatorUri, creatorName);
173                                getOrCreateRelation(creator, RelationTypes.CREATED, annotNode);
174                        }
175
176                        /*
177                         * The creation date of this annotation.
178                         */
179                        String created = annot.getCreated();
180                        if (created != null) {
181                                annotNode.setProperty("created", created);
182                        }
183
184                        tx.success();
185                } finally {
186                        tx.finish();
187                }
188
189                // re-read and return annotation
190                Annotation storedAnnot = createAnnotation(annotNode);
191                return storedAnnot;
192        }
193
194        /**
195         * Deletes the annotation with the given id.
196         *
197         * @param id
198         */
199        public void deleteById(String id) {
200                Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id).getSingle();
201                if (annotNode != null) {
202                        // delete related objects
203                        Transaction tx = graphDb.beginTx();
204                        try {
205                                for (Relationship rel : annotNode.getRelationships()) {
206                                        // delete relation and the related node if it has no other relations
207                                        Node other = rel.getOtherNode(annotNode);                                       
208                                        rel.delete();
209                                        if (! other.hasRelationship()) {
210                                                deleteNode(other);
211                                        }
212                                }
213                                if (! annotNode.hasRelationship()) {
214                                        deleteNode(annotNode);
215                                } else {
216                                        logger.error("deleteById: unable to delete: Node still has relations.");
217                                }
218                                tx.success();
219                        } finally {
220                                tx.finish();
221                        }
222                }
223
224        }
225
226        /**
227         * Returns all annotations with the given uri and/or user.
228         *
229         * @param uri
230         * @param userUri
231         * @param limit
232         * @param offset
233         * @return
234         */
235        public List<Annotation> searchByUriUser(String targetUri, String userUri,
236                        String limit, String offset) {
237                List<Annotation> annotations = new ArrayList<Annotation>();
238                if (targetUri != null) {
239                        // there should be only one
240                        Node target = getNodeIndex(NodeTypes.TARGET).get("uri", targetUri).getSingle();
241                        if (target != null) {
242                                Iterable<Relationship> relations = target
243                                                .getRelationships(RelationTypes.ANNOTATES);
244                                for (Relationship relation : relations) {
245                                        Node ann = relation.getStartNode();
246                                        if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
247                                                Annotation annot = createAnnotation(ann);
248                                                annotations.add(annot);
249                                        } else {
250                                                logger.error("ANNOTATES relation does not start with ANNOTATION: "
251                                                                + ann);
252                                        }
253                                }
254                        }
255                }
256                if (userUri != null) {
257                        // there should be only one
258                        Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri).getSingle();
259                        if (person != null) {
260                                Iterable<Relationship> relations = person
261                                                .getRelationships(RelationTypes.CREATED);
262                                for (Relationship relation : relations) {
263                                        Node ann = relation.getEndNode();
264                                        if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
265                                                Annotation annot = createAnnotation(ann);
266                                                annotations.add(annot);
267                                        } else {
268                                                logger.error("CREATED relation does not end with ANNOTATION: "
269                                                                + ann);
270                                        }
271                                }
272                        }
273                }
274                return annotations;
275        }
276
277        protected Relationship getOrCreateRelation(Node start,
278                        RelationshipType type, Node end) {
279                if (start.hasRelationship()) {
280                        // there are relations
281                        Iterable<Relationship> rels = start.getRelationships(type,
282                                        Direction.OUTGOING);
283                        for (Relationship rel : rels) {
284                                if (rel.getEndNode().equals(end)) {
285                                        // relation exists
286                                        return rel;
287                                }
288                        }
289                }
290                // create new one
291                Relationship rel;
292                Transaction tx = graphDb.beginTx();
293                try {
294                        rel = start.createRelationshipTo(end, type);
295                        tx.success();
296                } finally {
297                        tx.finish();
298                }
299                return rel;
300        }
301
302        protected Node getOrCreateAnnotationNode(String id) {
303                Index<Node> idx = getNodeIndex(NodeTypes.ANNOTATION);
304                IndexHits<Node> annotations = idx.get("id", id);
305                Node annotation = annotations.getSingle();
306                if (annotation == null) {
307                        // does not exist yet
308                        Transaction tx = graphDb.beginTx();
309                        try {
310                                annotation = graphDb.createNode();
311                                annotation.setProperty("TYPE", NodeTypes.ANNOTATION.name());
312                                annotation.setProperty("id", id);
313                                idx.add(annotation, "id", id);
314                                tx.success();
315                        } finally {
316                                tx.finish();
317                        }
318                }
319                return annotation;
320        }
321
322        protected Node getOrCreateTargetNode(String uri) {
323                Index<Node> idx = getNodeIndex(NodeTypes.TARGET);
324                IndexHits<Node> targets = idx.get("uri", uri);
325                Node target = targets.getSingle();
326                if (target == null) {
327                        // does not exist yet
328                        Transaction tx = graphDb.beginTx();
329                        try {
330                                target = graphDb.createNode();
331                                target.setProperty("TYPE", NodeTypes.TARGET.name());
332                                target.setProperty("uri", uri);
333                                idx.add(target, "uri", uri);
334                                tx.success();
335                        } finally {
336                                tx.finish();
337                        }
338                }
339                return target;
340        }
341
342        protected Node getOrCreatePersonNode(String uri, String name) {
343                // Person is identified by URI
344                Index<Node> idx = getNodeIndex(NodeTypes.PERSON);
345                IndexHits<Node> persons = idx.get("uri", uri);
346                Node person = persons.getSingle();
347                if (person == null) {
348                        // does not exist yet
349                        Transaction tx = graphDb.beginTx();
350                        try {
351                                person = graphDb.createNode();
352                                person.setProperty("TYPE", NodeTypes.PERSON.name());
353                                person.setProperty("uri", uri);
354                                idx.add(person, "uri", uri);
355                                if (name != null) {
356                                        person.setProperty("name", name);
357                                }
358                                tx.success();
359                        } finally {
360                                tx.finish();
361                        }
362                }
363                return person;
364        }
365
366        /**
367         * Unindexes and deletes given Node if it has no relations.
368         * @param node
369         */
370        protected void deleteNode(Node node) {
371                Transaction tx = graphDb.beginTx();
372                try {
373                        if (node.hasRelationship()) {
374                                logger.error("deleteNode: unable to delete: Node still has relations.");
375                        } else {
376                                String ts = (String) node.getProperty("TYPE", null);
377                                try {
378                                        NodeTypes type = NodeTypes.valueOf(ts);
379                                        getNodeIndex(type).remove(node);
380                                } catch (Exception e) {
381                                        logger.error("deleteNode: unable to get TYPE of node: "+node);
382                                }
383                                node.delete();
384                        }
385                        tx.success();
386                } finally {
387                        tx.finish();
388                }
389        }
390       
391        /**
392         * Erzeuge eine urn aus der aktuellen Zeit in millis
393         *
394         * @return
395         */
396        private String createRessourceURI(String prefix) {
397
398                Calendar cal = Calendar.getInstance();
399
400                long time = cal.getTimeInMillis();
401
402                return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time);
403
404        }
405
406}
Note: See TracBrowser for help on using the repository browser.