Nuxeo Annotation Service

Table of Contents

56.1. Introduction
56.1.1. W3C Annotea
56.1.2. Logical architecture overview
56.1.3. XPointer integration and extension.
56.2. Annotation Service Core
56.2.1. Overview
56.2.2. Implementation
56.2.3. Storage
56.2.4. uriResolver
56.2.5. urlPatternFilter
56.2.6. metadata
56.2.7. permissionManager and permissionMapper
56.2.8. annotabilityManager
56.2.9. UID Generation
56.2.10. Event management
56.3. NXAS Repository Plugin
56.3.1. Overview
56.3.2. Default contribution
56.3.3. Extension Point
56.3.4. documentEventListener
56.3.5. securityManager
56.3.6. jcrLifecycleEventId and graphManagerEventListener
56.4. NXAS Web
56.4.1. Overview
56.4.2. Extension Point
56.4.3. Configuration
56.5. Annotation Service Facade
56.6. Annotation Service HTTP Gateway
56.6.1. Overview
56.7. References

56.1. Introduction

56.1.1. W3C Annotea

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.

56.1.2. Logical architecture overview

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.

56.1.3. XPointer integration and extension.

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.

56.2. Annotation Service Core

56.2.1. Overview

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.

URI, URL and URN

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.

56.2.2. Implementation

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)
        

Implementation Note

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.

56.2.3. Storage

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.

56.2.4. uriResolver

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:***".

56.2.5. urlPatternFilter

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>

56.2.6. metadata

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.

56.2.7. permissionManager and permissionMapper

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>

56.2.8. annotabilityManager

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.

56.2.9. UID Generation

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() .

56.2.10. Event management

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.

56.3. NXAS Repository Plugin

56.3.1. Overview

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.

Querying using a DocumentModel

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.

56.3.2. Default contribution

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 ” ).

56.3.2.1. permissionMapper

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>

56.3.2.2. uriResolver

The defaultNuxeoUriResolver transform the URI if it points to a Nuxeo document. The URI becomes a URN using the docId and repository name.

56.3.2.3. metadataMapper

In addition to the default mapper, the DefaultNuxeoMetadataMapper add the company of the user.

56.3.2.4. permissionMapper

The name of permission are the same as the document permission.

56.3.2.5. annotabilityManager

The contribution to the annotability manager will call the documentAnnotabilityManager.

56.3.2.6. eventListener

The contribution to the eventListener will call the corresponding AnnotatedDocumentEventListener.

56.3.3. Extension Point

56.3.3.1.  documentAnnotability

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.

56.3.4. documentEventListener

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.

56.3.5. securityManager

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.

56.3.6.  jcrLifecycleEventId and graphManagerEventListener

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.

56.4. NXAS Web

56.4.1. Overview

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.

Implementation Note

56.4.2. Extension Point

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.

56.4.3. Configuration

56.4.3.1. Panel Element

The client uses a div with id "display" to add the annotation application to the current page.

56.4.3.2. Preview setting

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.

56.5. Annotation Service Facade

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)
      

56.6. Annotation Service HTTP Gateway

56.6.1. Overview

The Annotation Service HTTP gateway provides the http API on top of the java APi of the Annotation Service It is a servlet that implements the annotea protocol.

56.7. References