Table of Contents
Nuxeo Annotation service is based on Annotea W3C specification. It is compliant with the specification published at Annotea Protocol .
However the annotea specification is quite old and does not handle all use cases for annotating documents in the context of Nuxeo ECM. Therefore, we propose to provide some extensions to annotea. Using the repository plugin, it provides a plugable system to be able to keep track of the relationship between an annotated URL and the underlying nuxeo document.
Inside Nuxeo EP we need to be able to annotate the HTML preview of a document. This preview may include images. This images are annotable as the rest of the document, but it requires an extension to the Xpointer specification since user may want to annotate just a portion (zone) of the image.
This section provides an overview of the logical architecture of the Nuxeo Annotation service.
Annotation Service API
nuxeo-platform-annotations-api
Provides Java API and all the needed Java artifacts needed to call the Annotation service remotely.
Annotation Service Core
nuxeo-platform-annotations-core
Provides the Nuxeo Service that exposes the required annotation Java Interface. This service is implemented as a Nuxeo Runtime component and will provide the needed extension points .
Annotation Service Facade
nuxeo-platform-annotations-facade
Provides the service EJB3 facade for remote (RMI) access.
Annotation Service Http gateway
nuxeo-platform-annotations-http
The HTTP Gateway implements the Annotea HTTP protocol. It is implemented as a servlet that enable access to the annotation service via http GET/POST requests as defined in the W3C Annotea specification.
Annotation Service Web Interface
nuxeo-platform-annotations-web
The web interface provides ways to annotate document.
Annotea uses XPointer to annotates part of a web pages. We added a image-range function to XPointer to be able to annotates part of an image. A XPointer using image-range looks like: "http://example.com/foo.html#xpointer(image-range(/html[1]/body[0]/img[0],[79,133],[123,159]))". The form is "image-range(location-set , [tlX,tlY], [brX,brY])", with the location-set defined in the XPointer documentation, pointing to an image. tlX, tlY, brX and brY are integer for the top left X, top left Y, bottom right X and bottom right Y coordinates of a square within the annotated original image (as stored on the server). That is, if the size of the image is dynamically modified using Javascript, an image-range should always point to the same area of the image.
This is the main component of NXAS, the one that contains all the logic for managing RDF based annotations. The Core Service is not document aware and manages only URIs.
A URL is "http://foo.com/index.html", a URN doesn't use a protocol: "nuxeo:default:12345678". A URI is a URL or a URN.
This component is also responsible for exposing all the needed extension points that will be used for configuration and integration.
The service is implemented as a Runtime service on top of a Nuxeo Runtime component. The runtime component provides the extension point mechanisms. The API provided by the service will target managing annotations on URLs.
As any Nuxeo Service, the Annotation Service is accessible via the Runtime lookup method :
Framework.getLocalService(AnnotationService.class)
The core function of the annotation service is to add/remove/query annotations from the RDF Graph. It also has to provide security and add configurability. The implementation separates those 2 functions in 2 classes: The AnnotationServiceProxy class implements all the configuration, event management and security function and let the AnnotationServiceImpl provides the core RDF service.
The Annotation service stores the annotations as a RDF graph. Nuxeo Relation Service is responsible for storing and managing the RDF data. The service uses a graph named "annotations". The default contribution is:
<component name="org.nuxeo.ecm.annotations.graph"> <require>org.nuxeo.ecm.platform.relations.jena</require> <extension target="org.nuxeo.ecm.platform.relations.services.RelationService" point="graphs"> <graph name="annotations" type="jena"> <option name="backend">sql</option> <option name="databaseType">${org.nuxeo.ecm.sql.jena.databaseType}</option> <option name="databaseTransactionEnabled"> ${org.nuxeo.ecm.sql.jena.databaseTransactionEnabled} </option> <option name="datasource">java:/nxrelations-default-jena</option> <namespaces> <namespace name="rdf">http://www.w3.org/1999/02/22-rdf-syntax-ns#</namespace> <namespace name="dcterms">http://purl.org/dc/terms/</namespace> <namespace name="nuxeo">http://www.nuxeo.org/document/uid/</namespace> </namespaces> </graph> </extension> </component>
Refer to the Relation Service documentation ( Chapter 24, Relations ) for more information on configuration options.
The uriResolver extension point allows to contribute a class that is responsible for resolving uri. It maps URI sent by the client to URI stored in the graph. It also allows to translate a URI in a list of URIs when querying the graph.
This allows to consider annotations on different URLs to be considered as annotations on the same document, therefore being able to see those annotations on both URLs.
To contribute a uriResolver contribute to the extension point a class that implements the UriResolver interface. The default contribution is:
<extension target="org.nuxeo.ecm.platform.annotations.services.AnnotationsService" point="uriResolver"> <urlResolver class="org.nuxeo.ecm.platform.annotations.service.DefaultUriResolver"/> </extension>
The DefaultUriResolver maps URI without changing them, unless it includes "nuxeo/Annotations" in its URL. In such a case, it transform the URL in a URN of the form "urn:annotation:***".
The urlPatternFilter extension point allows to contribute regular expression pattern to the list of allowed URL pattern or disallowed URL pattern. When a request is made to get/set annotations on an URL, the server check the list.
The check is done before any transformation on the URL. Because the check on URL is done very early in the processing of a request, to increase performance, it is recommended to use it whenever possible.
The filter follows Apache's mod_access convention to filter URL. The default contribution is:
<extension target="org.nuxeo.ecm.platform.annotations.services.AnnotationsService" point="urlPatternFilter"> <urlPatternFilter order="Deny,Allow"> <deny>.*</deny> <allow>.*</allow> </urlPatternFilter> </extension>
The metadata extension point allows to add metadata to an annotations when it is created. The contribution needs to implement the MetadataMapper interface. It is passed the annotation to which it can add the metadata. The default contribution:
<extension target="org.nuxeo.ecm.platform.annotations.services.AnnotationsService" point="metadataMapper"> <metadataMapper class="org.nuxeo.ecm.platform.annotations.service.DefaultMetadataMapper"> </extension>
This contribution adds the date and creator to the annotation. Note that you can add metadata and modify the annotation before sending it to the service. You could choose to add the creation time using the local time of the client and add it to the annotation without using the metadatMapper.
The permissionManager extension point allows to contribute a class that checks before CRUD operations. The permissionMapper will maps permission name with operation.
The permissionMapper extension point allows to contribute the name of the permission to check before a CRUD operation. The default contribution is:
<extension target="org.nuxeo.ecm.platform.annotations.services.AnnotationsService" point="permissionMapper"> <permissionMapper> <createAnnotation>createAnnotation</createAnnotation> <readAnnotation>readAnnotation</readAnnotation> <updateAnnotation>updateAnnotation</updateAnnotation> <deleteAnnotation>deleteAnnotation</deleteAnnotation> </permissionMapper> </extension>
The permissionManager extension point allows to contribute a class to check before CRUD operations. The default permission manager allows all operations to everybody:
<extension target="org.nuxeo.ecm.platform.annotations.services.AnnotationsService" point="permissionManager"> <permissionManager class="org.nuxeo.ecm.platform.annotations.service.DefaultPermissionManager"/> </extension>
The annotabilityManager extension point allows to
contribute a class to fine grain which documents can be
annotated. An implementation needs to implement the
interface
AnnotabilityManager
. The default annotability manager is:
<extension target="org.nuxeo.ecm.platform.annotations.services.AnnotationsService" point="annotabilityManager"> <annotabilityManager class="org.nuxeo.ecm.platform.annotations.service.DefaultAnnotabilityManager"/> </extension>
It allows annotations on all URL.
When an annotation is created it is given a UID. This extension point allows to contribute a UID generator. The default contribution is:
<extension target="org.nuxeo.ecm.platform.annotations.services.AnnotationsService" point="annotationIDGenerator"> <IDGenerator class="org.nuxeo.ecm.platform.annotations.service.DefaultIDGenerator"/> </extension>
This default contribution create a UID using java
java.util.UUID.randomUUID()
.
The eventManager extension point allows to contribute a
listener class to handle annotation related events. The
listener class has to implement the interface.
EventListener
. There is one method for each CRUD operation, before
and after the operation. The calls are made
synchronously. There is no default contribution to this
extension point.
NXAS core offers an implementation of an Annotea Server. It is "pure" RDF and relies on URI for resource identification. However, Nuxeo deals with versionned document. The repository plugin allows to contribute to the core module using Nuxeo's object of DocumentModel, ACP and Version.
The repository plugin contribute to Core NXAS, replacing most of the default contribution. You can then contribute to the repository plugin to tune security, annotability and more.
The Annotation Service uses URI exclusively, if you need to query using a DocumentModel, you need to obtain the URN for this document:
URNDocumentViewTranslator translator = new URNDocumentViewTranslator(); String documentId = documentModel.getId(); String serverName = coreSession.getRepositoryName(); URI uri = translator.getNuxeoUrn(serverName, documentId);
You can then use the uri for the query method.
This section describes the default contribution made to the annotation service. You should not change them if you use the repository plugin. To modify the repository plugin behavior, use its extension point ( Section 56.3.3.1, “ documentAnnotability ” ).
The permission are mapped to the document that is being annotated:
<extension target="org.nuxeo.ecm.platform.annotations.services.AnnotationsService" point="permissionMapper"> <permissionMapper> <createAnnotation>updateDocument</createAnnotation> <readAnnotation>viewDocument</readAnnotation> <updateAnnotation>updateDocument</updateAnnotation> <deleteAnnotation>deleteDocument</deleteAnnotation> </permissionMapper> </extension>
The defaultNuxeoUriResolver transform the URI if it points to a Nuxeo document. The URI becomes a URN using the docId and repository name.
In addition to the default mapper, the DefaultNuxeoMetadataMapper add the company of the user.
The contribution to the annotability manager will call the documentAnnotabilityManager.
The documentAnnotability extension point allows to
choose which document are annotable. To contribute
to this point, create a class that implement
DocumentAnnotability
. The default implementation is (
DefaultDocumentAnnotability
), allows annotations on all documents.
The documentEventListener allows to contribute class that would be notify when an annotation is create, updated, read and deleted. Notification comes synchronously before and after the event. It is passed as parameter the annotation and the DocumentLocation of the the document being annoted.
A default contribution notify the JMS bus.
The security manager extension point allows to contribute a class that implements the SecurityManager interface. It fine grains security using NuxeoPrincipal, the permission checked and the DocumentMode.
The jcrLifecycleEventId and graphManagerEventListener allows to modify the RDF graph when an event happens in the repository. The jcrLifecycleEventId list the jms event we listen to. The graphManagerEventListener extension point allows to contribute a class that would be called when such event are received.
The default implementation is DocumentVersionnedGraphManager. It listens to the documentCheckedIn event. This event is sent when a new UUID is created for a document. The manager add, to each annotation that annotates the old UID, a new annotates statement with the new UID. The result is that when you version a document, the old version will have the same annotation than the new version, but annotation on the new version will not be seen in the old version.
The NXAS HTML Client is the a web interface that can be used by the end user. It is written in GWT. It can be configured in two ways. The "normal" Nuxeo way of extension point, or adding attribute or object to the html page to be read by the gwt module.
The WebAnnotationConfigurationService allows to contribute:
the different types of annotations you want to manage in your application. The default contribution provides the 6 annotea protocols types: SeeAlso, Question, Explanation, Example, Comment, Change and Advice.
the filters you may want to use in your application. They are displayed as button on the left side. The default contribution shows no filter.
the displayed fields: fields you want to display in the annotations list in addition to the icon and the date.
a class implementing the UserInfoMapper
interface to add to the WebConfiguration
some informations about the current user.
a class implementing the WebPermission
interface to let know to the client
if annotations are allowed or not on the current document.
For more informations and examples, see the files web-configuration-service-contrib.xml
and web-configuration-service-framework.xml
located in the nuxeo-platform-annotations-web
project.
The client uses a div with id "display" to add the annotation application to the current page.
To allow integration with the preview module, additional configuration is possible via a div with an id of "preview-setting". Each configuration is an attribute of the div.
imageOnly value should be true or false. If only the image should be annotated in the frame.
multipleImageAnnotation should be true or false. If more than one image should be annotated.
The annotation module uses 2 functions to transform the xpointer gotten from clicking on an image, and to transform a xpointer to a xpointer that make sens in the previewed image. It get the function from top[xPointerFilterPath] and top [pointerAdapter]. xPointerFilterPath and pointerAdapter are the value of the same named attribute.
The facade provides the integration of the service into JEE infrastructure. EJB3 Stateless Session Bean facade on top of the runtime service. This makes the Annotation Service remotable and accessible via the standard Nuxeo Lookup facility :
Framework.getService(AnnotationService.class)