source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 9:b2bfc3bc9ba8

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

new internal actor class for creator.

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