source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 34:8427930c5f88

Last change on this file since 34:8427930c5f88 was 34:8427930c5f88, checked in by casties, 12 years ago

Merge with 8ad8596a570af38aacfaecdb68b7e06145624181

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