Mercurial > hg > AnnotationManagerN4J
comparison src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 16:794077e6288c
CLOSED - # 252: Tags for Annotations
https://it-dev.mpiwg-berlin.mpg.de/tracs/mpdl-project-software/ticket/252
author | casties |
---|---|
date | Tue, 04 Sep 2012 20:02:59 +0200 |
parents | 58357a4b86de |
children | aafa3884b2c4 |
comparison
equal
deleted
inserted
replaced
15:58357a4b86de | 16:794077e6288c |
---|---|
3 */ | 3 */ |
4 package de.mpiwg.itgroup.annotations.neo4j; | 4 package de.mpiwg.itgroup.annotations.neo4j; |
5 | 5 |
6 import java.util.ArrayList; | 6 import java.util.ArrayList; |
7 import java.util.Calendar; | 7 import java.util.Calendar; |
8 import java.util.HashSet; | |
8 import java.util.List; | 9 import java.util.List; |
10 import java.util.Set; | |
9 | 11 |
10 import org.apache.log4j.Logger; | 12 import org.apache.log4j.Logger; |
11 import org.neo4j.graphdb.Direction; | 13 import org.neo4j.graphdb.Direction; |
12 import org.neo4j.graphdb.GraphDatabaseService; | 14 import org.neo4j.graphdb.GraphDatabaseService; |
13 import org.neo4j.graphdb.Node; | 15 import org.neo4j.graphdb.Node; |
32 protected static Logger logger = Logger.getLogger(AnnotationStore.class); | 34 protected static Logger logger = Logger.getLogger(AnnotationStore.class); |
33 | 35 |
34 protected GraphDatabaseService graphDb; | 36 protected GraphDatabaseService graphDb; |
35 | 37 |
36 public static enum NodeTypes { | 38 public static enum NodeTypes { |
37 ANNOTATION, PERSON, TARGET, GROUP | 39 ANNOTATION, PERSON, TARGET, GROUP, TAG |
38 } | 40 } |
39 | 41 |
40 protected List<Index<Node>> nodeIndexes; | 42 protected List<Index<Node>> nodeIndexes; |
41 | 43 |
42 public static enum RelationTypes implements RelationshipType { | 44 public static enum RelationTypes implements RelationshipType { |
43 ANNOTATES, CREATED, PERMITS_ADMIN, PERMITS_DELETE, PERMITS_UPDATE, PERMITS_READ, MEMBER_OF | 45 ANNOTATES, CREATED, PERMITS_ADMIN, PERMITS_DELETE, PERMITS_UPDATE, PERMITS_READ, MEMBER_OF, HAS_TAG |
44 } | 46 } |
45 | 47 |
46 public static String ANNOTATION_URI_BASE = "http://entities.mpiwg-berlin.mpg.de/annotations/"; | 48 public static String ANNOTATION_URI_BASE = "http://entities.mpiwg-berlin.mpg.de/annotations/"; |
47 | 49 |
48 public AnnotationStore(GraphDatabaseService graphDb) { | 50 public AnnotationStore(GraphDatabaseService graphDb) { |
49 super(); | 51 super(); |
50 this.graphDb = graphDb; | 52 this.graphDb = graphDb; |
51 nodeIndexes = new ArrayList<Index<Node>>(3); | 53 nodeIndexes = new ArrayList<Index<Node>>(5); |
52 // List.set(enum.ordinal(), val) seems not to work. | 54 // List.set(enum.ordinal(), val) seems not to work. |
53 nodeIndexes.add(NodeTypes.ANNOTATION.ordinal(), graphDb.index().forNodes("annotations")); | 55 nodeIndexes.add(NodeTypes.ANNOTATION.ordinal(), graphDb.index().forNodes("annotations")); |
54 nodeIndexes.add(NodeTypes.PERSON.ordinal(), graphDb.index().forNodes("persons")); | 56 nodeIndexes.add(NodeTypes.PERSON.ordinal(), graphDb.index().forNodes("persons")); |
55 nodeIndexes.add(NodeTypes.TARGET.ordinal(), graphDb.index().forNodes("targets")); | 57 nodeIndexes.add(NodeTypes.TARGET.ordinal(), graphDb.index().forNodes("targets")); |
56 nodeIndexes.add(NodeTypes.GROUP.ordinal(), graphDb.index().forNodes("groups")); | 58 nodeIndexes.add(NodeTypes.GROUP.ordinal(), graphDb.index().forNodes("groups")); |
59 nodeIndexes.add(NodeTypes.TAG.ordinal(), graphDb.index().forNodes("tags")); | |
57 } | 60 } |
58 | 61 |
59 protected Index<Node> getNodeIndex(NodeTypes type) { | 62 protected Index<Node> getNodeIndex(NodeTypes type) { |
60 return nodeIndexes.get(type.ordinal()); | 63 return nodeIndexes.get(type.ordinal()); |
61 } | 64 } |
68 if (userUri == null) return null; | 71 if (userUri == null) return null; |
69 Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri).getSingle(); | 72 Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri).getSingle(); |
70 return person; | 73 return person; |
71 } | 74 } |
72 | 75 |
73 | |
74 /** | 76 /** |
75 * Returns List of Groups the person is member of. | 77 * Returns List of Groups the person is member of. |
76 * | 78 * |
77 * @param person | 79 * @param person |
78 * @return | 80 * @return |
83 for (Relationship rel : rels) { | 85 for (Relationship rel : rels) { |
84 Node groupNode = rel.getEndNode(); | 86 Node groupNode = rel.getEndNode(); |
85 Actor group = createActorFromNode(groupNode); | 87 Actor group = createActorFromNode(groupNode); |
86 // make sure we're getting a group | 88 // make sure we're getting a group |
87 if (!(group instanceof Group)) { | 89 if (!(group instanceof Group)) { |
88 logger.error("target of MEMBER_OF is not GROUP! rel="+rel); | 90 logger.error("target of MEMBER_OF is not GROUP! rel=" + rel); |
89 continue; | 91 continue; |
90 } | 92 } |
91 groups.add((Group) group); | 93 groups.add((Group) group); |
92 } | 94 } |
93 return groups; | 95 return groups; |
94 } | 96 } |
95 | 97 |
96 /** | 98 /** |
97 * Returns if person with uri is in Group group. | 99 * Returns if person with uri is in Group group. |
98 * | 100 * |
99 * @param person | 101 * @param person |
100 * @param group | 102 * @param group |
101 * @return | 103 * @return |
102 */ | 104 */ |
103 public boolean isPersonInGroup(Person person, Group group) { | 105 public boolean isPersonInGroup(Person person, Group group) { |
104 Node pn = getPersonNodeByUri(person.getUriString()); | 106 Node pn = getPersonNodeByUri(person.getUriString()); |
105 if (pn == null) return false; | 107 if (pn == null) return false; |
106 // optimised version of getGroupsForPersonNode | 108 // optimized version of getGroupsForPersonNode |
107 Iterable<Relationship> rels = pn.getRelationships(RelationTypes.MEMBER_OF); | 109 Iterable<Relationship> rels = pn.getRelationships(RelationTypes.MEMBER_OF); |
108 for (Relationship rel : rels) { | 110 for (Relationship rel : rels) { |
109 Node gn = rel.getEndNode(); | 111 Node gn = rel.getEndNode(); |
110 if (gn.getProperty("uri", "").equals(group.getUriString()) || gn.getProperty("id", "").equals(group.getId())) { | 112 if (gn.getProperty("uri", "").equals(group.getUriString()) || gn.getProperty("id", "").equals(group.getId())) { |
111 return true; | 113 return true; |
112 } | 114 } |
113 } | 115 } |
114 return false; | 116 return false; |
115 } | 117 } |
116 | 118 |
117 /** | 119 /** |
118 * Returns the Annotation with the given id. | 120 * Returns the Annotation with the given id. |
119 * | 121 * |
120 * @param id | 122 * @param id |
121 * @return | 123 * @return |
135 public Annotation createAnnotationFromNode(Node annotNode) { | 137 public Annotation createAnnotationFromNode(Node annotNode) { |
136 Annotation annot = new Annotation(); | 138 Annotation annot = new Annotation(); |
137 annot.setUri((String) annotNode.getProperty("id", null)); | 139 annot.setUri((String) annotNode.getProperty("id", null)); |
138 annot.setBodyText((String) annotNode.getProperty("bodyText", null)); | 140 annot.setBodyText((String) annotNode.getProperty("bodyText", null)); |
139 annot.setBodyUri((String) annotNode.getProperty("bodyUri", null)); | 141 annot.setBodyUri((String) annotNode.getProperty("bodyUri", null)); |
140 // get annotation target from relation | 142 /* |
143 * get annotation target from relation | |
144 */ | |
141 Relationship targetRel = getRelation(annotNode, RelationTypes.ANNOTATES, null); | 145 Relationship targetRel = getRelation(annotNode, RelationTypes.ANNOTATES, null); |
142 if (targetRel != null) { | 146 if (targetRel != null) { |
143 Node target = targetRel.getEndNode(); | 147 Node target = targetRel.getEndNode(); |
144 annot.setTargetBaseUri((String) target.getProperty("uri", null)); | 148 annot.setTargetBaseUri((String) target.getProperty("uri", null)); |
145 } else { | 149 } else { |
148 annot.setTargetFragment((String) annotNode.getProperty("targetFragment", null)); | 152 annot.setTargetFragment((String) annotNode.getProperty("targetFragment", null)); |
149 String ft = (String) annotNode.getProperty("fragmentType", null); | 153 String ft = (String) annotNode.getProperty("fragmentType", null); |
150 if (ft != null) { | 154 if (ft != null) { |
151 annot.setFragmentType(FragmentTypes.valueOf(ft)); | 155 annot.setFragmentType(FragmentTypes.valueOf(ft)); |
152 } | 156 } |
153 // get creator from relation | 157 /* |
158 * get creator from relation | |
159 */ | |
154 Relationship creatorRel = getRelation(annotNode, RelationTypes.CREATED, null); | 160 Relationship creatorRel = getRelation(annotNode, RelationTypes.CREATED, null); |
155 if (creatorRel != null) { | 161 if (creatorRel != null) { |
156 Node creatorNode = creatorRel.getStartNode(); | 162 Node creatorNode = creatorRel.getStartNode(); |
157 Actor creator = createActorFromNode(creatorNode); | 163 Actor creator = createActorFromNode(creatorNode); |
158 annot.setCreator(creator); | 164 annot.setCreator(creator); |
159 } else { | 165 } else { |
160 logger.error("annotation " + annotNode + " has no creator node!"); | 166 logger.error("annotation " + annotNode + " has no creator node!"); |
161 } | 167 } |
162 // get creation date | 168 /* |
169 * get creation date | |
170 */ | |
163 annot.setCreated((String) annotNode.getProperty("created", null)); | 171 annot.setCreated((String) annotNode.getProperty("created", null)); |
164 // get permissions | 172 /* |
173 * get permissions | |
174 */ | |
165 Relationship adminRel = getRelation(annotNode, RelationTypes.PERMITS_ADMIN, null); | 175 Relationship adminRel = getRelation(annotNode, RelationTypes.PERMITS_ADMIN, null); |
166 if (adminRel != null) { | 176 if (adminRel != null) { |
167 Node adminNode = adminRel.getEndNode(); | 177 Node adminNode = adminRel.getEndNode(); |
168 Actor admin = createActorFromNode(adminNode); | 178 Actor admin = createActorFromNode(adminNode); |
169 annot.setAdminPermission(admin); | 179 annot.setAdminPermission(admin); |
184 if (readRel != null) { | 194 if (readRel != null) { |
185 Node readNode = readRel.getEndNode(); | 195 Node readNode = readRel.getEndNode(); |
186 Actor read = createActorFromNode(readNode); | 196 Actor read = createActorFromNode(readNode); |
187 annot.setReadPermission(read); | 197 annot.setReadPermission(read); |
188 } | 198 } |
199 /* | |
200 * get tags | |
201 */ | |
202 Set<String> tags = new HashSet<String>(); | |
203 for (Relationship rel : annotNode.getRelationships(RelationTypes.HAS_TAG)) { | |
204 String tag = (String) rel.getEndNode().getProperty("name", null); | |
205 if (tag != null) { | |
206 tags.add(tag); | |
207 } | |
208 } | |
209 annot.setTags(tags); | |
189 | 210 |
190 return annot; | 211 return annot; |
191 } | 212 } |
192 | 213 |
193 /** | 214 /** |
283 setPermissionRelation(annotNode, RelationTypes.PERMITS_ADMIN, annot.getAdminPermission()); | 304 setPermissionRelation(annotNode, RelationTypes.PERMITS_ADMIN, annot.getAdminPermission()); |
284 setPermissionRelation(annotNode, RelationTypes.PERMITS_DELETE, annot.getDeletePermission()); | 305 setPermissionRelation(annotNode, RelationTypes.PERMITS_DELETE, annot.getDeletePermission()); |
285 setPermissionRelation(annotNode, RelationTypes.PERMITS_UPDATE, annot.getUpdatePermission()); | 306 setPermissionRelation(annotNode, RelationTypes.PERMITS_UPDATE, annot.getUpdatePermission()); |
286 setPermissionRelation(annotNode, RelationTypes.PERMITS_READ, annot.getReadPermission()); | 307 setPermissionRelation(annotNode, RelationTypes.PERMITS_READ, annot.getReadPermission()); |
287 | 308 |
309 /* | |
310 * Tags on this annotation. | |
311 */ | |
312 Set<String> newTags = annot.getTags(); | |
313 // we ignore existing tags if tags == null | |
314 if (newTags != null) { | |
315 List<Relationship> oldHasTags = new ArrayList<Relationship>(); | |
316 for (Relationship rel : annotNode.getRelationships(RelationTypes.HAS_TAG)) { | |
317 oldHasTags.add(rel); | |
318 } | |
319 // adjust to new tags | |
320 if (newTags.isEmpty()) { | |
321 // remove old tags | |
322 if (!oldHasTags.isEmpty()) { | |
323 for (Relationship rel : oldHasTags) { | |
324 rel.delete(); | |
325 // TODO: should we delete orphan nodes too? | |
326 } | |
327 } | |
328 } else { | |
329 if (!oldHasTags.isEmpty()) { | |
330 // adjust old tags | |
331 for (Relationship rel : oldHasTags) { | |
332 String oldTag = (String) rel.getEndNode().getProperty("name", null); | |
333 if (newTags.contains(oldTag)) { | |
334 // tag exists | |
335 newTags.remove(oldTag); | |
336 } else { | |
337 // tag exists no longer | |
338 rel.delete(); | |
339 // TODO: should we delete orphan nodes too? | |
340 } | |
341 } | |
342 } | |
343 if (!newTags.isEmpty()) { | |
344 // still tags to add | |
345 for (String tag : newTags) { | |
346 // create new tag | |
347 Node tagNode = getOrCreateTagNode(tag); | |
348 getOrCreateRelation(annotNode, RelationTypes.HAS_TAG, tagNode); | |
349 } | |
350 } | |
351 | |
352 } | |
353 } | |
288 tx.success(); | 354 tx.success(); |
289 } finally { | 355 } finally { |
290 tx.finish(); | 356 tx.finish(); |
291 } | 357 } |
292 | 358 |
368 logger.error("CREATED relation does not end with ANNOTATION: " + ann); | 434 logger.error("CREATED relation does not end with ANNOTATION: " + ann); |
369 } | 435 } |
370 } | 436 } |
371 } | 437 } |
372 } | 438 } |
439 // TODO: if both uri and user are given we should intersect | |
373 return annotations; | 440 return annotations; |
374 } | 441 } |
375 | 442 |
443 /** | |
444 * Returns Relationship of type from Node start to Node end. Creates one if | |
445 * it doesn't exist. | |
446 * | |
447 * @param start | |
448 * @param type | |
449 * @param end | |
450 * @return | |
451 */ | |
376 protected Relationship getOrCreateRelation(Node start, RelationshipType type, Node end) { | 452 protected Relationship getOrCreateRelation(Node start, RelationshipType type, Node end) { |
377 if (start.hasRelationship()) { | 453 if (start.hasRelationship()) { |
378 // there are relations | 454 // there are relations |
379 Iterable<Relationship> rels = start.getRelationships(type, Direction.OUTGOING); | 455 Iterable<Relationship> rels = start.getRelationships(type, Direction.OUTGOING); |
380 for (Relationship rel : rels) { | 456 for (Relationship rel : rels) { |
455 try { | 531 try { |
456 person = graphDb.createNode(); | 532 person = graphDb.createNode(); |
457 if (actor.isGroup()) { | 533 if (actor.isGroup()) { |
458 person.setProperty("TYPE", NodeTypes.GROUP.name()); | 534 person.setProperty("TYPE", NodeTypes.GROUP.name()); |
459 } else { | 535 } else { |
460 person.setProperty("TYPE", NodeTypes.PERSON.name()); | 536 person.setProperty("TYPE", NodeTypes.PERSON.name()); |
461 } | 537 } |
462 person.setProperty("uri", uri); | 538 person.setProperty("uri", uri); |
463 idx.add(person, "uri", uri); | 539 idx.add(person, "uri", uri); |
464 if (name != null) { | 540 if (name != null) { |
465 person.setProperty("name", name); | 541 person.setProperty("name", name); |
471 } finally { | 547 } finally { |
472 tx.finish(); | 548 tx.finish(); |
473 } | 549 } |
474 } | 550 } |
475 return person; | 551 return person; |
552 } | |
553 | |
554 protected Node getOrCreateTagNode(String tagname) { | |
555 Index<Node> idx = getNodeIndex(NodeTypes.TAG); | |
556 IndexHits<Node> tags = idx.get("name", tagname); | |
557 Node tag = tags.getSingle(); | |
558 if (tag == null) { | |
559 // does not exist yet | |
560 Transaction tx = graphDb.beginTx(); | |
561 try { | |
562 tag = graphDb.createNode(); | |
563 tag.setProperty("TYPE", NodeTypes.TAG.name()); | |
564 tag.setProperty("name", tagname); | |
565 idx.add(tag, "name", tagname); | |
566 tx.success(); | |
567 } finally { | |
568 tx.finish(); | |
569 } | |
570 } | |
571 return tag; | |
476 } | 572 } |
477 | 573 |
478 /** | 574 /** |
479 * Create or update permissions relations for an annotation. | 575 * Create or update permissions relations for an annotation. |
480 * | 576 * |
530 } finally { | 626 } finally { |
531 tx.finish(); | 627 tx.finish(); |
532 } | 628 } |
533 } | 629 } |
534 | 630 |
535 /** returns the (first) Relationship of RelationTypes type from Node start. | 631 /** |
536 * | 632 * returns the (first) Relationship of RelationTypes type from Node start. |
633 * | |
537 * @param start | 634 * @param start |
538 * @param type | 635 * @param type |
539 * @param direction | 636 * @param direction |
540 * @return | 637 * @return |
541 */ | 638 */ |
546 rels = start.getRelationships(type); | 643 rels = start.getRelationships(type); |
547 } else { | 644 } else { |
548 rels = start.getRelationships(type, direction); | 645 rels = start.getRelationships(type, direction); |
549 } | 646 } |
550 for (Relationship rel : rels) { | 647 for (Relationship rel : rels) { |
648 // just the first one | |
551 return rel; | 649 return rel; |
552 } | 650 } |
553 return null; | 651 return null; |
554 } | 652 } |
555 | 653 |