source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 45:707902d468f6

Last change on this file since 45:707902d468f6 was 45:707902d468f6, checked in by casties, 12 years ago

store reads and sends annotations resources now.

File size: 36.8 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    protected <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    protected <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 and resource from relation
485         */
486        for (Relationship rel : annotNode.getRelationships(RelationTypes.ANNOTATES)) {
487            Node target = rel.getEndNode();
488            String type = (String) target.getProperty("TYPE");
489            if (type.equals("TARGET")) {
490                annot.setTargetBaseUri((String) target.getProperty("uri", null));
491            } else if (type.equals("RESOURCE")) {
492                annot.setResourceUri((String) target.getProperty("uri", null));
493            }
494        }
495        if (annot.getTargetBaseUri() == null) {
496            logger.error("annotation " + annotNode + " has no target node!");
497        }
498        // get fragment from attribute
499        annot.setTargetFragment((String) annotNode.getProperty("targetFragment", null));
500        String ft = (String) annotNode.getProperty("fragmentType", null);
501        if (ft != null) {
502            annot.setFragmentType(FragmentTypes.valueOf(ft));
503        }
504        /*
505         * get creator from relation
506         */
507        Relationship creatorRel = getRelation(annotNode, RelationTypes.CREATED, null);
508        if (creatorRel != null) {
509            Node creatorNode = creatorRel.getStartNode();
510            Actor creator = createActorFromNode(creatorNode);
511            annot.setCreator(creator);
512        } else {
513            logger.error("annotation " + annotNode + " has no creator node!");
514        }
515        /*
516         * get creation date
517         */
518        annot.setCreated((String) annotNode.getProperty("created", null));
519        /*
520         * get permissions
521         */
522        Relationship adminRel = getRelation(annotNode, RelationTypes.PERMITS_ADMIN, null);
523        if (adminRel != null) {
524            Node adminNode = adminRel.getEndNode();
525            Actor admin = createActorFromNode(adminNode);
526            annot.setAdminPermission(admin);
527        }
528        Relationship deleteRel = getRelation(annotNode, RelationTypes.PERMITS_DELETE, null);
529        if (deleteRel != null) {
530            Node deleteNode = deleteRel.getEndNode();
531            Actor delete = createActorFromNode(deleteNode);
532            annot.setDeletePermission(delete);
533        }
534        Relationship updateRel = getRelation(annotNode, RelationTypes.PERMITS_UPDATE, null);
535        if (updateRel != null) {
536            Node updateNode = updateRel.getEndNode();
537            Actor update = createActorFromNode(updateNode);
538            annot.setUpdatePermission(update);
539        }
540        Relationship readRel = getRelation(annotNode, RelationTypes.PERMITS_READ, null);
541        if (readRel != null) {
542            Node readNode = readRel.getEndNode();
543            Actor read = createActorFromNode(readNode);
544            annot.setReadPermission(read);
545        }
546        /*
547         * get tags
548         */
549        Set<String> tags = new HashSet<String>();
550        for (Relationship rel : annotNode.getRelationships(RelationTypes.HAS_TAG)) {
551            String tag = (String) rel.getEndNode().getProperty("name", null);
552            if (tag != null) {
553                tags.add(tag);
554            }
555        }
556        annot.setTags(tags);
557
558        return annot;
559    }
560
561    /**
562     * Returns an Actor object from a node.
563     *
564     * @param actorNode
565     * @return
566     */
567    protected Actor createActorFromNode(Node actorNode) {
568        if (actorNode == null) return null;
569        String id = (String) actorNode.getProperty("id", null);
570        String uri = (String) actorNode.getProperty("uri", null);
571        String name = (String) actorNode.getProperty("name", null);
572        String type = (String) actorNode.getProperty("TYPE", null);
573        if (type != null && type.equals("PERSON")) {
574            return new Person(id, uri, name);
575        } else if (type != null && type.equals("GROUP")) {
576            return new Group(id, uri, name);
577        }
578        return null;
579    }
580
581    public Tag createTagFromNode(Node tagNode) {
582        if (tagNode == null) return null;
583        String name = (String) tagNode.getProperty("name", null);
584        String uri = (String) tagNode.getProperty("uri", null);
585        String id = (String) tagNode.getProperty("id", null);
586
587        return new Tag(id, uri, name);
588
589    }
590
591    /**
592     * @param resourceNode
593     * @return
594     */
595    public Resource createResourceFromNode(Node resourceNode) {
596        return (Resource) createUriFromNode(resourceNode);
597    }
598   
599    /**
600     * @param targetNode
601     * @return
602     */
603    public Target createTargetFromNode(Node targetNode) {
604        return (Target) createUriFromNode(targetNode);
605    }
606   
607   
608    protected Uri createUriFromNode(Node uriNode) {
609        if (uriNode == null) return null;
610        String uri = (String) uriNode.getProperty("uri", null);
611        String type = (String) uriNode.getProperty("TYPE", null);
612        if (type != null && type.equals("TARGET")) {
613            return new Target(uri);
614        } else if (type != null && type.equals("RESOURCE")) {
615            return new Resource(uri);
616        }
617        return null;
618    }
619
620    /**
621     * Store a new annotation in the store or update an existing one. Returns
622     * the stored annotation.
623     *
624     * @param annot
625     * @return
626     */
627    public Annotation storeAnnotation(Annotation annot) {
628        Node annotNode = null;
629        Transaction tx = graphDb.beginTx();
630        try {
631            /*
632             * create or get the annotation
633             */
634            String id = annot.getUri();
635            if (id == null) {
636                id = createRessourceURI("annot:");
637            }
638            annotNode = getOrCreateAnnotationNode(id);
639
640            /*
641             * the annotation body
642             */
643            String bodyText = annot.getBodyText();
644            if (bodyText != null) {
645                annotNode.setProperty("bodyText", bodyText);
646            }
647            String bodyUri = annot.getBodyUri();
648            if (bodyUri != null) {
649                annotNode.setProperty("bodyUri", bodyUri);
650            }
651
652            /*
653             * the annotation target
654             */
655            String targetBaseUri = annot.getTargetBaseUri();
656            Node targetNode = null;
657            if (targetBaseUri != null) {
658                targetNode = getOrCreateTargetNode(targetBaseUri, NodeTypes.TARGET);
659                getOrCreateRelation(annotNode, RelationTypes.ANNOTATES, targetNode);
660            }
661
662            /*
663             * The fragment part of the annotation target.
664             */
665            String targetFragment = annot.getTargetFragment();
666            FragmentTypes fragmentType = annot.getFragmentType();
667            if (targetFragment != null) {
668                annotNode.setProperty("targetFragment", targetFragment);
669                annotNode.setProperty("fragmentType", fragmentType.name());
670            }
671
672            /*
673             * the annotation resource
674             */
675            String resourceUri = annot.getResourceUri();
676            if (resourceUri != null) {
677                Node resource = getOrCreateTargetNode(resourceUri, NodeTypes.RESOURCE);
678                getOrCreateRelation(annotNode, RelationTypes.ANNOTATES, resource);
679                getOrCreateRelation(targetNode, RelationTypes.PART_OF, resource);
680            }
681
682            /*
683             * The creator of this annotation.
684             */
685            Actor creator = annot.getCreator();
686            if (creator != null) {
687                Node creatorNode = getOrCreateActorNode(creator);
688                getOrCreateRelation(creatorNode, RelationTypes.CREATED, annotNode);
689            }
690
691            /*
692             * The creation date of this annotation.
693             */
694            String created = annot.getCreated();
695            if (created != null) {
696                annotNode.setProperty("created", created);
697            }
698
699            /*
700             * Permissions for this annotation.
701             */
702            setPermissionRelation(annotNode, RelationTypes.PERMITS_ADMIN, annot.getAdminPermission());
703            setPermissionRelation(annotNode, RelationTypes.PERMITS_DELETE, annot.getDeletePermission());
704            setPermissionRelation(annotNode, RelationTypes.PERMITS_UPDATE, annot.getUpdatePermission());
705            setPermissionRelation(annotNode, RelationTypes.PERMITS_READ, annot.getReadPermission());
706
707            /*
708             * Tags on this annotation.
709             */
710            Set<String> newTags = annot.getTags();
711            // we ignore existing tags if tags == null
712            if (newTags != null) {
713                List<Relationship> oldHasTags = new ArrayList<Relationship>();
714                for (Relationship rel : annotNode.getRelationships(RelationTypes.HAS_TAG)) {
715                    oldHasTags.add(rel);
716                }
717                // adjust to new tags
718                if (newTags.isEmpty()) {
719                    // remove old tags
720                    if (!oldHasTags.isEmpty()) {
721                        for (Relationship rel : oldHasTags) {
722                            rel.delete();
723                            // TODO: should we delete orphan nodes too?
724                        }
725                    }
726                } else {
727                    if (!oldHasTags.isEmpty()) {
728                        // adjust old tags
729                        for (Relationship rel : oldHasTags) {
730                            String oldTag = (String) rel.getEndNode().getProperty("name", null);
731                            if (newTags.contains(oldTag)) {
732                                // tag exists
733                                newTags.remove(oldTag);
734                            } else {
735                                // tag exists no longer
736                                rel.delete();
737                                // TODO: should we delete orphan nodes too?
738                            }
739                        }
740                    }
741                    if (!newTags.isEmpty()) {
742                        // still tags to add
743                        for (String tag : newTags) {
744                            // create new tag
745                            Node tagNode = getOrCreateTagNode(new Tag(null, null, tag));
746                            getOrCreateRelation(annotNode, RelationTypes.HAS_TAG, tagNode);
747                        }
748                    }
749
750                }
751            }
752            tx.success();
753        } finally {
754            tx.finish();
755        }
756
757        // re-read and return annotation
758        Annotation storedAnnot = createAnnotationFromNode(annotNode);
759        return storedAnnot;
760    }
761
762    /**
763     * Deletes the annotation with the given id.
764     *
765     * @param id
766     */
767    public void deleteAnnotationById(String id) {
768        Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id).getSingle();
769        if (annotNode != null) {
770            // delete related objects
771            Transaction tx = graphDb.beginTx();
772            try {
773                for (Relationship rel : annotNode.getRelationships()) {
774                    // delete relation and the related node if it has no other
775                    // relations and is not permanent
776                    Node other = rel.getOtherNode(annotNode);
777                    rel.delete();
778                    if (!(other.hasRelationship() || permanentNodeTypes.contains(other.getProperty("TYPE", null)))) {
779                        deleteNode(other);
780                    }
781                }
782                if (!annotNode.hasRelationship()) {
783                    deleteNode(annotNode);
784                } else {
785                    logger.error("deleteById: unable to delete: Node still has relations.");
786                }
787                tx.success();
788            } finally {
789                tx.finish();
790            }
791        }
792    }
793
794    /**
795     * Returns all annotations with the given uri and/or user.
796     *
797     * @param uri
798     * @param userUri
799     * @param limit
800     * @param offset
801     * @return
802     */
803    public List<Annotation> searchAnnotationByUriUser(String targetUri, String userUri, String limit, String offset) {
804        List<Annotation> annotations = new ArrayList<Annotation>();
805        if (targetUri != null) {
806            // there should be only one
807            Node target = getNodeIndex(NodeTypes.TARGET).get("uri", targetUri).getSingle();
808            if (target != null) {
809                Iterable<Relationship> relations = target.getRelationships(RelationTypes.ANNOTATES);
810                for (Relationship relation : relations) {
811                    Node ann = relation.getStartNode();
812                    if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
813                        Annotation annot = createAnnotationFromNode(ann);
814                        annotations.add(annot);
815                    } else {
816                        logger.error("ANNOTATES relation does not start with ANNOTATION: " + ann);
817                    }
818                }
819            }
820        }
821        if (userUri != null) {
822            // there should be only one
823            Node person = getPersonNodeByUri(userUri);
824            if (person != null) {
825                Iterable<Relationship> relations = person.getRelationships(RelationTypes.CREATED);
826                for (Relationship relation : relations) {
827                    Node ann = relation.getEndNode();
828                    if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
829                        Annotation annot = createAnnotationFromNode(ann);
830                        annotations.add(annot);
831                    } else {
832                        logger.error("CREATED relation does not end with ANNOTATION: " + ann);
833                    }
834                }
835            }
836        }
837        // TODO: if both uri and user are given we should intersect
838        return annotations;
839    }
840
841    /**
842     * Returns Relationship of type from Node start to Node end. Creates one if
843     * it doesn't exist.
844     *
845     * @param start
846     * @param type
847     * @param end
848     * @return
849     */
850    protected Relationship getOrCreateRelation(Node start, RelationshipType type, Node end) {
851        if (start == null || end == null) return null;
852        if (start.hasRelationship()) {
853            // there are relations
854            Iterable<Relationship> rels = start.getRelationships(type, Direction.OUTGOING);
855            for (Relationship rel : rels) {
856                if (rel.getEndNode().equals(end)) {
857                    // relation exists
858                    return rel;
859                }
860            }
861        }
862        // create new one
863        Relationship rel;
864        Transaction tx = graphDb.beginTx();
865        try {
866            rel = start.createRelationshipTo(end, type);
867            tx.success();
868        } finally {
869            tx.finish();
870        }
871        return rel;
872    }
873
874    protected Node getOrCreateAnnotationNode(String id) {
875        Index<Node> idx = getNodeIndex(NodeTypes.ANNOTATION);
876        IndexHits<Node> annotations = idx.get("id", id);
877        Node annotation = annotations.getSingle();
878        if (annotation == null) {
879            // does not exist yet
880            Transaction tx = graphDb.beginTx();
881            try {
882                annotation = graphDb.createNode();
883                annotation.setProperty("TYPE", NodeTypes.ANNOTATION.name());
884                annotation.setProperty("id", id);
885                idx.add(annotation, "id", id);
886                tx.success();
887            } finally {
888                tx.finish();
889            }
890        }
891        return annotation;
892    }
893
894    protected Node getOrCreateTargetNode(String uri, NodeTypes type) {
895        Index<Node> idx = getNodeIndex(type);
896        IndexHits<Node> targets = idx.get("uri", uri);
897        Node target = targets.getSingle();
898        if (target == null) {
899            // does not exist yet
900            Transaction tx = graphDb.beginTx();
901            try {
902                target = graphDb.createNode();
903                target.setProperty("TYPE", type.name());
904                target.setProperty("uri", uri);
905                idx.add(target, "uri", uri);
906                tx.success();
907            } finally {
908                tx.finish();
909            }
910        }
911        return target;
912    }
913
914    protected Node getActorNode(Actor actor) {
915        // Person/Group is identified by URI or id
916        String uri = actor.getUriString();
917        Index<Node> idx;
918        if (actor.isGroup()) {
919            idx = getNodeIndex(NodeTypes.GROUP);
920        } else {
921            idx = getNodeIndex(NodeTypes.PERSON);
922        }
923        IndexHits<Node> persons = idx.get("uri", uri);
924        Node person = persons.getSingle();
925        return person;
926    }
927
928    protected Node getOrCreateActorNode(Actor actor) {
929        // Person/Group is identified by URI or id
930        String uri = actor.getUriString();
931        String name = actor.getName();
932        String id = actor.getId();
933        Index<Node> idx;
934        if (actor.isGroup()) {
935            idx = getNodeIndex(NodeTypes.GROUP);
936        } else {
937            idx = getNodeIndex(NodeTypes.PERSON);
938        }
939        IndexHits<Node> persons = idx.get("uri", uri);
940        Node person = persons.getSingle();
941        if (person == null) {
942            // does not exist yet
943            Transaction tx = graphDb.beginTx();
944            try {
945                person = graphDb.createNode();
946                if (actor.isGroup()) {
947                    person.setProperty("TYPE", NodeTypes.GROUP.name());
948                } else {
949                    person.setProperty("TYPE", NodeTypes.PERSON.name());
950                }
951                person.setProperty("uri", uri);
952                idx.add(person, "uri", uri);
953                if (name != null) {
954                    person.setProperty("name", name);
955                }
956                if (id != null) {
957                    person.setProperty("id", id);
958                }
959                tx.success();
960            } finally {
961                tx.finish();
962            }
963        }
964        return person;
965    }
966
967    protected Node getOrCreateTagNode(Tag inTag) {
968        Index<Node> idx = getNodeIndex(NodeTypes.TAG);
969        String tagname = inTag.getName();
970        IndexHits<Node> tags = idx.get("name", tagname);
971        Node tag = tags.getSingle();
972        if (tag == null) {
973            // does not exist yet
974            Transaction tx = graphDb.beginTx();
975            try {
976                tag = graphDb.createNode();
977                tag.setProperty("TYPE", NodeTypes.TAG.name());
978                tag.setProperty("name", tagname);
979                idx.add(tag, "name", tagname);
980
981                tag.setProperty("id", inTag.getId());
982                tag.setProperty("uri", inTag.getUri());
983                idx.add(tag, "uri", inTag.getUri());
984
985                tx.success();
986            } finally {
987                tx.finish();
988            }
989        }
990        return tag;
991    }
992
993    /**
994     * Create or update permissions relations for an annotation.
995     *
996     * @param annotNode
997     * @param type
998     * @param annot
999     */
1000    protected void setPermissionRelation(Node annotNode, RelationTypes type, Actor actor) {
1001        Node newActorNode = null;
1002        if (actor != null) {
1003            newActorNode = getOrCreateActorNode(actor);
1004        }
1005        Relationship rel = getRelation(annotNode, type, null);
1006        if (rel != null) {
1007            // relation exists
1008            Node oldActorNode = rel.getEndNode();
1009            if (!oldActorNode.equals(newActorNode)) {
1010                // new admin is different
1011                Transaction tx = graphDb.beginTx();
1012                try {
1013                    rel.delete();
1014                    tx.success();
1015                } finally {
1016                    tx.finish();
1017                }
1018                if (newActorNode != null) {
1019                    rel = getOrCreateRelation(annotNode, type, newActorNode);
1020                }
1021            }
1022        } else {
1023            // no relation yet
1024            if (newActorNode != null) {
1025                rel = getOrCreateRelation(annotNode, type, newActorNode);
1026            }
1027        }
1028    }
1029
1030    /**
1031     * Unindexes and deletes given Node if it has no relations.
1032     *
1033     * @param node
1034     */
1035    protected void deleteNode(Node node) {
1036        Transaction tx = graphDb.beginTx();
1037        try {
1038            if (node.hasRelationship()) {
1039                logger.error("deleteNode: unable to delete: Node still has relations.");
1040            } else {
1041                String ts = (String) node.getProperty("TYPE", null);
1042                try {
1043                    NodeTypes type = NodeTypes.valueOf(ts);
1044                    getNodeIndex(type).remove(node);
1045                } catch (Exception e) {
1046                    logger.error("deleteNode: unable to get TYPE of node: " + node);
1047                }
1048                node.delete();
1049            }
1050            tx.success();
1051        } finally {
1052            tx.finish();
1053        }
1054    }
1055
1056    /**
1057     * returns the (first) Relationship of RelationTypes type from Node start.
1058     *
1059     * @param start
1060     * @param type
1061     * @param direction
1062     * @return
1063     */
1064    protected Relationship getRelation(Node start, RelationTypes type, Direction direction) {
1065        Iterable<Relationship> rels;
1066        if (direction == null) {
1067            // ignore direction
1068            rels = start.getRelationships(type);
1069        } else {
1070            rels = start.getRelationships(type, direction);
1071        }
1072        for (Relationship rel : rels) {
1073            // just the first one
1074            return rel;
1075        }
1076        return null;
1077    }
1078
1079    /**
1080     * Erzeuge eine urn aus der aktuellen Zeit in millis
1081     *
1082     * @return
1083     */
1084    private String createRessourceURI(String prefix) {
1085
1086        Calendar cal = Calendar.getInstance();
1087
1088        long time = cal.getTimeInMillis();
1089
1090        return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time);
1091
1092    }
1093
1094    public List<Annotation> getAnnotationsByTag(String tagUri) {
1095
1096        ArrayList<Annotation> ret = new ArrayList<Annotation>();
1097        Node tag = getTagNodeByUri(tagUri);
1098
1099        Iterable<Relationship> rels = tag.getRelationships(Direction.INCOMING, RelationTypes.HAS_TAG);
1100
1101        for (Relationship rel : rels) {
1102            Node node = rel.getStartNode();
1103            ret.add(createAnnotationFromNode(node));
1104
1105        }
1106        return ret;
1107    }
1108
1109    public List<Annotation> getAnnotationsByResource(String resourceUri) {
1110        ArrayList<Annotation> ret = new ArrayList<Annotation>();
1111        Node tag = getNodeFromIndex("uri", resourceUri, NodeTypes.RESOURCE);
1112        Iterable<Relationship> rels = tag.getRelationships(Direction.INCOMING, RelationTypes.ANNOTATES);
1113        for (Relationship rel : rels) {
1114            Node an = rel.getStartNode();
1115            Node rn = rel.getEndNode();
1116            if (rn.getProperty("TYPE", "").equals("RESOURCE")) {
1117                logger.error("getAnnotationsByResource got ANNOTATES != RESOURCE");
1118            }
1119            ret.add(createAnnotationFromNode(an));
1120        }
1121        return ret;
1122    }
1123
1124}
Note: See TracBrowser for help on using the repository browser.