source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 43:d1bef7952bec

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

more work on resources and targets.

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