Projets
Pages enfant
  • 3.3.2 Le fonctionnement

Comparaison des versions

Légende

  • Ces lignes ont été ajoutées. Ce mot a été ajouté.
  • Ces lignes ont été supprimées. Ce mot a été supprimé.
  • La mise en forme a été modifiée.
Commentaire: Migrated to Confluence 5.3
Remarque
titleA compléter

Paragraphe AOP

Sommaire :

Sommaire
maxLevel3

...

Les points d'entrée

En esup-commons V1 on devait modifier les différent points d'entrée de l'application (FacesServlet, FacesPortlet, XFireServlet). Cette approche avait 2 désavantages  :

...

La gestion des transactions se fait au niveau des appels métier (fichier resources/properties/domain/domain.xml). Exemple :

Bloc de code

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 
xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:jaxws="http://cxf.apache.org/jaxws"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
 http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

<aop:config>
 <aop:pointcut id="domainMethods"
  expression="execution(* org.esupportail.*.domain.DomainServiceImpl.*(..))" />
 <aop:advisor advice-ref="txAdvice" pointcut-ref="domainMethods" />
</aop:config>

<tx:advice id="txAdvice" transaction-manager="txManager">
 <tx:attributes>
  <tx:method name="add*" propagation="REQUIRED" />
  <tx:method name="delete*" propagation="REQUIRED" />
  <tx:method name="update*" propagation="REQUIRED" />
  <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
 </tx:attributes>
</tx:advice>

<bean id="domainService" class="org.esupportail.example.domain.DomainServiceImpl">
 <property name="daoService" ref="daoService" />
</bean>

Explications :

  • La racine <beans> contient la définition des espaces de nom aop: et tx: ainsi que la localisation des schémas XSD ad hoc- qui sont utilisés dans la suite du fichier.
  • La balise <aop:config>permet de préciser deux choses :
    • Le point de coupe (pointcut). C'est-à-dire l'emplacement où va être inséré dynamiquement le code AOP. L'attribut expression permet de préciser que l'on va cibler toutes les méthodes, quelle qu'en soit la signature, de la classe DomainServiceImpl dans un package donc le path commence par org.esupportail et fini par domain.
    • La référence au gestionnaire de transactions à brancher sur ce point de coupe.
  • La balise <tx:advice> permet de préciser la nature de la transaction. Ici on précise, via propagation="REQUIRED" que l'on veut créer une transaction, si elle n'est pas encore présente, sur toutes les méthodes dont le nom commence par add, delete ou update.

...

  • Info

    Sur les autres méthodes la transaction est conservée si elle existe mais elle ne sera pas créé si seulement ces méthodes sont appelés.

...

  • Info

    Si vous avez besoin de gérer des commit et rollback sur d'autres méthodes que celles commençant part add, delete ou update alors il faut ajouter une balise <tx:method> ad hoc.

Déploiement en servlet

