source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 36:0fdb05f35139

Last change on this file since 36:0fdb05f35139 was 36:0fdb05f35139, checked in by casties, 12 years ago

new node type "resource" for base documents (sans page number).

File size: 32.1 KB
Line 
1/**
2 *
3 */
4package de.mpiwg.itgroup.annotations.neo4j;
5
6import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.Calendar;
9import java.util.HashSet;
10import java.util.List;
11import java.util.Set;
12
13import org.apache.log4j.Logger;
14import org.neo4j.graphdb.Direction;
15import org.neo4j.graphdb.GraphDatabaseService;
16import org.neo4j.graphdb.Node;
17import org.neo4j.graphdb.Relationship;
18import org.neo4j.graphdb.RelationshipType;
19import org.neo4j.graphdb.Transaction;
20import org.neo4j.graphdb.index.Index;
21import org.neo4j.graphdb.index.IndexHits;
22
23import de.mpiwg.itgroup.annotations.Actor;
24import de.mpiwg.itgroup.annotations.Annotation;
25import de.mpiwg.itgroup.annotations.Annotation.FragmentTypes;
26import de.mpiwg.itgroup.annotations.Group;
27import de.mpiwg.itgroup.annotations.Person;
28import de.mpiwg.itgroup.annotations.Tag;
29
30/**
31 * Neo4J based Annotation store.
32 *
33 * @author casties
34 *
35 */
36public class AnnotationStore {
37
38    protected static Logger logger = Logger.getLogger(AnnotationStore.class);
39
40    protected GraphDatabaseService graphDb;
41
42    public static enum NodeTypes {
43        ANNOTATION, PERSON, TARGET, GROUP, TAG, RESOURCE
44    }
45
46    // types of nodes that should not be automatically deleted.
47    public Set<String> permanentNodeTypes = new HashSet<String>(Arrays.asList("PERSON", "GROUP", "TAG"));
48
49    protected List<Index<Node>> nodeIndexes;
50
51    public static enum RelationTypes implements RelationshipType {
52        ANNOTATES, CREATED, PERMITS_ADMIN, PERMITS_DELETE, PERMITS_UPDATE, PERMITS_READ, MEMBER_OF, HAS_TAG, PART_OF
53    }
54
55    public static String ANNOTATION_URI_BASE = "http://entities.mpiwg-berlin.mpg.de/annotations/";
56
57    public AnnotationStore(GraphDatabaseService graphDb) {
58        super();
59        this.graphDb = graphDb;
60        nodeIndexes = new ArrayList<Index<Node>>(5);
61        // List.set(enum.ordinal(), val) seems not to work.
62        nodeIndexes.add(NodeTypes.ANNOTATION.ordinal(), graphDb.index().forNodes("annotations"));
63        nodeIndexes.add(NodeTypes.PERSON.ordinal(), graphDb.index().forNodes("persons"));
64        nodeIndexes.add(NodeTypes.TARGET.ordinal(), graphDb.index().forNodes("targets"));
65        nodeIndexes.add(NodeTypes.GROUP.ordinal(), graphDb.index().forNodes("groups"));
66        nodeIndexes.add(NodeTypes.TAG.ordinal(), graphDb.index().forNodes("tags"));
67        nodeIndexes.add(NodeTypes.RESOURCE.ordinal(), graphDb.index().forNodes("resources"));
68    }
69
70    protected Index<Node> getNodeIndex(NodeTypes type) {
71        return nodeIndexes.get(type.ordinal());
72    }
73
74    /**
75     * @param userUri
76     * @return
77     */
78    public Node getPersonNodeByUri(String userUri) {
79        if (userUri == null) return null;
80        Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri).getSingle();
81        return person;
82    }
83
84    /**
85     * @param tagUri
86     * @return
87     */
88    public Node getTagNodeByUri(String tagUri) {
89        if (tagUri == null) return null;
90        Node person = getNodeIndex(NodeTypes.TAG).get("uri", tagUri).getSingle();
91        return person;
92    }
93
94    public List<Actor> getActors(String key, String query, NodeTypes type) {
95        ArrayList<Actor> actors = new ArrayList<Actor>();
96        Index<Node> idx = getNodeIndex(type);
97        if (key == null) {
98            key = "uri";
99            query = "*";
100        }
101        IndexHits<Node> actorNodes = idx.query(key, query);
102        for (Node actorNode : actorNodes) {
103            Actor actor = createActorFromNode(actorNode);
104            actors.add(actor);
105        }
106        return actors;
107    }
108
109    /**
110     * Returns List of Groups.
111     * Key has to be indexed.
112     *
113     * @param key
114     * @param query
115     * @return
116     */
117    public List<Group> getGroups(String key, String query) {
118        ArrayList<Group> groups = new ArrayList<Group>();
119        Index<Node> idx = getNodeIndex(NodeTypes.GROUP);
120        if (key == null) {
121            key = "uri";
122            query = "*";
123        }
124        IndexHits<Node> groupNodes = idx.query(key, query);
125        for (Node groupNode : groupNodes) {
126            Actor group = createActorFromNode(groupNode);
127            groups.add((Group) group);
128        }
129        return groups;
130    }
131
132    /**
133     * Returns List of Annotations.
134     * Key has to be indexed.
135     *
136     * @param key
137     * @param query
138     * @return
139     */
140    public List<Annotation> getAnnotations(String key, String query) {
141        ArrayList<Annotation> annotations = new ArrayList<Annotation>();
142        Index<Node> idx = getNodeIndex(NodeTypes.ANNOTATION);
143        if (key == null) {
144            key = "id";
145            query = "*";
146        }
147        IndexHits<Node> annotNodes = idx.query(key, query);
148        for (Node annotNode : annotNodes) {
149            Annotation annotation = createAnnotationFromNode(annotNode);
150            annotations.add(annotation);
151        }
152        return annotations;
153    }
154
155 
156   
157    /**
158     * Returns List of Tags.
159     * Key has to be indexed.
160     *
161     * @param key
162     * @param query
163     * @return
164     */
165    public List<Tag> getTags(String key, String query) {
166        ArrayList<Tag> tags = new ArrayList<Tag>();
167        Index<Node> idx = getNodeIndex(NodeTypes.TAG);
168        if (key == null) {
169            key = "uri";
170            query = "*";
171        }
172        IndexHits<Node> groupNodes = idx.query(key, query);
173        for (Node groupNode : groupNodes) {
174            Tag tag = createTagFromNode(groupNode);
175            tags.add(tag);
176        }
177        return tags;
178    }
179
180    /**
181     * Returns List of Groups the person is member of.
182     *
183     * @param person
184     * @return
185     */
186    public List<Group> getGroupsForPersonNode(Node person) {
187        ArrayList<Group> groups = new ArrayList<Group>();
188        Iterable<Relationship> rels = person.getRelationships(RelationTypes.MEMBER_OF);
189        for (Relationship rel : rels) {
190            Node groupNode = rel.getEndNode();
191            Actor group = createActorFromNode(groupNode);
192            // make sure we're getting a group
193            if (!(group instanceof Group)) {
194                logger.error("target of MEMBER_OF is not GROUP! rel=" + rel);
195                continue;
196            }
197            groups.add((Group) group);
198        }
199        return groups;
200    }
201
202    /**
203     * Returns if person with uri is in Group group.
204     *
205     * @param person
206     * @param group
207     * @return
208     */
209    public boolean isPersonInGroup(Person person, Group group) {
210        Node pn = getPersonNodeByUri(person.getUriString());
211        if (pn == null) return false;
212        // optimized version of getGroupsForPersonNode
213        Iterable<Relationship> rels = pn.getRelationships(RelationTypes.MEMBER_OF);
214        for (Relationship rel : rels) {
215            Node gn = rel.getEndNode();
216            if (gn.getProperty("uri", "").equals(group.getUriString()) || gn.getProperty("id", "").equals(group.getId())) {
217                return true;
218            }
219        }
220        return false;
221    }
222
223    /**
224     * Returns the members of the group.
225     *
226     * @param group
227     * @return
228     */
229    public List<Person> getMembersOfGroup(Group group) {
230        ArrayList<Person> members = new ArrayList<Person>();
231        Node gn = getActorNode(group);
232        Iterable<Relationship> rels = gn.getRelationships(RelationTypes.MEMBER_OF);
233        for (Relationship rel : rels) {
234            Node memberNode = rel.getStartNode();
235            Actor member = createActorFromNode(memberNode);
236            // make sure we're getting a group
237            if (!(member instanceof Person)) {
238                logger.error("source of MEMBER_OF is not PERSON! rel=" + rel);
239                continue;
240            }
241            members.add((Person) member);
242        }
243        return members;
244    }
245
246    /**
247     * Add Person newMember to Group group.
248     *
249     * @param group
250     * @param member
251     */
252    public Person addGroupMember(Group group, Person member) {
253        Node gn = getActorNode(group);
254        Node pn = getActorNode(member);
255        Person addedMember = null;
256        if (gn != null && pn != null) {
257            getOrCreateRelation(pn, RelationTypes.MEMBER_OF, gn);
258            addedMember = member;
259        }
260        return addedMember;
261    }
262
263    /**
264     * Delete Person oldMember from Group group.
265     *
266     * @param group
267     * @param member
268     */
269    public void deleteGroupMember(Group group, Person member) {
270        Node gn = getActorNode(group);
271        Node pn = getActorNode(member);
272        Iterable<Relationship> rels = gn.getRelationships(RelationTypes.MEMBER_OF);
273        for (Relationship rel : rels) {
274            Node mn = rel.getStartNode();
275            if (mn.equals(pn)) {
276                Transaction tx = graphDb.beginTx();
277                try {
278                    rel.delete();
279                    tx.success();
280                } finally {
281                    tx.finish();
282                }
283                // there should be only one
284                break;
285            }
286        }
287    }
288
289    /**
290     * Returns the stored Actor matching the given one.
291     *
292     * @param actor
293     * @return
294     */
295    public Actor getActor(Actor actor) {
296        Node actorNode = getActorNode(actor);
297        Actor storedActor = createActorFromNode(actorNode);
298        return storedActor;
299    }
300
301    /**
302     * Stores an Actor (Person or Group). Creates a new actor Node or update an
303     * existing one.
304     *
305     * @param actor
306     * @return
307     */
308    public Actor storeActor(Actor actor) {
309        Node actorNode = getOrCreateActorNode(actor);
310        Transaction tx = graphDb.beginTx();
311        try {
312            // id
313            String id = actor.getId();
314            if (id != null) {
315                actorNode.setProperty("id", id);
316            }
317            // name
318            String name = actor.getName();
319            if (name != null) {
320                actorNode.setProperty("name", name);
321            }
322            // uri
323            String uri = actor.getUri();
324            if (uri != null) {
325                actorNode.setProperty("uri", uri);
326            }
327            tx.success();
328        } finally {
329            tx.finish();
330        }
331        Actor storedActor = createActorFromNode(actorNode);
332        return storedActor;
333    }
334
335    /**
336     * Deletes the given Actor.
337     *
338     * @param actor
339     */
340    public void deleteActor(Actor actor) {
341        String uri = actor.getUriString();
342        Index<Node> idx;
343        if (actor.isGroup()) {
344            idx = getNodeIndex(NodeTypes.GROUP);
345        } else {
346            idx = getNodeIndex(NodeTypes.PERSON);
347        }
348        Node actorNode = idx.get("uri", uri).getSingle();
349        if (actorNode != null) {
350            // delete relations
351            Transaction tx = graphDb.beginTx();
352            try {
353                for (Relationship rel : actorNode.getRelationships()) {
354                    rel.delete();
355                }
356                if (!actorNode.hasRelationship()) {
357                    // this shouldn't happen
358                    deleteNode(actorNode);
359                } else {
360                    logger.error("deleteActor: unable to delete: Node still has relations.");
361                }
362                tx.success();
363            } finally {
364                tx.finish();
365            }
366        }
367    }
368
369    /**
370     * Returns the Annotation with the given id.
371     *
372     * @param id
373     * @return
374     */
375    public Annotation getAnnotationById(String id) {
376        Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id).getSingle();
377        Annotation annot = createAnnotationFromNode(annotNode);
378        return annot;
379    }
380
381    /**
382     * Returns an Annotation object from an annotation-Node.
383     *
384     * @param annotNode
385     * @return
386     */
387    public Annotation createAnnotationFromNode(Node annotNode) {
388        Annotation annot = new Annotation();
389        annot.setUri((String) annotNode.getProperty("id", null));
390        annot.setBodyText((String) annotNode.getProperty("bodyText", null));
391        annot.setBodyUri((String) annotNode.getProperty("bodyUri", null));
392        /*
393         * get annotation target from relation
394         */
395        Relationship targetRel = getRelation(annotNode, RelationTypes.ANNOTATES, null);
396        if (targetRel != null) {
397            Node target = targetRel.getEndNode();
398            annot.setTargetBaseUri((String) target.getProperty("uri", null));
399        } else {
400            logger.error("annotation " + annotNode + " has no target node!");
401        }
402        annot.setTargetFragment((String) annotNode.getProperty("targetFragment", null));
403        String ft = (String) annotNode.getProperty("fragmentType", null);
404        if (ft != null) {
405            annot.setFragmentType(FragmentTypes.valueOf(ft));
406        }
407        /*
408         * get creator from relation
409         */
410        Relationship creatorRel = getRelation(annotNode, RelationTypes.CREATED, null);
411        if (creatorRel != null) {
412            Node creatorNode = creatorRel.getStartNode();
413            Actor creator = createActorFromNode(creatorNode);
414            annot.setCreator(creator);
415        } else {
416            logger.error("annotation " + annotNode + " has no creator node!");
417        }
418        /*
419         * get creation date
420         */
421        annot.setCreated((String) annotNode.getProperty("created", null));
422        /*
423         * get permissions
424         */
425        Relationship adminRel = getRelation(annotNode, RelationTypes.PERMITS_ADMIN, null);
426        if (adminRel != null) {
427            Node adminNode = adminRel.getEndNode();
428            Actor admin = createActorFromNode(adminNode);
429            annot.setAdminPermission(admin);
430        }
431        Relationship deleteRel = getRelation(annotNode, RelationTypes.PERMITS_DELETE, null);
432        if (deleteRel != null) {
433            Node deleteNode = deleteRel.getEndNode();
434            Actor delete = createActorFromNode(deleteNode);
435            annot.setDeletePermission(delete);
436        }
437        Relationship updateRel = getRelation(annotNode, RelationTypes.PERMITS_UPDATE, null);
438        if (updateRel != null) {
439            Node updateNode = updateRel.getEndNode();
440            Actor update = createActorFromNode(updateNode);
441            annot.setUpdatePermission(update);
442        }
443        Relationship readRel = getRelation(annotNode, RelationTypes.PERMITS_READ, null);
444        if (readRel != null) {
445            Node readNode = readRel.getEndNode();
446            Actor read = createActorFromNode(readNode);
447            annot.setReadPermission(read);
448        }
449        /*
450         * get tags
451         */
452        Set<String> tags = new HashSet<String>();
453        for (Relationship rel : annotNode.getRelationships(RelationTypes.HAS_TAG)) {
454            String tag = (String) rel.getEndNode().getProperty("name", null);
455            if (tag != null) {
456                tags.add(tag);
457            }
458        }
459        annot.setTags(tags);
460
461        return annot;
462    }
463
464    /**
465     * Returns an Actor object from a node.
466     *
467     * @param actorNode
468     * @return
469     */
470    protected Actor createActorFromNode(Node actorNode) {
471        if (actorNode == null) return null;
472        String id = (String) actorNode.getProperty("id", null);
473        String uri = (String) actorNode.getProperty("uri", null);
474        String name = (String) actorNode.getProperty("name", null);
475        String type = (String) actorNode.getProperty("TYPE", null);
476        if (type != null && type.equals("PERSON")) {
477            return new Person(id, uri, name);
478        } else if (type != null && type.equals("GROUP")) {
479            return new Group(id, uri, name);
480        }
481        return null;
482    }
483
484    public Tag createTagFromNode(Node tagNode) {
485        if (tagNode == null) return null;
486        String name = (String) tagNode.getProperty("name", null);
487        String uri = (String) tagNode.getProperty("uri", null);
488        String id = (String) tagNode.getProperty("id", null);
489
490        return new Tag(id, uri, name);
491
492    }
493
494    /**
495     * Store a new annotation in the store or update an existing one. Returns
496     * the stored annotation.
497     *
498     * @param annot
499     * @return
500     */
501    public Annotation storeAnnotation(Annotation annot) {
502        Node annotNode = null;
503        Transaction tx = graphDb.beginTx();
504        try {
505            /*
506             * create or get the annotation
507             */
508            String id = annot.getUri();
509            if (id == null) {
510                id = createRessourceURI("annot:");
511            }
512            annotNode = getOrCreateAnnotationNode(id);
513
514            /*
515             * the annotation body
516             */
517            String bodyText = annot.getBodyText();
518            if (bodyText != null) {
519                annotNode.setProperty("bodyText", bodyText);
520            }
521            String bodyUri = annot.getBodyUri();
522            if (bodyUri != null) {
523                annotNode.setProperty("bodyUri", bodyUri);
524            }
525
526            /*
527             * the annotation target
528             */
529            String targetBaseUri = annot.getTargetBaseUri();
530            if (targetBaseUri != null) {
531                Node target = getOrCreateTargetNode(targetBaseUri);
532                getOrCreateRelation(annotNode, RelationTypes.ANNOTATES, target);
533            }
534
535            /*
536             * The fragment part of the annotation target.
537             */
538            String targetFragment = annot.getTargetFragment();
539            FragmentTypes fragmentType = annot.getFragmentType();
540            if (targetFragment != null) {
541                annotNode.setProperty("targetFragment", targetFragment);
542                annotNode.setProperty("fragmentType", fragmentType.name());
543            }
544
545            /*
546             * The creator of this annotation.
547             */
548            Actor creator = annot.getCreator();
549            if (creator != null) {
550                Node creatorNode = getOrCreateActorNode(creator);
551                getOrCreateRelation(creatorNode, RelationTypes.CREATED, annotNode);
552            }
553
554            /*
555             * The creation date of this annotation.
556             */
557            String created = annot.getCreated();
558            if (created != null) {
559                annotNode.setProperty("created", created);
560            }
561
562            /*
563             * Permissions for this annotation.
564             */
565            setPermissionRelation(annotNode, RelationTypes.PERMITS_ADMIN, annot.getAdminPermission());
566            setPermissionRelation(annotNode, RelationTypes.PERMITS_DELETE, annot.getDeletePermission());
567            setPermissionRelation(annotNode, RelationTypes.PERMITS_UPDATE, annot.getUpdatePermission());
568            setPermissionRelation(annotNode, RelationTypes.PERMITS_READ, annot.getReadPermission());
569
570            /*
571             * Tags on this annotation.
572             */
573            Set<String> newTags = annot.getTags();
574            // we ignore existing tags if tags == null
575            if (newTags != null) {
576                List<Relationship> oldHasTags = new ArrayList<Relationship>();
577                for (Relationship rel : annotNode.getRelationships(RelationTypes.HAS_TAG)) {
578                    oldHasTags.add(rel);
579                }
580                // adjust to new tags
581                if (newTags.isEmpty()) {
582                    // remove old tags
583                    if (!oldHasTags.isEmpty()) {
584                        for (Relationship rel : oldHasTags) {
585                            rel.delete();
586                            // TODO: should we delete orphan nodes too?
587                        }
588                    }
589                } else {
590                    if (!oldHasTags.isEmpty()) {
591                        // adjust old tags
592                        for (Relationship rel : oldHasTags) {
593                            String oldTag = (String) rel.getEndNode().getProperty("name", null);
594                            if (newTags.contains(oldTag)) {
595                                // tag exists
596                                newTags.remove(oldTag);
597                            } else {
598                                // tag exists no longer
599                                rel.delete();
600                                // TODO: should we delete orphan nodes too?
601                            }
602                        }
603                    }
604                    if (!newTags.isEmpty()) {
605                        // still tags to add
606                        for (String tag : newTags) {
607                            // create new tag
608                            Node tagNode = getOrCreateTagNode(new Tag(null, null, tag));
609                            getOrCreateRelation(annotNode, RelationTypes.HAS_TAG, tagNode);
610                        }
611                    }
612
613                }
614            }
615            tx.success();
616        } finally {
617            tx.finish();
618        }
619
620        // re-read and return annotation
621        Annotation storedAnnot = createAnnotationFromNode(annotNode);
622        return storedAnnot;
623    }
624
625    /**
626     * Deletes the annotation with the given id.
627     *
628     * @param id
629     */
630    public void deleteAnnotationById(String id) {
631        Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id).getSingle();
632        if (annotNode != null) {
633            // delete related objects
634            Transaction tx = graphDb.beginTx();
635            try {
636                for (Relationship rel : annotNode.getRelationships()) {
637                    // delete relation and the related node if it has no other
638                    // relations and is not permanent
639                    Node other = rel.getOtherNode(annotNode);
640                    rel.delete();
641                    if (!(other.hasRelationship() || permanentNodeTypes.contains(other.getProperty("TYPE", null)))) {
642                        deleteNode(other);
643                    }
644                }
645                if (!annotNode.hasRelationship()) {
646                    deleteNode(annotNode);
647                } else {
648                    logger.error("deleteById: unable to delete: Node still has relations.");
649                }
650                tx.success();
651            } finally {
652                tx.finish();
653            }
654        }
655    }
656
657    /**
658     * Returns all annotations with the given uri and/or user.
659     *
660     * @param uri
661     * @param userUri
662     * @param limit
663     * @param offset
664     * @return
665     */
666    public List<Annotation> searchAnnotationByUriUser(String targetUri, String userUri, String limit, String offset) {
667        List<Annotation> annotations = new ArrayList<Annotation>();
668        if (targetUri != null) {
669            // there should be only one
670            Node target = getNodeIndex(NodeTypes.TARGET).get("uri", targetUri).getSingle();
671            if (target != null) {
672                Iterable<Relationship> relations = target.getRelationships(RelationTypes.ANNOTATES);
673                for (Relationship relation : relations) {
674                    Node ann = relation.getStartNode();
675                    if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
676                        Annotation annot = createAnnotationFromNode(ann);
677                        annotations.add(annot);
678                    } else {
679                        logger.error("ANNOTATES relation does not start with ANNOTATION: " + ann);
680                    }
681                }
682            }
683        }
684        if (userUri != null) {
685            // there should be only one
686            Node person = getPersonNodeByUri(userUri);
687            if (person != null) {
688                Iterable<Relationship> relations = person.getRelationships(RelationTypes.CREATED);
689                for (Relationship relation : relations) {
690                    Node ann = relation.getEndNode();
691                    if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
692                        Annotation annot = createAnnotationFromNode(ann);
693                        annotations.add(annot);
694                    } else {
695                        logger.error("CREATED relation does not end with ANNOTATION: " + ann);
696                    }
697                }
698            }
699        }
700        // TODO: if both uri and user are given we should intersect
701        return annotations;
702    }
703
704    /**
705     * Returns Relationship of type from Node start to Node end. Creates one if
706     * it doesn't exist.
707     *
708     * @param start
709     * @param type
710     * @param end
711     * @return
712     */
713    protected Relationship getOrCreateRelation(Node start, RelationshipType type, Node end) {
714        if (start.hasRelationship()) {
715            // there are relations
716            Iterable<Relationship> rels = start.getRelationships(type, Direction.OUTGOING);
717            for (Relationship rel : rels) {
718                if (rel.getEndNode().equals(end)) {
719                    // relation exists
720                    return rel;
721                }
722            }
723        }
724        // create new one
725        Relationship rel;
726        Transaction tx = graphDb.beginTx();
727        try {
728            rel = start.createRelationshipTo(end, type);
729            tx.success();
730        } finally {
731            tx.finish();
732        }
733        return rel;
734    }
735
736    protected Node getOrCreateAnnotationNode(String id) {
737        Index<Node> idx = getNodeIndex(NodeTypes.ANNOTATION);
738        IndexHits<Node> annotations = idx.get("id", id);
739        Node annotation = annotations.getSingle();
740        if (annotation == null) {
741            // does not exist yet
742            Transaction tx = graphDb.beginTx();
743            try {
744                annotation = graphDb.createNode();
745                annotation.setProperty("TYPE", NodeTypes.ANNOTATION.name());
746                annotation.setProperty("id", id);
747                idx.add(annotation, "id", id);
748                tx.success();
749            } finally {
750                tx.finish();
751            }
752        }
753        return annotation;
754    }
755
756    protected Node getOrCreateTargetNode(String uri) {
757        Index<Node> idx = getNodeIndex(NodeTypes.TARGET);
758        IndexHits<Node> targets = idx.get("uri", uri);
759        Node target = targets.getSingle();
760        if (target == null) {
761            // does not exist yet
762            Transaction tx = graphDb.beginTx();
763            try {
764                target = graphDb.createNode();
765                target.setProperty("TYPE", NodeTypes.TARGET.name());
766                target.setProperty("uri", uri);
767                idx.add(target, "uri", uri);
768                tx.success();
769            } finally {
770                tx.finish();
771            }
772        }
773        return target;
774    }
775
776    protected Node getActorNode(Actor actor) {
777        // Person/Group is identified by URI or id
778        String uri = actor.getUriString();
779        Index<Node> idx;
780        if (actor.isGroup()) {
781            idx = getNodeIndex(NodeTypes.GROUP);
782        } else {
783            idx = getNodeIndex(NodeTypes.PERSON);
784        }
785        IndexHits<Node> persons = idx.get("uri", uri);
786        Node person = persons.getSingle();
787        return person;
788    }
789
790    protected Node getOrCreateActorNode(Actor actor) {
791        // Person/Group is identified by URI or id
792        String uri = actor.getUriString();
793        String name = actor.getName();
794        String id = actor.getId();
795        Index<Node> idx;
796        if (actor.isGroup()) {
797            idx = getNodeIndex(NodeTypes.GROUP);
798        } else {
799            idx = getNodeIndex(NodeTypes.PERSON);
800        }
801        IndexHits<Node> persons = idx.get("uri", uri);
802        Node person = persons.getSingle();
803        if (person == null) {
804            // does not exist yet
805            Transaction tx = graphDb.beginTx();
806            try {
807                person = graphDb.createNode();
808                if (actor.isGroup()) {
809                    person.setProperty("TYPE", NodeTypes.GROUP.name());
810                } else {
811                    person.setProperty("TYPE", NodeTypes.PERSON.name());
812                }
813                person.setProperty("uri", uri);
814                idx.add(person, "uri", uri);
815                if (name != null) {
816                    person.setProperty("name", name);
817                }
818                if (id != null) {
819                    person.setProperty("id", id);
820                }
821                tx.success();
822            } finally {
823                tx.finish();
824            }
825        }
826        return person;
827    }
828
829    protected Node getOrCreateTagNode(Tag inTag) {
830        Index<Node> idx = getNodeIndex(NodeTypes.TAG);
831        String tagname = inTag.getName();
832        IndexHits<Node> tags = idx.get("name", tagname);
833        Node tag = tags.getSingle();
834        if (tag == null) {
835            // does not exist yet
836            Transaction tx = graphDb.beginTx();
837            try {
838                tag = graphDb.createNode();
839                tag.setProperty("TYPE", NodeTypes.TAG.name());
840                tag.setProperty("name", tagname);
841                idx.add(tag, "name", tagname);
842
843                tag.setProperty("id", inTag.getId());
844                tag.setProperty("uri", inTag.getUri());
845                idx.add(tag, "uri", inTag.getUri());
846
847                tx.success();
848            } finally {
849                tx.finish();
850            }
851        }
852        return tag;
853    }
854
855    /**
856     * Create or update permissions relations for an annotation.
857     *
858     * @param annotNode
859     * @param type
860     * @param annot
861     */
862    protected void setPermissionRelation(Node annotNode, RelationTypes type, Actor actor) {
863        Node newActorNode = null;
864        if (actor != null) {
865            newActorNode = getOrCreateActorNode(actor);
866        }
867        Relationship rel = getRelation(annotNode, type, null);
868        if (rel != null) {
869            // relation exists
870            Node oldActorNode = rel.getEndNode();
871            if (!oldActorNode.equals(newActorNode)) {
872                // new admin is different
873                Transaction tx = graphDb.beginTx();
874                try {
875                    rel.delete();
876                    tx.success();
877                } finally {
878                    tx.finish();
879                }
880                if (newActorNode != null) {
881                    rel = getOrCreateRelation(annotNode, type, newActorNode);
882                }
883            }
884        } else {
885            // no relation yet
886            if (newActorNode != null) {
887                rel = getOrCreateRelation(annotNode, type, newActorNode);
888            }
889        }
890    }
891
892    /**
893     * Unindexes and deletes given Node if it has no relations.
894     *
895     * @param node
896     */
897    protected void deleteNode(Node node) {
898        Transaction tx = graphDb.beginTx();
899        try {
900            if (node.hasRelationship()) {
901                logger.error("deleteNode: unable to delete: Node still has relations.");
902            } else {
903                String ts = (String) node.getProperty("TYPE", null);
904                try {
905                    NodeTypes type = NodeTypes.valueOf(ts);
906                    getNodeIndex(type).remove(node);
907                } catch (Exception e) {
908                    logger.error("deleteNode: unable to get TYPE of node: " + node);
909                }
910                node.delete();
911            }
912            tx.success();
913        } finally {
914            tx.finish();
915        }
916    }
917
918    /**
919     * returns the (first) Relationship of RelationTypes type from Node start.
920     *
921     * @param start
922     * @param type
923     * @param direction
924     * @return
925     */
926    protected Relationship getRelation(Node start, RelationTypes type, Direction direction) {
927        Iterable<Relationship> rels;
928        if (direction == null) {
929            // ignore direction
930            rels = start.getRelationships(type);
931        } else {
932            rels = start.getRelationships(type, direction);
933        }
934        for (Relationship rel : rels) {
935            // just the first one
936            return rel;
937        }
938        return null;
939    }
940
941    /**
942     * Erzeuge eine urn aus der aktuellen Zeit in millis
943     *
944     * @return
945     */
946    private String createRessourceURI(String prefix) {
947
948        Calendar cal = Calendar.getInstance();
949
950        long time = cal.getTimeInMillis();
951
952        return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time);
953
954    }
955
956    public List<Annotation> getAnnotationsByTag(String tagUri) {
957
958        ArrayList<Annotation> ret = new ArrayList<Annotation>();
959        Node tag = getTagNodeByUri(tagUri);
960
961        Iterable<Relationship> rels = tag.getRelationships(Direction.INCOMING, RelationTypes.HAS_TAG);
962
963        for (Relationship rel : rels) {
964            Node node = rel.getStartNode();
965            ret.add(createAnnotationFromNode(node));
966
967        }
968        return ret;
969    }
970
971}
Note: See TracBrowser for help on using the repository browser.