source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 42:aa2bb7ac04d9

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

more work on resources and targets.

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