source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 10:90911b2da322

Last change on this file since 10:90911b2da322 was 10:90911b2da322, checked in by casties, 12 years ago

more work on permissions...

File size: 10.9 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                        tx.success();
184                } finally {
185                        tx.finish();
186                }
187
188                // re-read and return annotation
189                Annotation storedAnnot = createAnnotationFromNode(annotNode);
190                return storedAnnot;
191        }
192
193        /**
194         * Deletes the annotation with the given id.
195         *
196         * @param id
197         */
198        public void deleteById(String id) {
199                Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id).getSingle();
200                if (annotNode != null) {
201                        // delete related objects
202                        Transaction tx = graphDb.beginTx();
203                        try {
204                                for (Relationship rel : annotNode.getRelationships()) {
205                                        // delete relation and the related node if it has no other relations
206                                        Node other = rel.getOtherNode(annotNode);                                       
207                                        rel.delete();
208                                        if (! other.hasRelationship()) {
209                                                deleteNode(other);
210                                        }
211                                }
212                                if (! annotNode.hasRelationship()) {
213                                        deleteNode(annotNode);
214                                } else {
215                                        logger.error("deleteById: unable to delete: Node still has relations.");
216                                }
217                                tx.success();
218                        } finally {
219                                tx.finish();
220                        }
221                }
222        }
223
224        /**
225         * Returns all annotations with the given uri and/or user.
226         *
227         * @param uri
228         * @param userUri
229         * @param limit
230         * @param offset
231         * @return
232         */
233        public List<Annotation> searchByUriUser(String targetUri, String userUri,
234                        String limit, String offset) {
235                List<Annotation> annotations = new ArrayList<Annotation>();
236                if (targetUri != null) {
237                        // there should be only one
238                        Node target = getNodeIndex(NodeTypes.TARGET).get("uri", targetUri).getSingle();
239                        if (target != null) {
240                                Iterable<Relationship> relations = target
241                                                .getRelationships(RelationTypes.ANNOTATES);
242                                for (Relationship relation : relations) {
243                                        Node ann = relation.getStartNode();
244                                        if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
245                                                Annotation annot = createAnnotationFromNode(ann);
246                                                annotations.add(annot);
247                                        } else {
248                                                logger.error("ANNOTATES relation does not start with ANNOTATION: "
249                                                                + ann);
250                                        }
251                                }
252                        }
253                }
254                if (userUri != null) {
255                        // there should be only one
256                        Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri).getSingle();
257                        if (person != null) {
258                                Iterable<Relationship> relations = person
259                                                .getRelationships(RelationTypes.CREATED);
260                                for (Relationship relation : relations) {
261                                        Node ann = relation.getEndNode();
262                                        if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
263                                                Annotation annot = createAnnotationFromNode(ann);
264                                                annotations.add(annot);
265                                        } else {
266                                                logger.error("CREATED relation does not end with ANNOTATION: "
267                                                                + ann);
268                                        }
269                                }
270                        }
271                }
272                return annotations;
273        }
274
275        protected Relationship getOrCreateRelation(Node start,
276                        RelationshipType type, Node end) {
277                if (start.hasRelationship()) {
278                        // there are relations
279                        Iterable<Relationship> rels = start.getRelationships(type,
280                                        Direction.OUTGOING);
281                        for (Relationship rel : rels) {
282                                if (rel.getEndNode().equals(end)) {
283                                        // relation exists
284                                        return rel;
285                                }
286                        }
287                }
288                // create new one
289                Relationship rel;
290                Transaction tx = graphDb.beginTx();
291                try {
292                        rel = start.createRelationshipTo(end, type);
293                        tx.success();
294                } finally {
295                        tx.finish();
296                }
297                return rel;
298        }
299
300        protected Node getOrCreateAnnotationNode(String id) {
301                Index<Node> idx = getNodeIndex(NodeTypes.ANNOTATION);
302                IndexHits<Node> annotations = idx.get("id", id);
303                Node annotation = annotations.getSingle();
304                if (annotation == null) {
305                        // does not exist yet
306                        Transaction tx = graphDb.beginTx();
307                        try {
308                                annotation = graphDb.createNode();
309                                annotation.setProperty("TYPE", NodeTypes.ANNOTATION.name());
310                                annotation.setProperty("id", id);
311                                idx.add(annotation, "id", id);
312                                tx.success();
313                        } finally {
314                                tx.finish();
315                        }
316                }
317                return annotation;
318        }
319
320        protected Node getOrCreateTargetNode(String uri) {
321                Index<Node> idx = getNodeIndex(NodeTypes.TARGET);
322                IndexHits<Node> targets = idx.get("uri", uri);
323                Node target = targets.getSingle();
324                if (target == null) {
325                        // does not exist yet
326                        Transaction tx = graphDb.beginTx();
327                        try {
328                                target = graphDb.createNode();
329                                target.setProperty("TYPE", NodeTypes.TARGET.name());
330                                target.setProperty("uri", uri);
331                                idx.add(target, "uri", uri);
332                                tx.success();
333                        } finally {
334                                tx.finish();
335                        }
336                }
337                return target;
338        }
339
340        protected Node getOrCreatePersonNode(Actor actor) {
341            /*
342                // Person is identified by URI
343                Index<Node> idx = getNodeIndex(NodeTypes.PERSON);
344                IndexHits<Node> persons = idx.get("uri", uri);
345                Node person = persons.getSingle();
346                if (person == null) {
347                        // does not exist yet
348                        Transaction tx = graphDb.beginTx();
349                        try {
350                                person = graphDb.createNode();
351                                person.setProperty("TYPE", NodeTypes.PERSON.name());
352                                person.setProperty("uri", uri);
353                                idx.add(person, "uri", uri);
354                                if (name != null) {
355                                        person.setProperty("name", name);
356                                }
357                                tx.success();
358                        } finally {
359                                tx.finish();
360                        }
361                }
362                return person;
363                */
364            return null;
365        }
366
367        /**
368         * Unindexes and deletes given Node if it has no relations.
369         * @param node
370         */
371        protected void deleteNode(Node node) {
372                Transaction tx = graphDb.beginTx();
373                try {
374                        if (node.hasRelationship()) {
375                                logger.error("deleteNode: unable to delete: Node still has relations.");
376                        } else {
377                                String ts = (String) node.getProperty("TYPE", null);
378                                try {
379                                        NodeTypes type = NodeTypes.valueOf(ts);
380                                        getNodeIndex(type).remove(node);
381                                } catch (Exception e) {
382                                        logger.error("deleteNode: unable to get TYPE of node: "+node);
383                                }
384                                node.delete();
385                        }
386                        tx.success();
387                } finally {
388                        tx.finish();
389                }
390        }
391       
392        /**
393         * Erzeuge eine urn aus der aktuellen Zeit in millis
394         *
395         * @return
396         */
397        private String createRessourceURI(String prefix) {
398
399                Calendar cal = Calendar.getInstance();
400
401                long time = cal.getTimeInMillis();
402
403                return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time);
404
405        }
406
407}
Note: See TracBrowser for help on using the repository browser.