source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 8:c3cc6a41dd1c

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

under construction

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, PERMITS
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 = createAnnotationFromNode(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 createAnnotationFromNode(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 = createAnnotationFromNode(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         * Returns all annotations with the given uri and/or user.
227         *
228         * @param uri
229         * @param userUri
230         * @param limit
231         * @param offset
232         * @return
233         */
234        public List<Annotation> searchByUriUser(String targetUri, String userUri,
235                        String limit, String offset) {
236                List<Annotation> annotations = new ArrayList<Annotation>();
237                if (targetUri != null) {
238                        // there should be only one
239                        Node target = getNodeIndex(NodeTypes.TARGET).get("uri", targetUri).getSingle();
240                        if (target != null) {
241                                Iterable<Relationship> relations = target
242                                                .getRelationships(RelationTypes.ANNOTATES);
243                                for (Relationship relation : relations) {
244                                        Node ann = relation.getStartNode();
245                                        if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
246                                                Annotation annot = createAnnotationFromNode(ann);
247                                                annotations.add(annot);
248                                        } else {
249                                                logger.error("ANNOTATES relation does not start with ANNOTATION: "
250                                                                + ann);
251                                        }
252                                }
253                        }
254                }
255                if (userUri != null) {
256                        // there should be only one
257                        Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri).getSingle();
258                        if (person != null) {
259                                Iterable<Relationship> relations = person
260                                                .getRelationships(RelationTypes.CREATED);
261                                for (Relationship relation : relations) {
262                                        Node ann = relation.getEndNode();
263                                        if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
264                                                Annotation annot = createAnnotationFromNode(ann);
265                                                annotations.add(annot);
266                                        } else {
267                                                logger.error("CREATED relation does not end with ANNOTATION: "
268                                                                + ann);
269                                        }
270                                }
271                        }
272                }
273                return annotations;
274        }
275
276        protected Relationship getOrCreateRelation(Node start,
277                        RelationshipType type, Node end) {
278                if (start.hasRelationship()) {
279                        // there are relations
280                        Iterable<Relationship> rels = start.getRelationships(type,
281                                        Direction.OUTGOING);
282                        for (Relationship rel : rels) {
283                                if (rel.getEndNode().equals(end)) {
284                                        // relation exists
285                                        return rel;
286                                }
287                        }
288                }
289                // create new one
290                Relationship rel;
291                Transaction tx = graphDb.beginTx();
292                try {
293                        rel = start.createRelationshipTo(end, type);
294                        tx.success();
295                } finally {
296                        tx.finish();
297                }
298                return rel;
299        }
300
301        protected Node getOrCreateAnnotationNode(String id) {
302                Index<Node> idx = getNodeIndex(NodeTypes.ANNOTATION);
303                IndexHits<Node> annotations = idx.get("id", id);
304                Node annotation = annotations.getSingle();
305                if (annotation == null) {
306                        // does not exist yet
307                        Transaction tx = graphDb.beginTx();
308                        try {
309                                annotation = graphDb.createNode();
310                                annotation.setProperty("TYPE", NodeTypes.ANNOTATION.name());
311                                annotation.setProperty("id", id);
312                                idx.add(annotation, "id", id);
313                                tx.success();
314                        } finally {
315                                tx.finish();
316                        }
317                }
318                return annotation;
319        }
320
321        protected Node getOrCreateTargetNode(String uri) {
322                Index<Node> idx = getNodeIndex(NodeTypes.TARGET);
323                IndexHits<Node> targets = idx.get("uri", uri);
324                Node target = targets.getSingle();
325                if (target == null) {
326                        // does not exist yet
327                        Transaction tx = graphDb.beginTx();
328                        try {
329                                target = graphDb.createNode();
330                                target.setProperty("TYPE", NodeTypes.TARGET.name());
331                                target.setProperty("uri", uri);
332                                idx.add(target, "uri", uri);
333                                tx.success();
334                        } finally {
335                                tx.finish();
336                        }
337                }
338                return target;
339        }
340
341        protected Node getOrCreatePersonNode(String uri, String name) {
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
365        /**
366         * Unindexes and deletes given Node if it has no relations.
367         * @param node
368         */
369        protected void deleteNode(Node node) {
370                Transaction tx = graphDb.beginTx();
371                try {
372                        if (node.hasRelationship()) {
373                                logger.error("deleteNode: unable to delete: Node still has relations.");
374                        } else {
375                                String ts = (String) node.getProperty("TYPE", null);
376                                try {
377                                        NodeTypes type = NodeTypes.valueOf(ts);
378                                        getNodeIndex(type).remove(node);
379                                } catch (Exception e) {
380                                        logger.error("deleteNode: unable to get TYPE of node: "+node);
381                                }
382                                node.delete();
383                        }
384                        tx.success();
385                } finally {
386                        tx.finish();
387                }
388        }
389       
390        /**
391         * Erzeuge eine urn aus der aktuellen Zeit in millis
392         *
393         * @return
394         */
395        private String createRessourceURI(String prefix) {
396
397                Calendar cal = Calendar.getInstance();
398
399                long time = cal.getTimeInMillis();
400
401                return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time);
402
403        }
404
405}
Note: See TracBrowser for help on using the repository browser.