Ce chapitre a pour objectif de décrire l'architecture logicielle de Lutece. Nous allons commencer par la description des différentes étapes de la requète HTTP d'un client à la réponse HTTP du serveur. Puis nous décrirons plus en détail l'organisation du code dans les différentes classes java, JSP, fichiers HTML et xsl. Enfin, nous verrons de manière exhaustive l'organisation de ces fichiers dans un projet lutece.
Le choix général d'architecture repose sur la spécification Java EE qui apporte un cadre aux applications d'entreprise n-tiers.
Les choix de la conception détaillée se sont portés sur une architecture en quatre couches côté serveur :
Le schéma suivant présente de manière simplifiée le processus de restitution d'un contenu Front Office. Le schema se lit de gauche à droite et représente les différentes étapes commençant à la requète HTTP du client et terminant à la réponse HTTP du serveur. Le schéma est suivi d'explications sur les différentes étapes, puis de descriptions détaillées des différentes couches.
Les différents composants sont representés par des symboles différents: ceux de la couche présentation par de simples rectangles, ceux de la couche service avec un engrenage, ceux de la couche métier et ceux de la couche d'accès au données par une feuille de papier.
Les couleurs indiquent en blanc les composants de lutece-core, en bleu les composants du plugin-document, un plugin standard de lutèce, et en vert des composants qui pourraient être apportés par un nouveau plugin.
Ce schema donne donc plusieurs exemples d'architecture dont on peut s'inspirer lors de l'écriture de nouveaux plugins.
Portal.jsp
est le point d'entrée de restitution. Portal.jsp
utilise une directive <jsp:useBean> pour charger un bean java (ici PortalJspBean
), ce qui permet d'écrire le code dans une classe java normale afin de faciliter la maintenance. PortalJspBean
implémente des méthodes correspondant à différentes opérations de l'utilisateurs, et délègue la plupart des fonctionnalités à des classes java de services : PortalService
, ContentService
, AppPropertiesService
, etc. Il n'est pour l'instant pas important de connaître tous ces services, et les plus importants seront présentés dans la suite de livre, mais l'organisation du code JSP/JSPBean/Service est un point central de Lutece.Content Service
. isInvoked
indiquant selon les paramètres HTTP si c'est ce service qui est demandé, et une methode getPage
renvoyant le contenu HTML en utilisant un cache. Les Content Services proviennent du coeur de Lutece ou de plugins. Content Services
:PageContentService
de lutece-core
, paramètres HTTP "page_id=n"
. Ce Content Service
gère les pages éditoriales du site. Ces pages sont configurées en back office en y organisant des portlets. Ces pages sont organisées en une arborescence du site Lutece reflétée dans les menus et le fil d'ariane.XPageAppService
de lutece-core
, paramètres HTTP "page=name"
. Ce Content Service
gère des pages autonomes appelée XPages
fournissant des fonctionnalités spécifiques. Le contenu est entièrement fabriqué par la classe java appelée et n'est généralement pas aussi éditable que les pages du PageContentService
avec leurs portlets.DocumentContentSerivce
de plugin-document, paramètres HTTP "document_id=n&porlet_id=m"
. Ce Content service est fourni par le plugin document qui propose dans Lutece des contenus typés (par exemple, article, brève, etc.) organisés autour d'un workflow de publication (gestion de la collaboration, de la validation).PageContentService
est demandée, le bean s'adresse au PageService
qui fournira la page si elle est dans son cache ou sinon il la construira. La construction d'une page fait appel à la classe PageHome
pour obtenir une instance de la page demandée. Ensuite, le contenu de chaque rubrique de la page est récupéré en XML puis transformé à l'aide de la feuille de style XSL associée, et agrégé pour constituer la page. La nouvelle page construite est alors mise dans le cache. Ici, le point important d'architecture est que les class services s'appuient sur des classes d'objets métiers, par exemple PageHome
et Page
, qui chargent leur données depuis des objets DAO (Data Access Object), par exemple PageDAO
.Cette couche est réalisée à l'aide de JSP, de Java Beans, éventuellement de servlets. Le code HTML est produit de deux manières :
XPages
), des fichiers contenant des modèles de représentation HTML appelés Templates
seront utilisés.Pour rappel, nous parlons ici de la catégorie à laquelle appartient Portal.jsp, le point d'entrée principal de restitution de contenus du Front Office.
De manière générale, le rôle attribué aux JSP est strictement limité à la gestion de la structure des pages et à la navigation. La partie HTML sera construite par des beans qui utiliseront des templates pour construire le code qui sera inséré dans les pages JSP.
Les JSP contiendront donc essentiellement :
<jsp:useBean>
qui charge un bean contenant la majorité du code. <%@ page errorPage="path/to/ErrorPage.jsp"%>
<jsp:include>
(ex : code HTML pour inclure une feuille de style)<jsp:forward>
)Tout code Java et HTML est proscrit dans ces pages.
Les JSP doivent toutes contenir une JSP d'entête et une JSP de fin de page. Ceci permet d'intégrer dans toutes les pages des traitements initiaux et finaux sans avoir à modifier l'ensemble des pages (ex : test du timeout de la session, entête et pied de page HTML, lien vers une feuille de style, ajout de traitements statistiques, ...).
Le Front Office n'utilise principalement que Portal.jsp, alors que le Back Office utilise de nombreuses JSP. Cela permet d'avoir plus d'homogénéité dans le Front Office et plus de flexibilité dans le Back Office.
Pour rappel, nous parlons ici de la catégorie à laquelle appartient PortalJspBean, le bean associé à la JSP Portal.jsp vue dans les exemples.
Ces beans sont chargés de gérer la présentation des informations issues des objets métier. Ils doivent notamment produire du code HTML qui sera inséré dans les JSP. Ces composants sont regroupés dans le package fr.paris.lutece.portal.web pour le coeur de lutece, fr.paris.lutece.plugins.*.web pour les plugins. et ont un suffixe JspBean pour les différencier des beans métier.
Les JSP beans peuvent être utilisés par plusieurs pages JSP traitant des mêmes informations, notamment pour partager des constantes.
La portée des JSP beans (attribut scope
dans la déclaration du bean dans la JSP) doit être soit session s'il contient des variables d'instance relative à la session de l'utilisateur (état conversationnel), soit request s'il n'a pas de variable d'instance. Dans certains cas, les scopes page
ou applications
sont aussi utilisés.
Les templates sont des fichiers .html contenant un template de code HTML et éventuellement Javascript. Le moteur de template utilisé est FreeMarker http://freemarker.org. Par exemple, le template principal associé à Portal.jsp est le fichier page_frameset.html
.
Après le templating Freemarker, certaines transformations additionnelles sont effectuées dans cet ordre :
1. Le traitement des libellés multilingue introduits sous la forme #i18n{key}.
La gestion de l'internationalisation (i18n) sera décrite plus loin dans un chapitre dédié.
2. Le traitement des libellés sous la forme #dskey{key}
dont les valeurs sont stockées en base de données (dans le datastore de Lutece).
3. Les traitements d'éventuels ContentPostProcessor
comme ceux des plugins plugin-extend ou plugin-seo.
L'avantage de ces templates est qu'ils peuvent être partagés par plusieurs JSP et qu'ils peuvent être modifiés par des concepteurs graphiques sans risque d'impact sur les traitements. Ces templates seront stockés dans le répertoire /WEB-INF/templates.
Les feuilles de style XSL servent à transformer les contenus XML en HTML. Par ce mécanisme, on sépare le contenu de la forme. Par simple changement de style les mêmes contenus peuvent être présentés de manière très différente.
La couche métier est réalisée par un ensemble de classes correspondant à des objets métiers.
Ces classes ne contiennent aucun code technique HTML ou SQL. Ces composants sont regroupés dans les packages fr.paris.lutece.portal.business.* pour le coeur et fr.paris.lutece.plugins.*.business.* pour les plugins.
La persistance de ces objets est assurée par des objets DAO (Data Access Object
) dont l'interface contient les principales méthodes d'accès aux données correspondant aux opérations SQL de base : load
(SELECT
), store
(UPDATE
), create
(INSERT
), delete
(DELETE
).
Nous avons décidé d'avoir une conception proche des Enterprise JavaBeans, et nous utilisons une classe "Home" pour chaque objet métier principal, c'est à dire disposant d'un DAO, inspirée des EJB Home Interface. Les prérogatives de ces classes sont, comme pour les EJB, d'assurer la gestion des instances de l'objet métier :
create()
)findByPrimaryKey()
)findByCritère()
)À ces méthodes qui figurent dans l'interface des classes Home des EJB entity, nous ajouterons les méthodes qui normalement correspondent à des actions gérées par le conteneur d'EJB. L'objet Home étant le seul objet ayant accès au DAO, c'est lui qui assurera les opérations de modification et de suppression des entités dans la base de données.
Les appels à ces méthodes seront effectués par le biais de méthodes update()
et remove()
au niveau de l'objet métier.
Voici le tableau récapitulatif des interfaces classiques des différents objets. Une ligne represente des méthodes liées, leur portée, et l'existance de cette méthode dans le modèle de programmation des EJB entity :
Objet Métier | Home | DAO | |||||
---|---|---|---|---|---|---|---|
Méthode | Portée | Méthode | Portée | EJB? | Méthode | Portée | EJB? |
create |
public | X | insert |
package | X | ||
findByPrimaryKey |
public | X | load |
package | X | ||
finbBy... |
public | X | selectBy |
package | X | ||
Update | public | update |
package | store |
package | X | |
Remove | public | remove |
package | delete |
package | X |
Une recommandation importante de la conception d’EJB entity est d’avoir une granularité assez grosse, c'est à dire que tout objet métier ne doit pas nécessairement être implémenté sous la forme d’un EJB entity. Tous les objets métiers dépendant d’un objet métier principal, et particulièrement dans le cas où il est en lecture seule, doivent être implémentés sous la forme d’une classe simple. La lecture de cet objet sera alors réalisée au niveau du DAO de l’objet principal.
Les services servent à implémenter des fonctionnalités qui ne sont pas directement reliées à la création et modification d'un objet métier et de ses données. C'est souvent la partie la plus importante en termes de répartition de fonctionnalités d'une application.
C'est dans cette catégorie que se trouvent les Content Services, qui implémentent le framework dans lequel la majorité des contenus du Front Office sont restitués: PageContentService et XPageAppService.
Un certain nombre de services techniques fournis par le coeur sont accessibles à partir des composants de l’application : Par exemple:
Service | Description |
---|---|
AppTemplateService | Renvoie un modèle HTML à partir de son nom. Ce service dispose d’un cache activable qui permet de ne pas relire sur disque un modèle qui a déjà été demandé. |
AppConnectionService | Fourniture de connexions à la base données à partir d’un pool. Ce service est paramétrable pour utiliser soit le pool du serveur d’application, soit un pool de connexions autonome. |
AppPropertiesService | Renvoie les valeurs des variables définies dans les fichiers properties des répertoires /WEB-INF/conf/ et /WEB-INF/conf/plugins/ |
MailService.java | Permet l'envoi de mail en format text ou html, avec gestion d'évenements de calendrier. |
I18nService.java | Gère la traduction de chaines de caractères en fonction du choix de l'utilisateur |
AppLogService.java | Gère les logs avec différents niveaux de sévérité, différents loggers |
XmlTransformerService.java | Gère l'application de feuilles de styles XSL pour transformer des contenus XML. |
Il ne s'agit pas ici de donner une liste exhaustive des différents services du coeur, car la nature des services fait que des fonctionnalités très variées sont y sont implémentées. Il est conseillé de parcourir le code du coeur et de plugins incontournables (par exemple plugin-document, plugin-directory) pour avoir des exemples de fonctionnalités à regrouper dans des classes de services.
Les requêtes SQL écrites dans les fichiers DAO doivent être compatible avec la norme SQL92.
Les requêtes SQL et les types de colonnes dans les scripts de création de la base de données doivent être compatibles avec les bases de données MySQL ou MariaDB. Le système de Lutece de création de la base de données basé sur Ant assure une transcription pour les SGDB PostgreSQL, HSQLDB et Oracle.
L’arborescence des répertoires dans le projet source de Lutece core est définie comme suit et intègre les spécifications JEE - Servlet 2.5.
Localisation | Type de fichier | Description |
---|---|---|
src/java | *.java | Les sources de l’application |
src/sql | *.sql | Les scripts de création de base et d’initialisation de l’application |
<webapp>/css | *.css | Feuille de style CSS par défaut utilisée par l’application |
<webapp>/images | *.gif,*.jpg,*.png | L'ensemble des pictogrammes utilisés par l’application |
<webapp>/js | *.js | Fichiers javascripts utilisés dans l’ensemble de l’application |
<webapp>/jsp/admin | *.jsp | Les Java Server Pages du module d’administration de l’application |
<webapp>/jsp/admin/plugins | *.jsp | Les Java Server Pages de la fonctionnalité de gestion des plugins du module d’administration |
<webapp>/jsp/site | *.jsp | Les Java Server Pages de la partie site de l’application |
<webapp>/WEB-INF | web.xml | Fichier de configuration de l’application web (specs Servlet 2.5). Contient la déclaration des servlets de l’application |
<webapp>/WEB-INF/conf | *.properties |
|
<webapp>/WEB-INF/index | _*.f* et autres | Les index du moteur de recherche Lucene pour le site de l’application |
<webapp>/WEB-INF/indexall | _*.f* et autres | Les index du moteur de recherche Lucene pour un ensemble de sites définis dans le fichier config.properties |
<webapp>/WEB-INF/lib | *.jar | Les fichiers archive contenant les classes importées dans l’application ainsi que ceux de lutece core. (specs Servlet 2.5) |
<webapp>/WEB-INF/logs | *.logs | Les logs de l’application. |
<webapp>/WEB-INF/taglibs | *.tld | Fichiers taglibs utilisés dans l’application |
<webapp>/WEB-INF/templates/admin et sous répertoires | *.html | Les modèles HTML utilisés pour la construction dynamique des pages. Il s’agit de blocs de code HTML utilisés par les beans de présentation du module d’administration |
<webapp>/WEB-INF/templates/site et sous-répertoires | *.html | Les modèles HTML utilisés pour la construction dynamique des pages. Il s’agit de blocs de code HTML utilisés par les beans de présentation du site |
<webapp>/WEB-INF/tmp | aucun fichier | Répertoire utilisé dans les fonctionnalités d’ upload , doit être toujours vidé après le traitement |
<webapp>/WEB-INF/xsl/admin | *.xsl | Les feuilles de style XSL de mise en forme du contenu XML sur le module d'administration |
<webapp>/WEB-INF/xsl/normal | *.xsl | Les feuilles de style XSL de mise en forme du contenu XML sur le site |
Un plugin peut nécessiter un ensemble assez important et divers de fichiers. Voici les répertoires désignés pour contenir ces fichiers.
Localisation | Type de fichier | Description |
---|---|---|
/src/java/fr/lutece/plugins/<plugin_name>/business | *.java | Les fichiers sources java de la couche métier |
/src/java/fr/lutece/plugins/<plugin_name>/service | *.java | Les fichiers sources java de la couche service |
/src/java/fr/lutece/plugins/<plugin_name>/web | *.java | Les fichiers sources java de la couche présentation |
/src/sql/plugins/<plugin_name> | *.sql | Les scripts SQL d'installation et d'initialisation des tables du plugin |
<webapp>/jsp/admin/plugins/<plugin_name> | *.jsp | Les JSP des fonctions d'administration |
<webapp>/images/local/skin/plugins/<plugin_name> | *.gif,*.jpg,*.png | Les images des fonctions d'administration |
<webapp>/images/local/skin/plugins/<plugin_name> | *.gif,*.jpg,*.png | Les images de présentation de l'application |
<webapp>/images/local/data/<plugin_name> | *.gif,*.jpg,*.png | Les images gérées comme des données du plugin |
<webapp>/plugins/<plugin_name>/*.* | Sous-répertoires, tous types de fichiers | Emplacement réservé aux plugins ayant besoins de répertoires ou fichiers spécifiques |
<webapp>/WEB-INF/conf/plugins/<plugin_name>.properties | *.properties | Le fichier de propriété .properties du plugin |
<webapp>/WEB-INF/plugins | *.xml, plugins.dat, plugin_2_2.dtd | Le fichier de définition du plugin |
/WEB-INF/templates/admin/plugins | *.html | Les templates des fonctions d'administration |
/WEB-INF/templates/skin/plugins | *.html | Les templates de l'application accessibles du portail |
/WEB-INF/lib/plugin_<plugin_name>_<version>.jar | *.jar | Le fichier jar contenant les classes du plugin |
Il y a une erreur de communication avec le serveur Booktype. Nous ne savons pas actuellement où est le problème.
Vous devriez rafraîchir la page.