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

Last change on this file since 63:9f8c9611848a was 63:9f8c9611848a, checked in by casties, 11 years ago

fixed bug with new rectangle shapes. added limit, offset and sortBy parameters to annotator/ and annotator/search.

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