This is an old revision of the document!
eP-Core est le module d'accès à la BD. Ce module permet d'obtenir les objets Java représentant les données de la BD ePims ainsi que les services permettant d'agir sur ces objets. Ce module est déployé de façon indépendante sur le serveur d'application Java Geronimo afin d'être utilisé et partagé par les autres modules de présentations et de service du système.
Figure 1 Architecture globale de l’application
Le schema représente la totalité de l'application ePims. eP-Core représentele noyau de cette application, il ne contient pas ce qui se rapporte à la couche présentation càd interfaces Web, il constitue le point d’accès aux données de l’application ainsi qu’aux actions sur ces données (création, modification, suppression) au travers d’interfaces accessibles par toutes les couches de l’application.
Comme indiqué sur ce schéma, les technologies utilisées dans l'application ePims sont les suivantes:
Les cibles Ant principales définies pour eP-Core sont :
Cette section décrit l’organisation des packages ainsi que les points d’interaction entre les objets des différents frameworks.eP-Core ne concernant pas tout ce qui se rapporte à la partie présentation, seuls les objets de persistance de données et ceux propre à la logique applicative sont définis.
Figure 2 Diagramme de classe globale
En résumé, la couche model rend visible d’une part les objets représentant les données (package BO) et, d’autre part, les interfaces Services qui permettent de manipuler ces données.
On retrouve donc dans les fichiers de configuration xml : (spring-*.xml)
REMARQUE : ServiceLocator recherche dans l’ApplicationContext qui lui est spécifié les beans correspondants à l’implémentation de IXXXService (définit dans spring-*.xml).
La génération des POJOs et DAO se fait via MyEclipse Hibernate Reverse Engineering (HRE). Les hbms sont construits manuellement. Afin de permettre une séparation des POJOs et des DAO dans des packages différents la génération se fait en deux étapes :
Depuis MyEclipse Database Explorer, sélectionner toutes les tables de la BD ePims sauf :
Dans les fenêtres d'HRE
Figure 3 MyEclipse Hibernate Reverse Engineering
o table ms_protocol => classe cea.edyp.epims.domain.dao.impl.MSProtocol o table msms_protocol => classe cea.edyp.epims.domain.dao.impl.MSMSProtocol o table gel_1d => classe cea.edyp.epims.domain.dao.impl.Gel1D o table gel_2d => classe cea.edyp.epims.domain.dao.impl.Gel2D o table gel_1d_migration => classe cea.edyp.epims.domain.dao.impl.Gel1DMigration o table gel_2d_migration => classe cea.edyp.epims.domain.dao.impl.Gel2DMigration o table sample_species => classe cea.edyp.epims.domain.dao.impl.Species o table sample_subcellular_localisation => classe cea.edyp.epims.domain.dao.impl.SubCellularLocalisation
Une fois les classes DAO générées il faut corriger les erreurs suivantes :
public ActorRole findById( cea.edyp.epims.domain.dao.impl.ActorRoleId id) ⇒ public ActorRole findById( cea.edyp.epims.domain.ActorRoleId id)
Attention : A la première création des DAO, nous avons “extrait” les interfaces (via MyEclipse) dans le package cea.edyp.epims.domain.dao.*. Ceci afin de référencer les interfaces dans les services et éventuellement d'enrichir ces interfaces pour certaines classes. Dans ce cas des modifications sur les classes DAO générées sont nécessaires. Par exemple pour l'objet Study :
Figure 4 Diagramme de classes exemple pour les DAO Hibernate
Les Objets du domaines sont générés depuis les fichiers *.hbm.xml:
o spécifier src/main comme output folder, o cocher la case "Create abstract class" o ne pas cocher la case custom template
Seules les classes mères “AbstractXXX” sont systématiquement générées. Les sous classes ne sont générées que la première fois ce qui permet de les personnaliser sans tout perdre à chaque génération.
Figure 5 diagramme de classes exemple pour les objets du domaine
Accès:
Seules les interfaces IxxxService sont visibles depuis toute autre application (telle que la couche présentation) qui utilisera eP-Core. Ces interfaces devront fournir les méthodes nécessaires pour l’accès aux données en lecture et en écriture.
Règles de développement
Les méthodes pour l'écriture des données sont de la forme :
Pour les accès en lecture, les services sont écrits selon le principe suivant :
Il est certain que certaines actions ne peuvent être appliquées par une simple requête (aussi compliquée qu'elle puisse être !!), à ce moment là, les services peuvent aussi avoir des méthodes exécutant des tâches partiulières.
Et au niveau des fichiers de configuration, on définit les beans.
<bean id="contactServiceTarget" class="cea.edyp.epims.service.impl.HibernateContactService"> <property name="actorDao"><ref bean="ActorDAO"></ref></property> <property name="contactDao"><ref bean="ContactDAO"></ref></property> <property name="actorRoleDao"><ref bean="ActorRoleDAO"></ref></property> <property name="companyDao"><ref bean="CompanyDAO"></ref></property> </bean> <!-- Transactional proxy Services --> <bean id="baseTransactionProwy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager"><ref local="transactionManager"/></property> <property name="transactionAttributes"> <props> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="="create*">PROPAGATION_REQUIRED</prop> <prop key="="delete*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> ... <bean id="contactService" parent="baseTransactionProxy"> <property name="target"><ref local="contactServiceTarget"/></property> </bean>
<bean id=“actorDAO” class=“cea.edyp.epims.domain.dao.impl.HibernateActorDAO” >
<property name="hibernateTemplate"><ref bean="hibernateTemplate"/></property> </bean>
Tous les packages du projets sont des sous packages de cea.edyp.epims. Les classes relatives aux données sont sous les packages cea.edyp.epims.domain. Chacun de ces packages contient un package base où Hibernate génère les classes relatives aux données et un package dao où Hibernate génère les interfaces relatives à l’accès des données dans la base, les classes d’implémentation de ces interfaces sont générées dans le sous package dao.impl, package relatif aux packages des domaines.
Les interfaces fournissant les services (voir section précédente) sont regroupées dans le package cea.edyp.epims.service. Ces interfaces seront implémentées par les classes se trouvant dans le package cea.edyp.epims.service.impl
Les différentes configurations nécessaires à Spring sont faites dans des fichiers XML : springContext.xml, springAppContext.xml et springDataSource.xml.
o Des propriétés de hibernate via le bean SessionFactory,
o Du bean HibernateTemplate utilisé par les DAO o Les différents beans DAO o Les différents bean de services ainsi que les beans TransactionManager associés.
Les modules ePims déclaré dans l'application EAR partageront le context spring définit dans eP-Core et donc les beans 'singleton' définis dans ce contexte. Voir la doc de l'architecture ePims …
Pour un module d'application web, il est nécessaire de définir le context spring parent que l'on souhaite utiliser dans le fichier web.xml:
<!-- Spring Context --> <context-param> <param-name>locatorFactorySelector</param-name> <param-value>classpath*:springContext.xml</param-value> </context-param> <context-param> <param-name>parentContextKey</param-name> <param-value>span>epCore.context</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
il est également possible de l’utiliser dans une application :
String[] confFiles = {"/springAppContext.xml","/springDataSource.xml"}; ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(confFiles);
Dans le code des applications utilisant le module eP-Core, lorsque l'on souhaite accéder à un des beans(services) définis dans spring, on utilise la classe ServiceLocator :
ServiceLocator locator = new ServiceLocator(context); IStudyService service= locator.getStudyService();
Problème :
Cette solution semble parfaite mais le problème réside dans son utilisation. En effet, si l’on tente d’accéder à la propriété dite lazy une fois la session hibernate fermée, une exception est générée. Pour éviter toute exception, il ne faut donc pas utiliser directement les méthodes définies dans les objets du domaine.
public class StudyBean{ private Study study_ ; …
public List getSamples(){
if(study_ == null) return new ArrayList();
return study_.getSamples();
}
Une des solutions que l’on retrouve dans les différents forum ou docs, est de récupérer les données lors de la lecture de l’entité si l’on sait que l’on en aura besoin …. Cette solution n’est pas convaincante lorsque l’on souhaite séparer complètement la vue des données. En effet, lors du chargement d’une entités au niveau des DAO ou même des Services, on ne connaît pas l’utilisation qui en sera faite.