En déploiement servlet esup-commons V1 pour JSF, il faut fallait utiliser la servlet FacesServlet offerte par esup-commons, et qui gère les sessions Hibernate et les exceptions (cf /webapp/WEB-INF/ (org.esupportail.commons.web.servlet.FacesServlet) qui gérait les sessions Hibernate. Ce n'est plus utile en esup-commons V2 grâce à l'utilisation de APO. La servlet utilisée est celle de JSF (dans web.xml) :

Bloc de code

<servlet>
 <servlet>
 <description> The main servlet of the application. This class inherits
  from the MyFaces implementation and handles exceptions thrown for
  specific exception handling.
 </description>
 <display-name>Faces Servlet</display-name>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>
    org.esupportail.commons.web.servlet.FacesServlet
  <class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>


<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.faces<xhtml</url-pattern>
</servlet-mapping>

Déploiement en portlet

Par contre, avec JSF et JPA on peut faire une requête à la base de données dans la couche métier pour récupérer un objet et avoir besoin de naviguer des les fils de ce dernier au moment de l'affichage de la vue. Dans ce cas on peut avoir besoin de maintenir l'accès à la base de données pendant le temps du rendu de la vue afin d'éviter les erreurs de type LazyLoadingException. Pour ce faire on utilise un listerner particulier (dans le En mode portlet, il faut utiliser la servlet PortletServlet offerte par esup-commons, et qui gère également les sessions Hibernate et les exceptions (cf /webapp/WEB-INF/web.xml) :

Bloc de code

<servlet><filter>
  <display-name>esup-application<name>JPA Filter</display-name>
  <servlet-name>esup-application</servlet<filter-name>JPA Filter</filter-name>
  <servlet-class>
    org.esupportail.commons.web.portlet.PortletServlet
  </servlet-class>
  <init-param>
    <param-name>portlet-class</param-name>
    <param-value>
      org.esupportail.commons.web.portlet.FacesPortlet
    </param-value>
  </init-param>
  <init-param>
    <param-name>portlet-guid</param-name>
    <param-value>esup-diskquota.esup-diskquota</param-value>
  </init-param>
</servlet>
Bloc de code

<servlet-mapping>
  <servlet-name>esup-application</servlet-name>
  <url-pattern>/esup-application/*</url-pattern>
</servlet-mapping>

Web services

<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>

<filter-mapping>
 <filter-name>JPA Filter</filter-name>
 <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

Déploiement en portlet

En esup-commons V1 pour JSF, il fallait utiliser la servlet FacesPortlet offerte par esup-commons (org.esupportail.commons.web.portlet.FacesPortlet) qui gérait les sessions Hibernate. Ce n'est plus utile en esup-commons V2 grâce à l'utilisation de APO. La portlet utilisée est celle de la spécification portlet bridge pour JSF (dans portlet.xml)

En mode portlet, il faut utiliser la servlet PortletServlet En mode web service, il faut utiliser la servlet XFireServlet offerte par esup-commons, et qui gère également les sessions Hibernate et les exceptions (cf . /webapp/WEB-INF/web.xml) :

Bloc de code
<portlet>
<servlet>
  <servlet-name>xfire</servlet <portlet-name>esup-example</portlet-name>
  <servlet<display-class>
    org.esupportail.commons.web.servlet.XFireServlet
  </servlet-class>
</servlet>


<servlet-mapping>
  <servlet-name>xfire</servletname xml:lang="fr">esup-example</display-name>
  <url-pattern>/xfire/*</url-pattern>
</servlet-mapping>

Cela implique que les opérations effectuées soient unitaires, au sens transactionnel.

Accès batch

Les accès batch sont traités en détail dans un chapitre dédié.

Voir : 11 Commandes batch

La configuration de l'accès aux données

Les points d'entrées ci-dessus utilisent la classe statique DatabaseUtils qui, pour pouvoir gérer plusieurs connexions à des bases de données, s'appuie sur un « magasin de gestionnaires de bases  de données ».

Ce magasin, qui recense les gestionnaires de bases de données, est un bean nommé databaseManagerStore, qui doit implémenter l'interface DatabaseManagerStore. Une seule implémentation est fournie de base (BasicDatabaseManagerStoreImpl), elle doit permettre de répondre à toutes les demandes.

On trouvera par exemple dans le fichier /properties/dao/dao.xml :

Bloc de code

<bean
    id="databaseManagerStore"
    class="[...].services.database.BasicDatabaseManagerStoreImpl" >
  <property name="databaseManagers">
    <list>
      <ref bean="databaseManager1" />
      <ref bean="databaseManager2" />
    </list>
  </property>
</bean>

Le magasin recense ici deux gestionnaires de bases de données (databaseManager1 et databaseManager2).

Les gestionnaires de bases de données sont chargés de l'accès à une base de données ; ce sont également des beans, qui doivent implémenter l'interface DatabaseManager. Les méthodes de cette interface sont :

  • void open(servletContext) : ouvre la connexion à la base de données et commence une transaction ; cette méthode est utilisée en mode web.
  • void open() : ouvre la connexion à la base de données et commence une transaction ; cette méthode est utilisée en mode batch.
  • void close(boolean) : valide (commit) ou invalide (rollback) la transaction courante et ferme la connexion.
  • void test() : teste la connexion; cette méthode est utilisée par la tâche ant test-database.
  • boolean isUpdatable() : indique si le gestionnaire est capable de créer et mettre à jour la structure de la base de données (on pourra dans ce cas appeler les méthodes create() et update()).
  • void create() : crée les structures de la base de données.
  • void update() : met à jour les structures de la base de données.
    Remarque
    titleUtiliser _esup-commons_ sans base de données

    Les utilisateurs ne s'appuyant sur aucune base de données devront utiliser l'implémentation EmptyDatabaseManagerStoreImpl pour le bean databaseManagerStore.

L'accès aux données depuis du code Java

Le service métier (le bean domainService) accède aux données via le service d'accès aux données (le bean daoService). Il est à la charge des implémentations de l'interface DaoService de récupérer les sessions courantes des bases données et d'effectuer les requêtes nécessaires.

<portlet-class>javax.portlet.faces.GenericFacesPortlet</portlet-class>

Par contre, avec JSF et JPA on peut faire une requête à la base de données dans la couche métier pour récupérer un objet et avoir besoin de naviguer des les fils de ce dernier au moment de l'affichage de la vue. Dans ce cas on peut avoir besoin de maintenir l'accès à la base de données pendant le temps du rendu de la vue afin d'éviter les erreurs de type LazyLoadingException. Le listerner utilisé en mode servlet n'est pas utilisable en mode portlet. ESUP-Commons propose un phaseListener JSF qui offre les mêmes services. Il faut le configurer dans le fichier webapp/WEB-INF/jsf/faces-config.xml :

Bloc de code
<phase-listener>org.esupportail.commons.jsf.PortletPhaseListenerWithJPA</phase-listener>
Info

En mode portlet on préférera sans doute faire appel à un Web Service exposé par une application métier et ne pas directement faire des appels à la base de données. Dans ce cas le phaseListener à utiliser sera org.esupportail.commons.jsf.PortletPhaseListener.

Web services

En esup-commons V1, il fallait utiliser la servlet XFireServlet offerte par esup-commons (org.esupportail.commons.web.servlet.XFireServlet) qui gérait les sessions Hibernate. Ce n'est plus utile en esup-commons V2 grâce à l'utilisation de AOPLa méthode utilisée par les implémentations Hibernate est détaillée dans la partie suivante.