source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 11:bc90aaeb925d

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

permissions still under construction.

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