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 |
