source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 40:03e0f7574224

Last change on this file since 40:03e0f7574224 was 40:03e0f7574224, checked in by casties, 12 years ago

saving and loading resource targets should work now (no searching yet)

File size: 32.6 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            Node targetNode = null;
531            if (targetBaseUri != null) {
532                targetNode = getOrCreateTargetNode(targetBaseUri, NodeTypes.TARGET);
533                getOrCreateRelation(annotNode, RelationTypes.ANNOTATES, targetNode);
534            }
535
536            /*
537             * The fragment part of the annotation target.
538             */
539            String targetFragment = annot.getTargetFragment();
540            FragmentTypes fragmentType = annot.getFragmentType();
541            if (targetFragment != null) {
542                annotNode.setProperty("targetFragment", targetFragment);
543                annotNode.setProperty("fragmentType", fragmentType.name());
544            }
545
546            /*
547             * the annotation resource
548             */
549            String resourceUri = annot.getResourceUri();
550            if (resourceUri != null) {
551                Node resource = getOrCreateTargetNode(resourceUri, NodeTypes.RESOURCE);
552                getOrCreateRelation(annotNode, RelationTypes.ANNOTATES, resource);
553                getOrCreateRelation(targetNode, RelationTypes.PART_OF, resource);
554            }
555
556            /*
557             * The creator of this annotation.
558             */
559            Actor creator = annot.getCreator();
560            if (creator != null) {
561                Node creatorNode = getOrCreateActorNode(creator);
562                getOrCreateRelation(creatorNode, RelationTypes.CREATED, annotNode);
563            }
564
565            /*
566             * The creation date of this annotation.
567             */
568            String created = annot.getCreated();
569            if (created != null) {
570                annotNode.setProperty("created", created);
571            }
572
573            /*
574             * Permissions for this annotation.
575             */
576            setPermissionRelation(annotNode, RelationTypes.PERMITS_ADMIN, annot.getAdminPermission());
577            setPermissionRelation(annotNode, RelationTypes.PERMITS_DELETE, annot.getDeletePermission());
578            setPermissionRelation(annotNode, RelationTypes.PERMITS_UPDATE, annot.getUpdatePermission());
579            setPermissionRelation(annotNode, RelationTypes.PERMITS_READ, annot.getReadPermission());
580
581            /*
582             * Tags on this annotation.
583             */
584            Set<String> newTags = annot.getTags();
585            // we ignore existing tags if tags == null
586            if (newTags != null) {
587                List<Relationship> oldHasTags = new ArrayList<Relationship>();
588                for (Relationship rel : annotNode.getRelationships(RelationTypes.HAS_TAG)) {
589                    oldHasTags.add(rel);
590                }
591                // adjust to new tags
592                if (newTags.isEmpty()) {
593                    // remove old tags
594                    if (!oldHasTags.isEmpty()) {
595                        for (Relationship rel : oldHasTags) {
596                            rel.delete();
597                            // TODO: should we delete orphan nodes too?
598                        }
599                    }
600                } else {
601                    if (!oldHasTags.isEmpty()) {
602                        // adjust old tags
603                        for (Relationship rel : oldHasTags) {
604                            String oldTag = (String) rel.getEndNode().getProperty("name", null);
605                            if (newTags.contains(oldTag)) {
606                                // tag exists
607                                newTags.remove(oldTag);
608                            } else {
609                                // tag exists no longer
610                                rel.delete();
611                                // TODO: should we delete orphan nodes too?
612                            }
613                        }
614                    }
615                    if (!newTags.isEmpty()) {
616                        // still tags to add
617                        for (String tag : newTags) {
618                            // create new tag
619                            Node tagNode = getOrCreateTagNode(new Tag(null, null, tag));
620                            getOrCreateRelation(annotNode, RelationTypes.HAS_TAG, tagNode);
621                        }
622                    }
623
624                }
625            }
626            tx.success();
627        } finally {
628            tx.finish();
629        }
630
631        // re-read and return annotation
632        Annotation storedAnnot = createAnnotationFromNode(annotNode);
633        return storedAnnot;
634    }
635
636    /**
637     * Deletes the annotation with the given id.
638     *
639     * @param id
640     */
641    public void deleteAnnotationById(String id) {
642        Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id).getSingle();
643        if (annotNode != null) {
644            // delete related objects
645            Transaction tx = graphDb.beginTx();
646            try {
647                for (Relationship rel : annotNode.getRelationships()) {
648                    // delete relation and the related node if it has no other
649                    // relations and is not permanent
650                    Node other = rel.getOtherNode(annotNode);
651                    rel.delete();
652                    if (!(other.hasRelationship() || permanentNodeTypes.contains(other.getProperty("TYPE", null)))) {
653                        deleteNode(other);
654                    }
655                }
656                if (!annotNode.hasRelationship()) {
657                    deleteNode(annotNode);
658                } else {
659                    logger.error("deleteById: unable to delete: Node still has relations.");
660                }
661                tx.success();
662            } finally {
663                tx.finish();
664            }
665        }
666    }
667
668    /**
669     * Returns all annotations with the given uri and/or user.
670     *
671     * @param uri
672     * @param userUri
673     * @param limit
674     * @param offset
675     * @return
676     */
677    public List<Annotation> searchAnnotationByUriUser(String targetUri, String userUri, String limit, String offset) {
678        List<Annotation> annotations = new ArrayList<Annotation>();
679        if (targetUri != null) {
680            // there should be only one
681            Node target = getNodeIndex(NodeTypes.TARGET).get("uri", targetUri).getSingle();
682            if (target != null) {
683                Iterable<Relationship> relations = target.getRelationships(RelationTypes.ANNOTATES);
684                for (Relationship relation : relations) {
685                    Node ann = relation.getStartNode();
686                    if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
687                        Annotation annot = createAnnotationFromNode(ann);
688                        annotations.add(annot);
689                    } else {
690                        logger.error("ANNOTATES relation does not start with ANNOTATION: " + ann);
691                    }
692                }
693            }
694        }
695        if (userUri != null) {
696            // there should be only one
697            Node person = getPersonNodeByUri(userUri);
698            if (person != null) {
699                Iterable<Relationship> relations = person.getRelationships(RelationTypes.CREATED);
700                for (Relationship relation : relations) {
701                    Node ann = relation.getEndNode();
702                    if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
703                        Annotation annot = createAnnotationFromNode(ann);
704                        annotations.add(annot);
705                    } else {
706                        logger.error("CREATED relation does not end with ANNOTATION: " + ann);
707                    }
708                }
709            }
710        }
711        // TODO: if both uri and user are given we should intersect
712        return annotations;
713    }
714
715    /**
716     * Returns Relationship of type from Node start to Node end. Creates one if
717     * it doesn't exist.
718     *
719     * @param start
720     * @param type
721     * @param end
722     * @return
723     */
724    protected Relationship getOrCreateRelation(Node start, RelationshipType type, Node end) {
725        if (start == null || end == null) return null;
726        if (start.hasRelationship()) {
727            // there are relations
728            Iterable<Relationship> rels = start.getRelationships(type, Direction.OUTGOING);
729            for (Relationship rel : rels) {
730                if (rel.getEndNode().equals(end)) {
731                    // relation exists
732                    return rel;
733                }
734            }
735        }
736        // create new one
737        Relationship rel;
738        Transaction tx = graphDb.beginTx();
739        try {
740            rel = start.createRelationshipTo(end, type);
741            tx.success();
742        } finally {
743            tx.finish();
744        }
745        return rel;
746    }
747
748    protected Node getOrCreateAnnotationNode(String id) {
749        Index<Node> idx = getNodeIndex(NodeTypes.ANNOTATION);
750        IndexHits<Node> annotations = idx.get("id", id);
751        Node annotation = annotations.getSingle();
752        if (annotation == null) {
753            // does not exist yet
754            Transaction tx = graphDb.beginTx();
755            try {
756                annotation = graphDb.createNode();
757                annotation.setProperty("TYPE", NodeTypes.ANNOTATION.name());
758                annotation.setProperty("id", id);
759                idx.add(annotation, "id", id);
760                tx.success();
761            } finally {
762                tx.finish();
763            }
764        }
765        return annotation;
766    }
767
768    protected Node getOrCreateTargetNode(String uri, NodeTypes type) {
769        Index<Node> idx = getNodeIndex(type);
770        IndexHits<Node> targets = idx.get("uri", uri);
771        Node target = targets.getSingle();
772        if (target == null) {
773            // does not exist yet
774            Transaction tx = graphDb.beginTx();
775            try {
776                target = graphDb.createNode();
777                target.setProperty("TYPE", type.name());
778                target.setProperty("uri", uri);
779                idx.add(target, "uri", uri);
780                tx.success();
781            } finally {
782                tx.finish();
783            }
784        }
785        return target;
786    }
787
788    protected Node getActorNode(Actor actor) {
789        // Person/Group is identified by URI or id
790        String uri = actor.getUriString();
791        Index<Node> idx;
792        if (actor.isGroup()) {
793            idx = getNodeIndex(NodeTypes.GROUP);
794        } else {
795            idx = getNodeIndex(NodeTypes.PERSON);
796        }
797        IndexHits<Node> persons = idx.get("uri", uri);
798        Node person = persons.getSingle();
799        return person;
800    }
801
802    protected Node getOrCreateActorNode(Actor actor) {
803        // Person/Group is identified by URI or id
804        String uri = actor.getUriString();
805        String name = actor.getName();
806        String id = actor.getId();
807        Index<Node> idx;
808        if (actor.isGroup()) {
809            idx = getNodeIndex(NodeTypes.GROUP);
810        } else {
811            idx = getNodeIndex(NodeTypes.PERSON);
812        }
813        IndexHits<Node> persons = idx.get("uri", uri);
814        Node person = persons.getSingle();
815        if (person == null) {
816            // does not exist yet
817            Transaction tx = graphDb.beginTx();
818            try {
819                person = graphDb.createNode();
820                if (actor.isGroup()) {
821                    person.setProperty("TYPE", NodeTypes.GROUP.name());
822                } else {
823                    person.setProperty("TYPE", NodeTypes.PERSON.name());
824                }
825                person.setProperty("uri", uri);
826                idx.add(person, "uri", uri);
827                if (name != null) {
828                    person.setProperty("name", name);
829                }
830                if (id != null) {
831                    person.setProperty("id", id);
832                }
833                tx.success();
834            } finally {
835                tx.finish();
836            }
837        }
838        return person;
839    }
840
841    protected Node getOrCreateTagNode(Tag inTag) {
842        Index<Node> idx = getNodeIndex(NodeTypes.TAG);
843        String tagname = inTag.getName();
844        IndexHits<Node> tags = idx.get("name", tagname);
845        Node tag = tags.getSingle();
846        if (tag == null) {
847            // does not exist yet
848            Transaction tx = graphDb.beginTx();
849            try {
850                tag = graphDb.createNode();
851                tag.setProperty("TYPE", NodeTypes.TAG.name());
852                tag.setProperty("name", tagname);
853                idx.add(tag, "name", tagname);
854
855                tag.setProperty("id", inTag.getId());
856                tag.setProperty("uri", inTag.getUri());
857                idx.add(tag, "uri", inTag.getUri());
858
859                tx.success();
860            } finally {
861                tx.finish();
862            }
863        }
864        return tag;
865    }
866
867    /**
868     * Create or update permissions relations for an annotation.
869     *
870     * @param annotNode
871     * @param type
872     * @param annot
873     */
874    protected void setPermissionRelation(Node annotNode, RelationTypes type, Actor actor) {
875        Node newActorNode = null;
876        if (actor != null) {
877            newActorNode = getOrCreateActorNode(actor);
878        }
879        Relationship rel = getRelation(annotNode, type, null);
880        if (rel != null) {
881            // relation exists
882            Node oldActorNode = rel.getEndNode();
883            if (!oldActorNode.equals(newActorNode)) {
884                // new admin is different
885                Transaction tx = graphDb.beginTx();
886                try {
887                    rel.delete();
888                    tx.success();
889                } finally {
890                    tx.finish();
891                }
892                if (newActorNode != null) {
893                    rel = getOrCreateRelation(annotNode, type, newActorNode);
894                }
895            }
896        } else {
897            // no relation yet
898            if (newActorNode != null) {
899                rel = getOrCreateRelation(annotNode, type, newActorNode);
900            }
901        }
902    }
903
904    /**
905     * Unindexes and deletes given Node if it has no relations.
906     *
907     * @param node
908     */
909    protected void deleteNode(Node node) {
910        Transaction tx = graphDb.beginTx();
911        try {
912            if (node.hasRelationship()) {
913                logger.error("deleteNode: unable to delete: Node still has relations.");
914            } else {
915                String ts = (String) node.getProperty("TYPE", null);
916                try {
917                    NodeTypes type = NodeTypes.valueOf(ts);
918                    getNodeIndex(type).remove(node);
919                } catch (Exception e) {
920                    logger.error("deleteNode: unable to get TYPE of node: " + node);
921                }
922                node.delete();
923            }
924            tx.success();
925        } finally {
926            tx.finish();
927        }
928    }
929
930    /**
931     * returns the (first) Relationship of RelationTypes type from Node start.
932     *
933     * @param start
934     * @param type
935     * @param direction
936     * @return
937     */
938    protected Relationship getRelation(Node start, RelationTypes type, Direction direction) {
939        Iterable<Relationship> rels;
940        if (direction == null) {
941            // ignore direction
942            rels = start.getRelationships(type);
943        } else {
944            rels = start.getRelationships(type, direction);
945        }
946        for (Relationship rel : rels) {
947            // just the first one
948            return rel;
949        }
950        return null;
951    }
952
953    /**
954     * Erzeuge eine urn aus der aktuellen Zeit in millis
955     *
956     * @return
957     */
958    private String createRessourceURI(String prefix) {
959
960        Calendar cal = Calendar.getInstance();
961
962        long time = cal.getTimeInMillis();
963
964        return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time);
965
966    }
967
968    public List<Annotation> getAnnotationsByTag(String tagUri) {
969
970        ArrayList<Annotation> ret = new ArrayList<Annotation>();
971        Node tag = getTagNodeByUri(tagUri);
972
973        Iterable<Relationship> rels = tag.getRelationships(Direction.INCOMING, RelationTypes.HAS_TAG);
974
975        for (Relationship rel : rels) {
976            Node node = rel.getStartNode();
977            ret.add(createAnnotationFromNode(node));
978
979        }
980        return ret;
981    }
982
983}
Note: See TracBrowser for help on using the repository browser.