1 Architecture logicielle : points clefs
1.1 OSGI et Nuxeo
Nuxeo s'appuie sur la norme OSGI pour déployer ses services.
Les services sont découpés en composants « packagés » dans des bundles OSGI. Au démarrage du serveur d'application, ils sont chargés dans l'ordre défini par les règles de configuration.
1.2 Les composants de configuration <XML/>
La configuration des services existant se fait en déclarant des composants rédigés sous forme de fichiers XML. Ces fichiers sont embarqués dans les Bundles OSGI. Sans écrire une ligne de code JAVA, le développeur peut tout à fait réaliser une extension de Nuxeo permettant :
-
de contribuer à un nouveau document ;
-
de l'associer à un cycle de vie spécifique ;
-
de construire les formulaires de création, de consultation et de modification ; ...
1.3 SEAM et JSF
La couche présentation est assurée par le framework JSF. En articulation des services et de JSF, Nuxeo a fait le choix de SEAM. Il agit comme un chef d’orchestre :
-
les vues JSF (pages web ou portions de pages) accèdent aux composants applicatifs par l’intermédiaire de Seam ;
-
les composants applicatifs accèdent à d’autres composants applicatifs par l’intermédiaire de Seam ;
-
les composants applicatifs accèdent aux entités persistantes du modèle par le contexte Seam.
1.4 Le langage de requête NXQL
Tous les contenus de Nuxeo sont enregistrés dans le référentiel documentaire. Nuxeo a développé un pseudo langage SQL permettant d'interroger le fond documentaire au moyen de requêtes dites NXQL.
SELECT * FROM Document WHERE dc:contributor = 'oadam' ORDER BY dc:modifed DESC
La requête ci-dessus liste les documents auxquels l'utilisateur « oadam » a contribué et les trie selon leur dernière date de modification (cf http://doc.nuxeo.com/display/NXDOC/NXQL).
1.5Le service Content Automation
Content Automation est un service de Nuxeo qui expose des actions de gestion de contenus sous formes d'opérations unitaires. Elles peuvent être assemblées pour créer des règles métiers plus complexes sans le moindre code JAVA.
Ces opérations sont exposées sous forme d'URL REST. Un client « Automation » interagira avec elles en forgeant des requêtes HTTP JSON (figure 1). Cf http://doc.nuxeo.com/display/NXDOC56/Using+the+REST+API+-+Examples. Une librairie JAVA « nuxeo-automation-client » est fournie par Nuxeo pour interfacer la fabrication des requêtes « automation ». Nous l'utilisons pour les interactions portail/portlet avec Nuxeo.
Il est possible d'enrichir le catalogue d'opérations pour répondre à des besoins de traitements spécifiques. Le développement devra être réalisé par un développeur JAVA.
Le service Content Automation
2 Développer, adapter Nuxeo
2.1 Surcharger, développer un service
Voici, en exemple, le point d'extension nous permettant de remplacer l'implémentation par défaut du service « userworkspaceservice » par une implémentation spécifique de l'académie de Rennes. Pour gérer la génération des espaces personnels de nos 300 000 usagers potentiels, nous avons surchargé le service existant pour éviter d'avoir tous les espaces dans le même conteneur. Une logique a été implémentée pour les ranger dans une arborescence structurée de la façon suivante : /home/o/a/d/oadam.
<?xml version="1.0"?>
<component name="fr.gouv.education.acrennes.ged.userworkspaceservice">
<extension target="org.nuxeo.ecm.platform.userworkspace.UserWorkspaceService" point="userWorkspace">
<userWorkspace class="fr.gouv.education.acrennes.ged.userworkspace.AcarenUserWorkspaceService" />
</extension>
</component>
Le livrable de cette extension consiste en un bundle OSGI contenant la configuration ci-dessus et la classe implémentant l'extension du service. Il est évidement nécessaire de configurer le bundle pour qu'il se charge après celui du service de base de Nuxeo.
2.2 « Customiser » l'interface utilisateur : intégration SEAM et JSF
Toujours dans l'esprit d'étendre le comportement de Nuxeo, il est possible de remplacer un bean SEAM existant par un autre :
-
ce bean devra étendre le précédent ;
-
le nom SEAM du bean devra être le même que le précédent (annotation @Name) ;
-
l'annotation « Install » devra spécifier la règle d'installation du composant SEAM. La propriété « precedence » doit être fixée à « Install.DEPLOYMENT » pour que ce bean remplace le précédent ;
-
ce bean devra être « packagé » dans un bundle OSGI chargé après celui contenant le bean étendu.
Il est aussi possible de remplacer une page ou un fragment JSF par un autre.
Nous avons, par exemple, surchargé le bean SEAM permettant d'insérer des images dans des contenus HTML (Note, Annonce, Article) au moyen de l'éditeur riche embarqué dans Nuxeo, TinyMCE. L’objectif est de pouvoir rechercher prioritairement des images dans l'espace de travail ou personnel ou de publication courant et aussi de pouvoir afficher les images jointes au document courant.
@Name("editorImageActions")
@Scope(CONVERSATION)
@Install(precedence = Install.DEPLOYMENT)
public class AcarenEditorImageActionsBean extends EditorImageActionsBean {
@Override
public String searchImages() throws ClientException {
//Extension Académie de Rennes
}
En complément, nous avons surchargé la page JSF correspondant à cette vue afin de présenter ces fonctionnalités.
2.3 Ajouter une opération au service Content Automation
Développer une opération pour interfacer un traitement dans les chaînes d'opérations consiste à créer une classe JAVA.
L'annotation @Operation permet d’enregistrer l'opération dans le service Content Automation.
@Operation(id = GetNbPagePDFFile.ID, category = Constants.CAT_BLOB, label = "Get the page number of pdf.", description = "Get the page number of a 'blob' is a pdf file. The number of page is accessible via the context variable 'nbpage' if there is not xpathnbpage specifie. ")
Les paramètres sont aussi spécifiés par annotation.
@Param(name = "xpathBlob", required = true, order = 0)
protected String xpathblob;
La classe doit implémenter une méthode annotée « OperationMethod ». Cette méthode réalisera le traitement attendu. Dans le cas où l'opération modifie un document, il est nécessaire que la méthode prenne un objet « DocumentModel » en paramètre et le retourne.
@OperationMethod()
public DocumentModel run(DocumentModel doc) throws Exception {
//Traitement pour compter le nombre de pages d'un fichier PDF
return doc;
}