source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 32:0731c4549065

Last change on this file since 32:0731c4549065 was 32:0731c4549065, checked in by casties, 12 years ago

UI for editing groups and persons works now. (still no authorisation!)

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