/** * {@inheritDoc} <br> * Implementation which gets all the annotation class objects in the document pointed by the * target, and matches their ids against the ids in the passed collection of annotations. If they * match, they are updated with the new data in the annotations in annotation. * * @see org.xwiki.annotation.io.IOService#updateAnnotations(String, java.util.Collection) */ @Override public void updateAnnotations(String target, Collection<Annotation> annotations) throws IOServiceException { try { EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT); // get the document name from the parsed reference String docName = target; if (targetReference.getType() == EntityType.DOCUMENT || targetReference.getType() == EntityType.OBJECT_PROPERTY) { docName = serializer.serialize(targetReference.extractReference(EntityType.DOCUMENT)); } // get the document pointed to by the target XWikiContext deprecatedContext = getXWikiContext(); XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext); List<String> updateNotifs = new ArrayList<String>(); boolean updated = false; for (Annotation annotation : annotations) { // parse annotation id as string. If cannot parse, then ignore annotation, is not valid int annId = 0; try { annId = Integer.parseInt(annotation.getId()); } catch (NumberFormatException e) { continue; } BaseObject object = document.getXObject(configuration.getAnnotationClassReference(), annId); if (object == null) { continue; } updated = updateObject(object, annotation, deprecatedContext) || updated; updateNotifs.add(annotation.getId()); } if (updated) { // set the author of the document to the current user document.setAuthor(deprecatedContext.getUser()); deprecatedContext .getWiki() .saveDocument(document, "Updated annotations", deprecatedContext); // send annotation update notifications for all annotations set to notify for ObservationManager observationManager = componentManager.lookup(ObservationManager.class); for (String updateNotif : updateNotifs) { observationManager.notify( new AnnotationUpdatedEvent(docName, updateNotif), document, deprecatedContext); } } } catch (XWikiException e) { throw new IOServiceException("An exception has occurred while updating the annotation", e); } catch (ComponentLookupException exc) { this.logger.warn( "Could not get the observation manager to send notifications about the annotation update"); } }
/** * {@inheritDoc} <br> * This implementation deletes the annotation object with the object number indicated by {@code * annotationID} from the document indicated by {@code target}, if its stored target matches the * passed target. * * @see org.xwiki.annotation.io.IOService#removeAnnotation(String, String) */ @Override public void removeAnnotation(String target, String annotationID) throws IOServiceException { try { if (annotationID == null || target == null) { return; } EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT); // get the target identifier and the document name from the parsed reference String localTargetId = target; String docName = target; if (targetReference.getType() == EntityType.DOCUMENT || targetReference.getType() == EntityType.OBJECT_PROPERTY) { localTargetId = localSerializer.serialize(targetReference); docName = serializer.serialize(targetReference.extractReference(EntityType.DOCUMENT)); } // get the document XWikiContext deprecatedContext = getXWikiContext(); XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext); if (document.isNew()) { // if the document doesn't exist already skip it return; } // and the document object on it BaseObject annotationObject = document.getXObject( configuration.getAnnotationClassReference(), Integer.valueOf(annotationID.toString())); // if object exists and its target matches the requested target, delete it if (annotationObject != null && localTargetId.equals(annotationObject.getStringValue(Annotation.TARGET_FIELD))) { document.removeObject(annotationObject); document.setAuthor(deprecatedContext.getUser()); deprecatedContext .getWiki() .saveDocument(document, "Deleted annotation " + annotationID, deprecatedContext); // notify listeners that an annotation was deleted ObservationManager observationManager = componentManager.lookup(ObservationManager.class); observationManager.notify( new AnnotationDeletedEvent(docName, annotationID), document, deprecatedContext); } } catch (NumberFormatException e) { throw new IOServiceException("An exception has occurred while parsing the annotation id", e); } catch (XWikiException e) { throw new IOServiceException("An exception has occurred while removing the annotation", e); } catch (ComponentLookupException exc) { this.logger.warn( "Could not get the observation manager to send notifications about the annotation delete"); } }
/** * {@inheritDoc} <br> * This implementation retrieves all the objects of the annotation class in the document where * target points to, and which have the target set to {@code target}. * * @see org.xwiki.annotation.io.IOService#getAnnotations(String) */ @Override public Collection<Annotation> getAnnotations(String target) throws IOServiceException { try { // parse the target and extract the local reference serialized from it, by the same rules EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT); // build the target identifier for the annotation String localTargetId = target; // and the name of the document where it should be stored String docName = target; if (targetReference.getType() == EntityType.DOCUMENT || targetReference.getType() == EntityType.OBJECT_PROPERTY) { localTargetId = localSerializer.serialize(targetReference); docName = serializer.serialize(targetReference.extractReference(EntityType.DOCUMENT)); } // get the document XWikiContext deprecatedContext = getXWikiContext(); XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext); // and the annotation class objects in it List<BaseObject> objects = document.getXObjects(configuration.getAnnotationClassReference()); // and build a list of Annotation objects List<Annotation> result = new ArrayList<Annotation>(); if (objects == null) { return Collections.<Annotation>emptySet(); } for (BaseObject object : objects) { // if it's not on the required target, ignore it if (object == null || !localTargetId.equals(object.getStringValue(Annotation.TARGET_FIELD))) { continue; } // use the object number as annotation id result.add(loadAnnotationFromObject(object, deprecatedContext)); } return result; } catch (XWikiException e) { throw new IOServiceException("An exception has occurred while loading the annotations", e); } }
@Override public Annotation getAnnotation(String target, String annotationID) throws IOServiceException { try { if (annotationID == null || target == null) { return null; } // parse the target and extract the local reference serialized from it, by the same rules EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT); // build the target identifier for the annotation String localTargetId = target; // and the name of the document where it should be stored String docName = target; if (targetReference.getType() == EntityType.DOCUMENT || targetReference.getType() == EntityType.OBJECT_PROPERTY) { localTargetId = localSerializer.serialize(targetReference); docName = serializer.serialize(targetReference.extractReference(EntityType.DOCUMENT)); } // get the document XWikiContext deprecatedContext = getXWikiContext(); XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext); // and the annotation class objects in it // parse the annotation id as object index BaseObject object = document.getXObject( configuration.getAnnotationClassReference(), Integer.valueOf(annotationID.toString())); if (object == null || !localTargetId.equals(object.getStringValue(Annotation.TARGET_FIELD))) { return null; } // use the object number as annotation id return loadAnnotationFromObject(object, deprecatedContext); } catch (NumberFormatException e) { throw new IOServiceException("Could not parse annotation id " + annotationID, e); } catch (XWikiException e) { throw new IOServiceException( "An exception has occurred while loading the annotation with id " + annotationID, e); } }
/** * {@inheritDoc} <br> * This implementation saves the added annotation in the document where the target of the * annotation is. * * @see org.xwiki.annotation.io.IOService#addAnnotation(String, org.xwiki.annotation.Annotation) */ @Override public void addAnnotation(String target, Annotation annotation) throws IOServiceException { try { // extract the document name from the passed target // by default the fullname is the passed target String documentFullName = target; EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT); // try to get a document reference from the passed target reference EntityReference docRef = targetReference.extractReference(EntityType.DOCUMENT); if (docRef != null) { documentFullName = serializer.serialize(docRef); } // now get the document with that name XWikiContext deprecatedContext = getXWikiContext(); XWikiDocument document = deprecatedContext.getWiki().getDocument(documentFullName, deprecatedContext); // create a new object in this document to hold the annotation int id = document.createXObject(configuration.getAnnotationClassReference(), deprecatedContext); BaseObject object = document.getXObject(configuration.getAnnotationClassReference(), id); updateObject(object, annotation, deprecatedContext); // and set additional data: author to annotation author, date to now and the annotation target object.set(Annotation.DATE_FIELD, new Date(), deprecatedContext); // TODO: maybe we shouldn't trust what we receive from the caller but set the author from the // context. // Or the other way around, set the author of the document from the annotations author. object.set(Annotation.AUTHOR_FIELD, annotation.getAuthor(), deprecatedContext); // store the target of this annotation, serialized with a local serializer, to be exportable // and importable // in a different wiki // TODO: figure out if this is the best idea in terms of target serialization // 1/ the good part is that it is a fixed value that can be searched with a query in all // objects in the wiki // 2/ the bad part is that copying a document to another space will not also update its // annotation targets // 3/ if annotations are stored in the same document they annotate, the targets are only // required for object // fields // ftm don't store the type of the reference since we only need to recognize the field, not to // also read it. if (targetReference.getType() == EntityType.OBJECT_PROPERTY || targetReference.getType() == EntityType.DOCUMENT) { object.set( Annotation.TARGET_FIELD, localSerializer.serialize(targetReference), deprecatedContext); } else { object.set(Annotation.TARGET_FIELD, target, deprecatedContext); } // set the author of the document to the current user document.setAuthor(deprecatedContext.getUser()); deprecatedContext .getWiki() .saveDocument( document, "Added annotation on \"" + annotation.getSelection() + "\"", deprecatedContext); // notify listeners that an annotation was added ObservationManager observationManager = componentManager.lookup(ObservationManager.class); observationManager.notify( new AnnotationAddedEvent(documentFullName, object.getNumber() + ""), document, deprecatedContext); } catch (XWikiException e) { throw new IOServiceException( "An exception message has occurred while saving the annotation", e); } catch (ComponentLookupException exc) { this.logger.warn( "Could not get the observation manager to send notifications about the annotation add"); } }