Changeset 14:629e15b345aa in AnnotationManagerN4J
- Timestamp:
- Jul 13, 2012, 6:41:02 PM (13 years ago)
- Branch:
- default
- Location:
- src/main/java/de/mpiwg/itgroup/annotations
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
src/main/java/de/mpiwg/itgroup/annotations/Actor.java
r13 r14 8 8 /** 9 9 * @author casties 10 * 10 * 11 11 */ 12 12 public abstract class Actor { … … 15 15 public String name; 16 16 public String id; 17 17 18 18 /** 19 19 * @return if this Actor is a Group 20 20 */ 21 21 public abstract boolean isGroup(); 22 22 23 /** 24 * Returns if this Actor is equivalent to an Actor with this id. If this is 25 * a Group returns true when the Person is in the Group. 26 * 27 * @param userId 28 * @return 29 */ 30 public boolean isEquivalentWith(String userId) { 31 if (userId == null) return false; 32 if (userId.equals(getIdString())) { 33 return true; 34 } 35 if (isGroup()) { 36 // TODO: check if person in group 37 } 38 return false; 39 } 40 23 41 /** 24 42 * @return the uri … … 34 52 */ 35 53 public String getUriString() { 36 37 38 54 if (uri == null) { 55 return getUriFromId(id, isGroup()); 56 } 39 57 return uri; 40 58 } 41 59 42 60 /** 43 * @param uri the uri to set 61 * @param uri 62 * the uri to set 44 63 */ 45 64 public void setUri(String uri) { 46 65 this.uri = uri; 47 66 } 67 48 68 /** 49 69 * @return the name … … 52 72 return name; 53 73 } 74 54 75 /** 55 * @param name the name to set 76 * @param name 77 * the name to set 56 78 */ 57 79 public void setName(String name) { … … 65 87 return id; 66 88 } 67 89 68 90 /** 69 91 * Returns id as a String starting with "group:" for groups. … … 72 94 */ 73 95 public abstract String getIdString(); 74 96 75 97 /** 76 * @param id the id to set 98 * @param id 99 * the id to set 77 100 */ 78 101 public void setId(String id) { 79 102 this.id = id; 80 103 } 81 104 82 105 /** 83 106 * Returns a short id from an uri. … … 110 133 prefix = NS.MPIWG_GROUPS_URL; 111 134 } 112 if (id != null && ! 113 uri = prefix + id; 135 if (id != null && !id.startsWith("http://")) { 136 uri = prefix + id; 114 137 } 115 138 return uri; -
src/main/java/de/mpiwg/itgroup/annotations/Annotation.java
r10 r14 81 81 protected Actor readPermission; 82 82 83 84 /** 85 * Returns if the requested action is allowed on this annotation. 86 * 87 * @param action 88 * @param userId 89 * @return 90 */ 91 public boolean isActionAllowed(String action, String userId) { 92 if (action.equals("read")) { 93 Actor reader = getReadPermission(); 94 if (reader == null) { 95 return true; 96 } else { 97 return reader.isEquivalentWith(userId); 98 } 99 } else if (action.equals("update")) { 100 // require at least an authenticated user 101 if (userId == null) return false; 102 Actor updater = getUpdatePermission(); 103 if (updater == null) { 104 return true; 105 } else { 106 return updater.isEquivalentWith(userId); 107 } 108 } else if (action.equals("delete")) { 109 // require at least an authenticated user 110 if (userId == null) return false; 111 Actor updater = getUpdatePermission(); 112 if (updater == null) { 113 return true; 114 } else { 115 return updater.isEquivalentWith(userId); 116 } 117 } else if (action.equals("admin")) { 118 // require at least an authenticated user 119 if (userId == null) return false; 120 Actor admin = getAdminPermission(); 121 if (admin == null) { 122 return true; 123 } else { 124 return admin.isEquivalentWith(userId); 125 } 126 } 127 return false; 128 } 129 83 130 /** 84 131 * @return the uri -
src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java
r13 r14 30 30 public class AnnotationStore { 31 31 32 protected static Logger logger = Logger.getLogger(AnnotationStore.class); 33 34 protected GraphDatabaseService graphDb; 35 36 public static enum NodeTypes { 37 ANNOTATION, PERSON, TARGET 38 } 39 40 protected List<Index<Node>> nodeIndexes; 41 42 public static enum RelationTypes implements RelationshipType { 43 ANNOTATES, CREATED, PERMITS_ADMIN, PERMITS_DELETE, PERMITS_UPDATE, PERMITS_READ 44 } 45 46 public static String ANNOTATION_URI_BASE = "http://entities.mpiwg-berlin.mpg.de/annotations/"; 47 48 public AnnotationStore(GraphDatabaseService graphDb) { 49 super(); 50 this.graphDb = graphDb; 51 nodeIndexes = new ArrayList<Index<Node>>(3); 52 // List.set(enum.ordinal(), val) seems not to work. 53 nodeIndexes.add(NodeTypes.ANNOTATION.ordinal(), graphDb.index() 54 .forNodes("annotations")); 55 nodeIndexes.add(NodeTypes.PERSON.ordinal(), 56 graphDb.index().forNodes("persons")); 57 nodeIndexes.add(NodeTypes.TARGET.ordinal(), 58 graphDb.index().forNodes("targets")); 59 } 60 61 protected Index<Node> getNodeIndex(NodeTypes type) { 62 return nodeIndexes.get(type.ordinal()); 63 } 64 65 /** 66 * Returns the Annotation with the given id. 67 * 68 * @param id 69 * @return 70 */ 71 public Annotation getAnnotationById(String id) { 72 Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id) 73 .getSingle(); 74 Annotation annot = createAnnotationFromNode(annotNode); 75 return annot; 76 } 77 78 /** 79 * Returns an Annotation object from an annotation-Node. 80 * 81 * @param annotNode 82 * @return 83 */ 84 public Annotation createAnnotationFromNode(Node annotNode) { 85 Annotation annot = new Annotation(); 86 annot.setUri((String) annotNode.getProperty("id", null)); 87 annot.setBodyText((String) annotNode.getProperty("bodyText", null)); 88 annot.setBodyUri((String) annotNode.getProperty("bodyUri", null)); 89 // get annotation target from relation 90 Relationship targetRel = getRelation(annotNode, 91 RelationTypes.ANNOTATES, null); 92 if (targetRel != null) { 93 Node target = targetRel.getEndNode(); 94 annot.setTargetBaseUri((String) target.getProperty("uri", null)); 95 } else { 96 logger.error("annotation " + annotNode + " has no target node!"); 97 } 98 annot.setTargetFragment((String) annotNode.getProperty( 99 "targetFragment", null)); 100 String ft = (String) annotNode.getProperty("fragmentType", null); 101 if (ft != null) { 102 annot.setFragmentType(FragmentTypes.valueOf(ft)); 103 } 104 // get creator from relation 105 Relationship creatorRel = getRelation(annotNode, RelationTypes.CREATED, 106 null); 107 if (creatorRel != null) { 108 Node creatorNode = creatorRel.getStartNode(); 109 Actor creator = createActorFromNode(creatorNode); 110 annot.setCreator(creator); 111 } else { 112 logger.error("annotation " + annotNode + " has no creator node!"); 113 } 114 // get creation date 115 annot.setCreated((String) annotNode.getProperty("created", null)); 116 // get permissions 117 Relationship adminRel = getRelation(annotNode, 118 RelationTypes.PERMITS_ADMIN, null); 119 if (adminRel != null) { 120 Node adminNode = adminRel.getEndNode(); 121 Actor admin = createActorFromNode(adminNode); 122 annot.setAdminPermission(admin); 123 } 124 Relationship deleteRel = getRelation(annotNode, 125 RelationTypes.PERMITS_DELETE, null); 126 if (deleteRel != null) { 127 Node deleteNode = deleteRel.getEndNode(); 128 Actor delete = createActorFromNode(deleteNode); 129 annot.setDeletePermission(delete); 130 } 131 Relationship updateRel = getRelation(annotNode, 132 RelationTypes.PERMITS_UPDATE, null); 133 if (updateRel != null) { 134 Node updateNode = updateRel.getEndNode(); 135 Actor update = createActorFromNode(updateNode); 136 annot.setUpdatePermission(update); 137 } 138 Relationship readRel = getRelation(annotNode, 139 RelationTypes.PERMITS_READ, null); 140 if (readRel != null) { 141 Node readNode = readRel.getEndNode(); 142 Actor read = createActorFromNode(readNode); 143 annot.setReadPermission(read); 144 } 145 146 return annot; 147 } 148 149 /** 150 * Returns an Actor object from a node. 151 * 152 * @param actorNode 153 * @return 154 */ 155 protected Actor createActorFromNode(Node actorNode) { 156 String uri = (String) actorNode.getProperty("uri", null); 157 String name = (String) actorNode.getProperty("name", null); 158 String type = (String) actorNode.getProperty("TYPE", null); 159 if (type != null && type.equals("PERSON")) { 160 return new Person(uri, name); 161 } else if (type != null && type.equals("GROUP")) { 162 return new Group(uri, name); 163 } 164 return null; 165 } 166 167 /** 168 * Store a new annotation in the store or update an existing one. Returns 169 * the stored annotation. 170 * 171 * @param annot 172 * @return 173 */ 174 public Annotation storeAnnotation(Annotation annot) { 175 Node annotNode = null; 176 Transaction tx = graphDb.beginTx(); 177 try { 178 /* 179 * create or get the annotation 180 */ 181 String id = annot.getUri(); 182 if (id == null) { 183 id = createRessourceURI("annot:"); 184 } 185 annotNode = getOrCreateAnnotationNode(id); 186 187 /* 188 * the annotation body 189 */ 190 String bodyText = annot.getBodyText(); 191 if (bodyText != null) { 192 annotNode.setProperty("bodyText", bodyText); 193 } 194 String bodyUri = annot.getBodyUri(); 195 if (bodyUri != null) { 196 annotNode.setProperty("bodyUri", bodyUri); 197 } 198 199 /* 200 * the annotation target 201 */ 202 String targetBaseUri = annot.getTargetBaseUri(); 203 if (targetBaseUri != null) { 204 Node target = getOrCreateTargetNode(targetBaseUri); 205 getOrCreateRelation(annotNode, RelationTypes.ANNOTATES, target); 206 } 207 208 /* 209 * The fragment part of the annotation target. 210 */ 211 String targetFragment = annot.getTargetFragment(); 212 FragmentTypes fragmentType = annot.getFragmentType(); 213 if (targetFragment != null) { 214 annotNode.setProperty("targetFragment", targetFragment); 215 annotNode.setProperty("fragmentType", fragmentType.name()); 216 } 217 218 /* 219 * The creator of this annotation. 220 */ 221 Actor creator = annot.getCreator(); 222 if (creator != null) { 223 Node creatorNode = getOrCreatePersonNode(creator); 224 getOrCreateRelation(creatorNode, RelationTypes.CREATED, 225 annotNode); 226 } 227 228 /* 229 * The creation date of this annotation. 230 */ 231 String created = annot.getCreated(); 232 if (created != null) { 233 annotNode.setProperty("created", created); 234 } 235 236 /* 237 * Permissions for this annotation. 238 */ 239 setPermissionRelation(annotNode, RelationTypes.PERMITS_ADMIN, 240 annot.getAdminPermission()); 241 setPermissionRelation(annotNode, RelationTypes.PERMITS_DELETE, 242 annot.getDeletePermission()); 243 setPermissionRelation(annotNode, RelationTypes.PERMITS_UPDATE, 244 annot.getUpdatePermission()); 245 setPermissionRelation(annotNode, RelationTypes.PERMITS_READ, 246 annot.getReadPermission()); 247 248 tx.success(); 249 } finally { 250 tx.finish(); 251 } 252 253 // re-read and return annotation 254 Annotation storedAnnot = createAnnotationFromNode(annotNode); 255 return storedAnnot; 256 } 257 258 /** 259 * Deletes the annotation with the given id. 260 * 261 * @param id 262 */ 263 public void deleteById(String id) { 264 Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id) 265 .getSingle(); 266 if (annotNode != null) { 267 // delete related objects 268 Transaction tx = graphDb.beginTx(); 269 try { 270 for (Relationship rel : annotNode.getRelationships()) { 271 // delete relation and the related node if it has no other 272 // relations 273 Node other = rel.getOtherNode(annotNode); 274 rel.delete(); 275 if (!other.hasRelationship()) { 276 deleteNode(other); 277 } 278 } 279 if (!annotNode.hasRelationship()) { 280 deleteNode(annotNode); 281 } else { 282 logger.error("deleteById: unable to delete: Node still has relations."); 283 } 284 tx.success(); 285 } finally { 286 tx.finish(); 287 } 288 } 289 } 290 291 /** 292 * Returns all annotations with the given uri and/or user. 293 * 294 * @param uri 295 * @param userUri 296 * @param limit 297 * @param offset 298 * @return 299 */ 300 public List<Annotation> searchByUriUser(String targetUri, String userUri, 301 String limit, String offset) { 302 List<Annotation> annotations = new ArrayList<Annotation>(); 303 if (targetUri != null) { 304 // there should be only one 305 Node target = getNodeIndex(NodeTypes.TARGET).get("uri", targetUri) 306 .getSingle(); 307 if (target != null) { 308 Iterable<Relationship> relations = target 309 .getRelationships(RelationTypes.ANNOTATES); 310 for (Relationship relation : relations) { 311 Node ann = relation.getStartNode(); 312 if (ann.getProperty("TYPE", "").equals("ANNOTATION")) { 313 Annotation annot = createAnnotationFromNode(ann); 314 annotations.add(annot); 315 } else { 316 logger.error("ANNOTATES relation does not start with ANNOTATION: " 317 + ann); 318 } 319 } 320 } 321 } 322 if (userUri != null) { 323 // there should be only one 324 Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri) 325 .getSingle(); 326 if (person != null) { 327 Iterable<Relationship> relations = person 328 .getRelationships(RelationTypes.CREATED); 329 for (Relationship relation : relations) { 330 Node ann = relation.getEndNode(); 331 if (ann.getProperty("TYPE", "").equals("ANNOTATION")) { 332 Annotation annot = createAnnotationFromNode(ann); 333 annotations.add(annot); 334 } else { 335 logger.error("CREATED relation does not end with ANNOTATION: " 336 + ann); 337 } 338 } 339 } 340 } 341 return annotations; 342 } 343 344 protected Relationship getOrCreateRelation(Node start, 345 RelationshipType type, Node end) { 346 if (start.hasRelationship()) { 347 // there are relations 348 Iterable<Relationship> rels = start.getRelationships(type, 349 Direction.OUTGOING); 350 for (Relationship rel : rels) { 351 if (rel.getEndNode().equals(end)) { 352 // relation exists 353 return rel; 354 } 355 } 356 } 357 // create new one 358 Relationship rel; 359 Transaction tx = graphDb.beginTx(); 360 try { 361 rel = start.createRelationshipTo(end, type); 362 tx.success(); 363 } finally { 364 tx.finish(); 365 } 366 return rel; 367 } 368 369 protected Node getOrCreateAnnotationNode(String id) { 370 Index<Node> idx = getNodeIndex(NodeTypes.ANNOTATION); 371 IndexHits<Node> annotations = idx.get("id", id); 372 Node annotation = annotations.getSingle(); 373 if (annotation == null) { 374 // does not exist yet 375 Transaction tx = graphDb.beginTx(); 376 try { 377 annotation = graphDb.createNode(); 378 annotation.setProperty("TYPE", NodeTypes.ANNOTATION.name()); 379 annotation.setProperty("id", id); 380 idx.add(annotation, "id", id); 381 tx.success(); 382 } finally { 383 tx.finish(); 384 } 385 } 386 return annotation; 387 } 388 389 protected Node getOrCreateTargetNode(String uri) { 390 Index<Node> idx = getNodeIndex(NodeTypes.TARGET); 391 IndexHits<Node> targets = idx.get("uri", uri); 392 Node target = targets.getSingle(); 393 if (target == null) { 394 // does not exist yet 395 Transaction tx = graphDb.beginTx(); 396 try { 397 target = graphDb.createNode(); 398 target.setProperty("TYPE", NodeTypes.TARGET.name()); 399 target.setProperty("uri", uri); 400 idx.add(target, "uri", uri); 401 tx.success(); 402 } finally { 403 tx.finish(); 404 } 405 } 406 return target; 407 } 408 409 protected Node getOrCreatePersonNode(Actor actor) { 410 // Person is identified by URI 411 String uri = actor.getUriString(); 412 String name = actor.getName(); 413 Index<Node> idx = getNodeIndex(NodeTypes.PERSON); 414 IndexHits<Node> persons = idx.get("uri", uri); 415 Node person = persons.getSingle(); 416 if (person == null) { 417 // does not exist yet 418 Transaction tx = graphDb.beginTx(); 419 try { 420 person = graphDb.createNode(); 421 person.setProperty("TYPE", NodeTypes.PERSON.name()); 422 person.setProperty("uri", uri); 423 idx.add(person, "uri", uri); 424 if (name != null) { 425 person.setProperty("name", name); 426 } 427 tx.success(); 428 } finally { 429 tx.finish(); 430 } 431 } 432 return person; 433 } 434 435 /** 436 * Create or update permissions relations for an annotation. 437 * 438 * @param annotNode 439 * @param type 440 * @param annot 441 */ 442 protected void setPermissionRelation(Node annotNode, RelationTypes type, 443 Actor actor) { 444 Node newActorNode = null; 445 if (actor != null) { 446 newActorNode = getOrCreatePersonNode(actor); 447 } 448 Relationship rel = getRelation(annotNode, type, null); 449 if (rel != null) { 450 // relation exists 451 Node oldActorNode = rel.getEndNode(); 452 if (!oldActorNode.equals(newActorNode)) { 453 // new admin is different 454 rel.delete(); 455 if (newActorNode != null) { 456 rel = getOrCreateRelation(annotNode, type, newActorNode); 457 } 458 } 459 } else { 460 // no relation yet 461 if (newActorNode != null) { 462 rel = getOrCreateRelation(annotNode, type, newActorNode); 463 } 464 } 465 } 466 467 /** 468 * Unindexes and deletes given Node if it has no relations. 469 * 470 * @param node 471 */ 472 protected void deleteNode(Node node) { 473 Transaction tx = graphDb.beginTx(); 474 try { 475 if (node.hasRelationship()) { 476 logger.error("deleteNode: unable to delete: Node still has relations."); 477 } else { 478 String ts = (String) node.getProperty("TYPE", null); 479 try { 480 NodeTypes type = NodeTypes.valueOf(ts); 481 getNodeIndex(type).remove(node); 482 } catch (Exception e) { 483 logger.error("deleteNode: unable to get TYPE of node: " 484 + node); 485 } 486 node.delete(); 487 } 488 tx.success(); 489 } finally { 490 tx.finish(); 491 } 492 } 493 494 protected Relationship getRelation(Node start, RelationTypes type, 495 Direction direction) { 496 Iterable<Relationship> rels; 497 if (direction == null) { 498 // ignore direction 499 rels = start.getRelationships(type); 500 } else { 501 rels = start.getRelationships(type, direction); 502 } 503 for (Relationship rel : rels) { 504 return rel; 505 } 506 return null; 507 } 508 509 /** 510 * Erzeuge eine urn aus der aktuellen Zeit in millis 511 * 512 * @return 513 */ 514 private String createRessourceURI(String prefix) { 515 516 Calendar cal = Calendar.getInstance(); 517 518 long time = cal.getTimeInMillis(); 519 520 return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time); 521 522 } 32 protected static Logger logger = Logger.getLogger(AnnotationStore.class); 33 34 protected GraphDatabaseService graphDb; 35 36 public static enum NodeTypes { 37 ANNOTATION, PERSON, TARGET 38 } 39 40 protected List<Index<Node>> nodeIndexes; 41 42 public static enum RelationTypes implements RelationshipType { 43 ANNOTATES, CREATED, PERMITS_ADMIN, PERMITS_DELETE, PERMITS_UPDATE, PERMITS_READ 44 } 45 46 public static String ANNOTATION_URI_BASE = "http://entities.mpiwg-berlin.mpg.de/annotations/"; 47 48 public AnnotationStore(GraphDatabaseService graphDb) { 49 super(); 50 this.graphDb = graphDb; 51 nodeIndexes = new ArrayList<Index<Node>>(3); 52 // List.set(enum.ordinal(), val) seems not to work. 53 nodeIndexes.add(NodeTypes.ANNOTATION.ordinal(), graphDb.index().forNodes("annotations")); 54 nodeIndexes.add(NodeTypes.PERSON.ordinal(), graphDb.index().forNodes("persons")); 55 nodeIndexes.add(NodeTypes.TARGET.ordinal(), graphDb.index().forNodes("targets")); 56 } 57 58 protected Index<Node> getNodeIndex(NodeTypes type) { 59 return nodeIndexes.get(type.ordinal()); 60 } 61 62 /** 63 * Returns the Annotation with the given id. 64 * 65 * @param id 66 * @return 67 */ 68 public Annotation getAnnotationById(String id) { 69 Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id).getSingle(); 70 Annotation annot = createAnnotationFromNode(annotNode); 71 return annot; 72 } 73 74 /** 75 * Returns an Annotation object from an annotation-Node. 76 * 77 * @param annotNode 78 * @return 79 */ 80 public Annotation createAnnotationFromNode(Node annotNode) { 81 Annotation annot = new Annotation(); 82 annot.setUri((String) annotNode.getProperty("id", null)); 83 annot.setBodyText((String) annotNode.getProperty("bodyText", null)); 84 annot.setBodyUri((String) annotNode.getProperty("bodyUri", null)); 85 // get annotation target from relation 86 Relationship targetRel = getRelation(annotNode, RelationTypes.ANNOTATES, null); 87 if (targetRel != null) { 88 Node target = targetRel.getEndNode(); 89 annot.setTargetBaseUri((String) target.getProperty("uri", null)); 90 } else { 91 logger.error("annotation " + annotNode + " has no target node!"); 92 } 93 annot.setTargetFragment((String) annotNode.getProperty("targetFragment", null)); 94 String ft = (String) annotNode.getProperty("fragmentType", null); 95 if (ft != null) { 96 annot.setFragmentType(FragmentTypes.valueOf(ft)); 97 } 98 // get creator from relation 99 Relationship creatorRel = getRelation(annotNode, RelationTypes.CREATED, null); 100 if (creatorRel != null) { 101 Node creatorNode = creatorRel.getStartNode(); 102 Actor creator = createActorFromNode(creatorNode); 103 annot.setCreator(creator); 104 } else { 105 logger.error("annotation " + annotNode + " has no creator node!"); 106 } 107 // get creation date 108 annot.setCreated((String) annotNode.getProperty("created", null)); 109 // get permissions 110 Relationship adminRel = getRelation(annotNode, RelationTypes.PERMITS_ADMIN, null); 111 if (adminRel != null) { 112 Node adminNode = adminRel.getEndNode(); 113 Actor admin = createActorFromNode(adminNode); 114 annot.setAdminPermission(admin); 115 } 116 Relationship deleteRel = getRelation(annotNode, RelationTypes.PERMITS_DELETE, null); 117 if (deleteRel != null) { 118 Node deleteNode = deleteRel.getEndNode(); 119 Actor delete = createActorFromNode(deleteNode); 120 annot.setDeletePermission(delete); 121 } 122 Relationship updateRel = getRelation(annotNode, RelationTypes.PERMITS_UPDATE, null); 123 if (updateRel != null) { 124 Node updateNode = updateRel.getEndNode(); 125 Actor update = createActorFromNode(updateNode); 126 annot.setUpdatePermission(update); 127 } 128 Relationship readRel = getRelation(annotNode, RelationTypes.PERMITS_READ, null); 129 if (readRel != null) { 130 Node readNode = readRel.getEndNode(); 131 Actor read = createActorFromNode(readNode); 132 annot.setReadPermission(read); 133 } 134 135 return annot; 136 } 137 138 /** 139 * Returns an Actor object from a node. 140 * 141 * @param actorNode 142 * @return 143 */ 144 protected Actor createActorFromNode(Node actorNode) { 145 String uri = (String) actorNode.getProperty("uri", null); 146 String name = (String) actorNode.getProperty("name", null); 147 String type = (String) actorNode.getProperty("TYPE", null); 148 if (type != null && type.equals("PERSON")) { 149 return new Person(uri, name); 150 } else if (type != null && type.equals("GROUP")) { 151 return new Group(uri, name); 152 } 153 return null; 154 } 155 156 /** 157 * Store a new annotation in the store or update an existing one. Returns 158 * the stored annotation. 159 * 160 * @param annot 161 * @return 162 */ 163 public Annotation storeAnnotation(Annotation annot) { 164 Node annotNode = null; 165 Transaction tx = graphDb.beginTx(); 166 try { 167 /* 168 * create or get the annotation 169 */ 170 String id = annot.getUri(); 171 if (id == null) { 172 id = createRessourceURI("annot:"); 173 } 174 annotNode = getOrCreateAnnotationNode(id); 175 176 /* 177 * the annotation body 178 */ 179 String bodyText = annot.getBodyText(); 180 if (bodyText != null) { 181 annotNode.setProperty("bodyText", bodyText); 182 } 183 String bodyUri = annot.getBodyUri(); 184 if (bodyUri != null) { 185 annotNode.setProperty("bodyUri", bodyUri); 186 } 187 188 /* 189 * the annotation target 190 */ 191 String targetBaseUri = annot.getTargetBaseUri(); 192 if (targetBaseUri != null) { 193 Node target = getOrCreateTargetNode(targetBaseUri); 194 getOrCreateRelation(annotNode, RelationTypes.ANNOTATES, target); 195 } 196 197 /* 198 * The fragment part of the annotation target. 199 */ 200 String targetFragment = annot.getTargetFragment(); 201 FragmentTypes fragmentType = annot.getFragmentType(); 202 if (targetFragment != null) { 203 annotNode.setProperty("targetFragment", targetFragment); 204 annotNode.setProperty("fragmentType", fragmentType.name()); 205 } 206 207 /* 208 * The creator of this annotation. 209 */ 210 Actor creator = annot.getCreator(); 211 if (creator != null) { 212 Node creatorNode = getOrCreatePersonNode(creator); 213 getOrCreateRelation(creatorNode, RelationTypes.CREATED, annotNode); 214 } 215 216 /* 217 * The creation date of this annotation. 218 */ 219 String created = annot.getCreated(); 220 if (created != null) { 221 annotNode.setProperty("created", created); 222 } 223 224 /* 225 * Permissions for this annotation. 226 */ 227 setPermissionRelation(annotNode, RelationTypes.PERMITS_ADMIN, annot.getAdminPermission()); 228 setPermissionRelation(annotNode, RelationTypes.PERMITS_DELETE, annot.getDeletePermission()); 229 setPermissionRelation(annotNode, RelationTypes.PERMITS_UPDATE, annot.getUpdatePermission()); 230 setPermissionRelation(annotNode, RelationTypes.PERMITS_READ, annot.getReadPermission()); 231 232 tx.success(); 233 } finally { 234 tx.finish(); 235 } 236 237 // re-read and return annotation 238 Annotation storedAnnot = createAnnotationFromNode(annotNode); 239 return storedAnnot; 240 } 241 242 /** 243 * Deletes the annotation with the given id. 244 * 245 * @param id 246 */ 247 public void deleteById(String id) { 248 Node annotNode = getNodeIndex(NodeTypes.ANNOTATION).get("id", id).getSingle(); 249 if (annotNode != null) { 250 // delete related objects 251 Transaction tx = graphDb.beginTx(); 252 try { 253 for (Relationship rel : annotNode.getRelationships()) { 254 // delete relation and the related node if it has no other 255 // relations 256 Node other = rel.getOtherNode(annotNode); 257 rel.delete(); 258 if (!other.hasRelationship()) { 259 deleteNode(other); 260 } 261 } 262 if (!annotNode.hasRelationship()) { 263 deleteNode(annotNode); 264 } else { 265 logger.error("deleteById: unable to delete: Node still has relations."); 266 } 267 tx.success(); 268 } finally { 269 tx.finish(); 270 } 271 } 272 } 273 274 /** 275 * Returns all annotations with the given uri and/or user. 276 * 277 * @param uri 278 * @param userUri 279 * @param limit 280 * @param offset 281 * @return 282 */ 283 public List<Annotation> searchByUriUser(String targetUri, String userUri, String limit, String offset) { 284 List<Annotation> annotations = new ArrayList<Annotation>(); 285 if (targetUri != null) { 286 // there should be only one 287 Node target = getNodeIndex(NodeTypes.TARGET).get("uri", targetUri).getSingle(); 288 if (target != null) { 289 Iterable<Relationship> relations = target.getRelationships(RelationTypes.ANNOTATES); 290 for (Relationship relation : relations) { 291 Node ann = relation.getStartNode(); 292 if (ann.getProperty("TYPE", "").equals("ANNOTATION")) { 293 Annotation annot = createAnnotationFromNode(ann); 294 annotations.add(annot); 295 } else { 296 logger.error("ANNOTATES relation does not start with ANNOTATION: " + ann); 297 } 298 } 299 } 300 } 301 if (userUri != null) { 302 // there should be only one 303 Node person = getNodeIndex(NodeTypes.PERSON).get("uri", userUri).getSingle(); 304 if (person != null) { 305 Iterable<Relationship> relations = person.getRelationships(RelationTypes.CREATED); 306 for (Relationship relation : relations) { 307 Node ann = relation.getEndNode(); 308 if (ann.getProperty("TYPE", "").equals("ANNOTATION")) { 309 Annotation annot = createAnnotationFromNode(ann); 310 annotations.add(annot); 311 } else { 312 logger.error("CREATED relation does not end with ANNOTATION: " + ann); 313 } 314 } 315 } 316 } 317 return annotations; 318 } 319 320 protected Relationship getOrCreateRelation(Node start, RelationshipType type, Node end) { 321 if (start.hasRelationship()) { 322 // there are relations 323 Iterable<Relationship> rels = start.getRelationships(type, Direction.OUTGOING); 324 for (Relationship rel : rels) { 325 if (rel.getEndNode().equals(end)) { 326 // relation exists 327 return rel; 328 } 329 } 330 } 331 // create new one 332 Relationship rel; 333 Transaction tx = graphDb.beginTx(); 334 try { 335 rel = start.createRelationshipTo(end, type); 336 tx.success(); 337 } finally { 338 tx.finish(); 339 } 340 return rel; 341 } 342 343 protected Node getOrCreateAnnotationNode(String id) { 344 Index<Node> idx = getNodeIndex(NodeTypes.ANNOTATION); 345 IndexHits<Node> annotations = idx.get("id", id); 346 Node annotation = annotations.getSingle(); 347 if (annotation == null) { 348 // does not exist yet 349 Transaction tx = graphDb.beginTx(); 350 try { 351 annotation = graphDb.createNode(); 352 annotation.setProperty("TYPE", NodeTypes.ANNOTATION.name()); 353 annotation.setProperty("id", id); 354 idx.add(annotation, "id", id); 355 tx.success(); 356 } finally { 357 tx.finish(); 358 } 359 } 360 return annotation; 361 } 362 363 protected Node getOrCreateTargetNode(String uri) { 364 Index<Node> idx = getNodeIndex(NodeTypes.TARGET); 365 IndexHits<Node> targets = idx.get("uri", uri); 366 Node target = targets.getSingle(); 367 if (target == null) { 368 // does not exist yet 369 Transaction tx = graphDb.beginTx(); 370 try { 371 target = graphDb.createNode(); 372 target.setProperty("TYPE", NodeTypes.TARGET.name()); 373 target.setProperty("uri", uri); 374 idx.add(target, "uri", uri); 375 tx.success(); 376 } finally { 377 tx.finish(); 378 } 379 } 380 return target; 381 } 382 383 protected Node getOrCreatePersonNode(Actor actor) { 384 // Person is identified by URI 385 String uri = actor.getUriString(); 386 String name = actor.getName(); 387 Index<Node> idx = getNodeIndex(NodeTypes.PERSON); 388 IndexHits<Node> persons = idx.get("uri", uri); 389 Node person = persons.getSingle(); 390 if (person == null) { 391 // does not exist yet 392 Transaction tx = graphDb.beginTx(); 393 try { 394 person = graphDb.createNode(); 395 person.setProperty("TYPE", NodeTypes.PERSON.name()); 396 person.setProperty("uri", uri); 397 idx.add(person, "uri", uri); 398 if (name != null) { 399 person.setProperty("name", name); 400 } 401 tx.success(); 402 } finally { 403 tx.finish(); 404 } 405 } 406 return person; 407 } 408 409 /** 410 * Create or update permissions relations for an annotation. 411 * 412 * @param annotNode 413 * @param type 414 * @param annot 415 */ 416 protected void setPermissionRelation(Node annotNode, RelationTypes type, Actor actor) { 417 Node newActorNode = null; 418 if (actor != null) { 419 newActorNode = getOrCreatePersonNode(actor); 420 } 421 Relationship rel = getRelation(annotNode, type, null); 422 if (rel != null) { 423 // relation exists 424 Node oldActorNode = rel.getEndNode(); 425 if (!oldActorNode.equals(newActorNode)) { 426 // new admin is different 427 rel.delete(); 428 if (newActorNode != null) { 429 rel = getOrCreateRelation(annotNode, type, newActorNode); 430 } 431 } 432 } else { 433 // no relation yet 434 if (newActorNode != null) { 435 rel = getOrCreateRelation(annotNode, type, newActorNode); 436 } 437 } 438 } 439 440 /** 441 * Unindexes and deletes given Node if it has no relations. 442 * 443 * @param node 444 */ 445 protected void deleteNode(Node node) { 446 Transaction tx = graphDb.beginTx(); 447 try { 448 if (node.hasRelationship()) { 449 logger.error("deleteNode: unable to delete: Node still has relations."); 450 } else { 451 String ts = (String) node.getProperty("TYPE", null); 452 try { 453 NodeTypes type = NodeTypes.valueOf(ts); 454 getNodeIndex(type).remove(node); 455 } catch (Exception e) { 456 logger.error("deleteNode: unable to get TYPE of node: " + node); 457 } 458 node.delete(); 459 } 460 tx.success(); 461 } finally { 462 tx.finish(); 463 } 464 } 465 466 protected Relationship getRelation(Node start, RelationTypes type, Direction direction) { 467 Iterable<Relationship> rels; 468 if (direction == null) { 469 // ignore direction 470 rels = start.getRelationships(type); 471 } else { 472 rels = start.getRelationships(type, direction); 473 } 474 for (Relationship rel : rels) { 475 return rel; 476 } 477 return null; 478 } 479 480 /** 481 * Erzeuge eine urn aus der aktuellen Zeit in millis 482 * 483 * @return 484 */ 485 private String createRessourceURI(String prefix) { 486 487 Calendar cal = Calendar.getInstance(); 488 489 long time = cal.getTimeInMillis(); 490 491 return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time); 492 493 } 523 494 524 495 } -
src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java
r4 r14 51 51 // TODO: what to return without id - list of all annotations? 52 52 53 // TODO: what to do with authentication? 54 boolean authenticated = isAuthenticated(entity); 55 logger.debug("request authenticated=" + authenticated); 56 57 Annotation annots = getAnnotationStore().getAnnotationById(id); 58 if (annots != null) { 59 // there should be only one 60 JSONObject result = createAnnotatorJson(annots); 53 // do authentication 54 String authUser = this.checkAuthToken(entity); 55 logger.debug("request authenticated=" + authUser); 56 57 Annotation annot = getAnnotationStore().getAnnotationById(id); 58 if (annot != null) { 59 if (! annot.isActionAllowed("read", authUser)) { 60 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); 61 return null; 62 } 63 JSONObject result = createAnnotatorJson(annot, (authUser == null)); 61 64 logger.debug("sending:"); 62 65 logger.debug(result); 63 66 return new JsonRepresentation(result); 64 67 } else { 65 JSONArray results = new JSONArray(); 66 // annotator read request returns a list of annotation objects 67 logger.debug("sending:"); 68 logger.debug(results); 69 return new JsonRepresentation(results); 68 // not found 69 setStatus(Status.CLIENT_ERROR_NOT_FOUND); 70 return null; 70 71 } 71 72 } … … 73 74 /** 74 75 * POST with JSON content-type. 75 *76 * json hash: username: name des users xpointer: xpointer auf den Ausschnitt77 * (incl. der URL des Dokumentes) text: text der annotation annoturl: url78 * auf eine Annotation falls extern79 76 * 80 77 * @return … … 85 82 // set headers 86 83 setCorsHeaders(); 84 85 // do authentication TODO: who's allowed to create? 86 String authUser = this.checkAuthToken(entity); 87 logger.debug("request authenticated=" + authUser); 88 if (authUser == null) { 89 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); 90 return null; 91 } 92 87 93 Annotation annot = null; 88 94 try { … … 115 121 * return 303: see other. For now we return the annotation. 116 122 */ 117 JSONObject jo = createAnnotatorJson(storedAnnot );123 JSONObject jo = createAnnotatorJson(storedAnnot, (authUser == null)); 118 124 JsonRepresentation retRep = new JsonRepresentation(jo); 119 125 return retRep; … … 135 141 logger.debug("annotation-id=" + id); 136 142 137 // TODO: what to do with authentication? we should check the owner 138 boolean authenticated = isAuthenticated(entity); 139 logger.debug("request authenticated=" + authenticated); 140 if (!authenticated) { 141 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); 142 return null; 143 } 143 // do authentication 144 String authUser = this.checkAuthToken(entity); 145 logger.debug("request authenticated=" + authUser); 144 146 145 147 Annotation annot = null; … … 156 158 if (storedAnnot == null) { 157 159 setStatus(Status.CLIENT_ERROR_NOT_FOUND); 160 return null; 161 } 162 if (! storedAnnot.isActionAllowed("update", authUser)) { 163 setStatus(Status.CLIENT_ERROR_FORBIDDEN); 158 164 return null; 159 165 } … … 170 176 */ 171 177 // return new annotation 172 jo = createAnnotatorJson(storedAnnot );178 jo = createAnnotatorJson(storedAnnot, (authUser == null)); 173 179 JsonRepresentation retRep = new JsonRepresentation(jo); 174 180 return retRep; … … 198 204 logger.debug("annotation-id=" + id); 199 205 200 // TODO: what to do with authentication? we should check the owner 201 boolean authenticated = isAuthenticated(entity); 202 logger.debug("request authenticated=" + authenticated); 203 if (!authenticated) { 204 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); 205 return null; 206 } 207 206 // do authentication 207 String authUser = this.checkAuthToken(entity); 208 logger.debug("request authenticated=" + authUser); 209 Annotation annot = getAnnotationStore().getAnnotationById(id); 210 if (annot != null) { 211 if (! annot.isActionAllowed("delete", authUser)) { 212 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); 213 return null; 214 } 215 } 216 208 217 // delete annotation 209 218 getAnnotationStore().deleteById(id); -
src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java
r10 r14 141 141 Form requestHeaders = (Form) getRequest().getAttributes().get("org.restlet.http.headers"); 142 142 String authToken = requestHeaders.getFirstValue("x-annotator-auth-token", true); 143 if (authToken == null) return null; 143 144 // decode token first to get consumer key 144 145 JsonToken token = new JsonTokenParser(null, null).deserialize(authToken); … … 178 179 * 179 180 * @param annot 181 * @param forAnonymous TODO 180 182 * @return 181 183 */ 182 public JSONObject createAnnotatorJson(Annotation annot ) {184 public JSONObject createAnnotatorJson(Annotation annot, boolean forAnonymous) { 183 185 // return user as a JSON object (otherwise just as string) 184 186 boolean makeUserObject = true; … … 233 235 if (adminPerm != null) { 234 236 adminPerms.put(adminPerm.getIdString()); 237 } else if (forAnonymous) { 238 // set something because its not allowed for anonymous 239 adminPerms.put("not-you"); 235 240 } 236 241 // delete … … 240 245 if (deletePerm != null) { 241 246 deletePerms.put(deletePerm.getIdString()); 247 } else if (forAnonymous) { 248 // set something because its not allowed for anonymous 249 deletePerms.put("not-you"); 242 250 } 243 251 // update … … 247 255 if (updatePerm != null) { 248 256 updatePerms.put(updatePerm.getIdString()); 257 } else if (forAnonymous) { 258 // set something because its not allowed for anonymous 259 updatePerms.put("not-you"); 249 260 } 250 261 // read -
src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorSearch.java
r4 r14 16 16 17 17 import de.mpiwg.itgroup.annotations.Annotation; 18 import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;19 18 20 19 /** … … 32 31 33 32 /** 34 * result for JSON content-type. optional search parameters: uri user limit35 * offset 33 * result for JSON content-type. optional search parameters: uri, user, limit, 34 * offset. 36 35 * 37 36 * @param entity … … 42 41 logger.debug("AnnotatorSearch doGetJSON!"); 43 42 setCorsHeaders(); 44 // TODO: what to do with authentication?45 boolean authenticated = isAuthenticated(entity);46 logger.debug("request authenticated=" + auth enticated);43 // do authentication 44 String authUser = this.checkAuthToken(entity); 45 logger.debug("request authenticated=" + authUser); 47 46 48 47 Form form = getRequest().getResourceRef().getQueryAsForm(); 49 48 String uri = form.getFirstValue("uri"); 50 49 String user = form.getFirstValue("user"); 51 52 50 String limit = form.getFirstValue("limit"); 53 51 String offset = form.getFirstValue("offset"); 54 52 55 AnnotationStore searcher = getAnnotationStore(); 56 57 JSONArray ja; 58 59 List<Annotation> annots = searcher.searchByUriUser(uri, user, limit, offset); 60 61 ja = new JSONArray(); 53 JSONArray results = new JSONArray(); 54 // do search 55 logger.debug(String.format("searching for uri=%s user=%s", uri, user)); 56 List<Annotation> annots = getAnnotationStore().searchByUriUser(uri, user, limit, offset); 62 57 for (Annotation annot : annots) { 63 JSONObject jo = createAnnotatorJson(annot); 58 // check permission 59 if (!annot.isActionAllowed("read", authUser)) continue; 60 JSONObject jo = createAnnotatorJson(annot, (authUser == null)); 64 61 if (jo != null) { 65 ja.put(createAnnotatorJson(annot));62 results.put(jo); 66 63 } else { 67 64 setStatus(Status.SERVER_ERROR_INTERNAL, "JSON Error"); … … 69 66 } 70 67 } 71 68 // assemble result object 72 69 JSONObject result = new JSONObject(); 73 70 try { 74 result.put("rows", ja);75 result.put("total", ja.length());71 result.put("rows", results); 72 result.put("total", results.length()); 76 73 } catch (JSONException e) { 77 e.printStackTrace();78 74 setStatus(Status.SERVER_ERROR_INTERNAL, "JSON Error"); 79 75 return null;
Note: See TracChangeset
for help on using the changeset viewer.