Accueil > DynaResume, JPA, JPA/EclipseLink, JPA/Hibernate, Spring ORM > Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step18]

Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step18]


Dans le billet précédant [step17] nous avons mis en place JPA avec Spring en utilisant LocalEntityManagerFactoryBean avec l’implémentations JPA JPA/Eclipselink et les 2 bases de données H2 et Derby. Nous avons vu que le support Spring ORM nous permet de gérer JPA dans un conteneur (Spring) JPA ce qui permet de:

  • gérer les ouvertures/fermetures des EntityManager.
  • gérer les ouvertures/fermetures des EntityTransaction (commit/rollback) via l’annotation Spring org.springframework.transaction.annotation.@Transactionnal

A ce stade nous avons déclaré un persistence-unit par implémentation JPA et par base de données, ce qui engendre une duplication de déclaration XML (« provider », « propertes », et « class ») . Par exemple si on souhaite utiliser 2 base de données pour une même implémentation JPA, l’information « provider » est dupliquée 2 fois dans le fichier persistence.xml mais pire la déclaration des éléments « class » est aussi dupliquée. Lorsque l’on souhaite gérer une nouvelle classe Java domain persistente, l’élément « class » doit être ajouté dans les 2 déclaration des persistence-unit. Si on ajoute à ça une autre implémentation JPA, ceci signifie que l’on a 2 (implémentation JPA) * 2 (base de données) = 4 déclarations de persistence-unit.

L’idéal serait d’avoir 1 seule déclaration persistence-unit qui gère tous les cas. Le support de Spring ORM permet de gérer ce cas-ci en déléguant les informations de « provider » et de « properties » à des bean Spring en utilisant LocalContainerEntityManagerFactoryBean. LocalContainerEntityManagerFactoryBean permet d’avoir une seule déclaration persistence-unit pour n’importe quelle implémentation JPA et base de données :

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	version="1.0">

	<persistence-unit name="dynaresume"
		transaction-type="RESOURCE_LOCAL">

		<class>org.dynaresume.domain.User</class>

	</persistence-unit>

</persistence>

C’est ce que nous allons effectuer dans ce billet en mettant en place JPA avec LocalContainerEntityManagerFactoryBean en utilisant JPA/Hibernate et JPA/Eclipselink avec les 2 bases de données H2 et Derby.

Vous pouvez télécharger le zip org.dynaresume_step18.zip qui contient les projets expliqués ci dessous:

  • org.dynaresume.test.jpa_lfb : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaEntityManagerFactoryBean.
  • org.dynaresume.test.jpa_lcfb_1 : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaContainerEntityManagerFactoryBean. Dans ce projet l’implémentation JPA/Eclipselink ne fonctionne pas du au problème de LoadTimeWeaver (pour JPA/Hibernate le problème ne se pose pas).
  • org.dynaresume.test.jpa_lcfb_withoutLTW : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaContainerEntityManagerFactoryBean. Dans ce projet l’implémentation JPA/Eclipselink fonctionne en désactivant le LoadTimeWeaver.
  • org.dynaresume.test.jpa_lcfb_withLTW : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaContainerEntityManagerFactoryBean. Dans ce projet l’implémentation JPA/Eclipselink fonctionne en utilisant l’agent Spring.
  • org.dynaresume.test.jpa_lcfb_2 : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaContainerEntityManagerFactoryBean et qui délègue les informations provider et properties à des bean Spring.
  • org.dynaresume.test.jpa_lcfb_3 : projet identique au projet org.dynaresume.test.jpa_lcfb_2 mais qui « splitte » la déclaration des bean en plusieurs fichier XML Spring applicationContext qui définiront dans le prochain billet nos bundles OSGi.
  • org.dynaresume.test.jpa_lcfb_4 : projet identique au projet org.dynaresume.test.jpa_lcfb_3 mais qui utilise org.springframework.beans.factory.config.PropertyPlaceholderConfigurer pour définir les propriétés de la base de données dans un fichier de propriétés.
  • spring-target-platform-dao : projet qui contient toutes les librairies nécessaires à la couche DAO.

Pré-requis

Avant de démarrer ce billet vous devez avoir :

Téléchargez le zip spring-target-platform-dao.zip qui contient les librairies JARs JPA, JPA/Hibernate,… récupérés via Maven dans le billet [step14] puis importez le projet spring-target-platform-dao dans votre workspace.

REMARQUE : nous avons créé la base de données via des scripts mais JPA est capable de générer la base de données en utilisant les informations de mapping.

org.dynaresume.test.jpa_lfb

Dans cette section nous allons créer le projet org.dynaresume.test.jpa_lfb qui utilise LocaEntityManagerFactoryBean avec les 2 implémentation JPA JPA/Hibernate et JPA/EclipseLink avec les 2 bases de données H2 et Derby. Ici je ne vais pas détaillé le code JPA car celui-ci est déjà expliqué dans les billets précédants.

Créez le projet Java org.dynaresume.test.jpa_lfb.

Librairies

Ajoutez au projet les librairies provenant du projet spring-target-platform-dao :

  • API JPA & Transaction stockés dans le répertoire : lib/javax.
  • les 2 Implémentation JPA :
    • JPA/Hibernate : stockés dans le répertoire : lib/jpa-hibernate.
    • JPA/EclipseLink: stockés dans le répertoire : lib/jpa-eclipselink.
  • le support de Spring ORM : stockés dans le répertoire : lib/spring-orm.
  • l’implémentation SL4J avec log4j stocké dans le répertoire : lib/slf4j-log4j.
  • 2 bases de données :
    • Derby : stockés dans le répertoire : lib/derby. Le JAR com.springsource.org.apache.derby.client-10.5.1000001.764942.jar n’est pas nécéssaire.
    • H2: stockés dans le répertoire : lib/h2

log4j.properties

L’implémentation JPA/Hibernate utilise SL4J. Nous utilisons l’implémentation log4j de SL4J et pour cela créez le ficher log4j.properties dans le répertoire src du projet :

log4j.rootLogger=info, con
log4j.appender.con=org.apache.log4j.ConsoleAppender
log4j.appender.con.layout=org.apache.log4j.PatternLayout
log4j.appender.con.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

Domain – User

Créez la classe org.dynaresume.domain.User avec le mapping JPA comme suit :

package org.dynaresume.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "T_USER")
public class User {

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "USR_ID_N")
	private long id;

	@Column(name = "USR_LOGIN_C")
	private String login;

	@Column(name = "USR_PASSWORD_C")
	private String password;

	public User() {
	}

	public User(String login, String password) {
		setLogin(login);
		setPassword(password);
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

}

persistence.xml

Ici nous allons créer le fichier persistence.xml qui déclare les persistence-unit pour chacune des implémentation JPA et base de données soit 2 (implémentation JPA) * 2 (base de données) = 4 persistence-unit. Créez le fichier persistence.xml dans le répertoire META-INF que vous devez créer dans le répertoire src (et pas à la racine du projet comme les bundles OSGi). En effet ce fichier doit se retrouver après compilation du projet dans le répertoire bin. Créez le fichier persistence.xml avec le contenu suivant :

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	version="1.0">

	<persistence-unit name="dynaresume-hibernate-h2"
		transaction-type="RESOURCE_LOCAL">

		<provider>
			org.hibernate.ejb.HibernatePersistence
		</provider>

		<class>org.dynaresume.domain.User</class>

		<properties>
			<property name="hibernate.connection.driver_class" value="org.h2.Driver" />
			<property name="hibernate.connection.url" value="jdbc:h2:C:/db/h2/dynaresume" />
			<property name="hibernate.connection.username" value="sa" />
			<property name="hibernate.connection.password" value="" />
			<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
			<property name="hibernate.show_sql" value="true" />
		</properties>

	</persistence-unit>

	<persistence-unit name="dynaresume-hibernate-derby"
		transaction-type="RESOURCE_LOCAL">

		<provider>
			org.hibernate.ejb.HibernatePersistence
		</provider>

		<class>org.dynaresume.domain.User</class>

		<properties>
			<property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.EmbeddedDriver" />
			<property name="hibernate.connection.url" value="jdbc:derby:C:/db/derby/dynaresume" />
			<property name="hibernate.connection.username" value="" />
			<property name="hibernate.connection.password" value="" />
			<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
			<property name="hibernate.show_sql" value="true" />
		</properties>

	</persistence-unit>

	<persistence-unit name="dynaresume-eclipselink-h2"
		transaction-type="RESOURCE_LOCAL">

		<provider>
			org.eclipse.persistence.jpa.PersistenceProvider
		</provider>

		<class>org.dynaresume.domain.User</class>

		<properties>
			<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
			<property name="javax.persistence.jdbc.url" value="jdbc:h2:C:/db/h2/dynaresume" />
			<property name="javax.persistence.jdbc.user" value="sa" />
			<property name="javax.persistence.jdbc.password" value="" />
			<property name="eclipselink.target-database"
				value="org.eclipse.persistence.platform.database.H2Platform" />
			<property name="show-sql" value="true" />
		</properties>

	</persistence-unit>

	<persistence-unit name="dynaresume-eclipselink-derby"
		transaction-type="RESOURCE_LOCAL">

		<provider>
			org.eclipse.persistence.jpa.PersistenceProvider
		</provider>

		<class>org.dynaresume.domain.User</class>

		<properties>
			<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
			<property name="javax.persistence.jdbc.url" value="jdbc:derby:C:/db/derby/dynaresume" />
			<property name="javax.persistence.jdbc.user" value="" />
			<property name="javax.persistence.jdbc.password" value="" />
			<property name="eclipselink.target-database"
				value="org.eclipse.persistence.platform.database.DerbyPlatform" />
			<property name="show-sql" value="true" />
		</properties>

	</persistence-unit>

</persistence>

Comme vous pouvez le constater l’élément « class » se retrouve 4 fois déclarés. Les élements « provider » sont dupliqués 2 fois (2 implémentation JPA).

DAO – UserDAO/UserDAOJpa

Interface UserDAO

Créez l’interface org.dynaresume.dao.UserDAO comme suit :

package org.dynaresume.dao;

import java.util.Collection;

import org.dynaresume.domain.User;

public interface UserDAO {

	Collection<User> findAllUsers();
	
	User saveUser(User user);
}

Implémentation UserDAOJpa

Créez l’implémentation JPA de UserDAOJpa avec la classe org.dynaresume.dao.jpa.UserDAOJpa comme suit :

ackage org.dynaresume.dao.jpa;

import java.util.Collection;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.dynaresume.dao.UserDAO;
import org.dynaresume.domain.User;

public class UserDAOJpa implements UserDAO {

	@PersistenceContext
	private EntityManager entityManager;

	public Collection<User> findAllUsers() {
		Query query = entityManager.createQuery("select u from "
				+ User.class.getSimpleName() + " u");
		return query.getResultList();
	}

	public User saveUser(User user) {
		entityManager.persist(user);
		return user;
	}

}

Service – UserService/UserServiceImpl

Ici nous allons mettre en place la couche Service avec l’interface UserService et son implémentation UserServiceImpl qui va utiliser l’interface UserDAO (et pas l’implémentation direct). On parle de Dépendance d’Injection.

Interface UserService

Créez l’interface org.dynaresume.services.UserService comme suit :

package org.dynaresume.services; 
 
import java.util.Collection; 

import org.dynaresume.domain.User;
 
public interface UserService { 
 
  Collection<User> findAllUsers(); 
}
Implémentation UserService

Créez l’implémentation du service UserService avec la classe org.dynaresume.services.impl.UserServiceImpl comme suit :

package org.dynaresume.services.impl;

import java.util.Collection;

import org.dynaresume.dao.UserDAO;
import org.dynaresume.domain.User;
import org.dynaresume.services.UserService;
import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly=true)
public class UserServiceImpl implements UserService {

	private UserDAO userDAO;

	public void setUserDAO(UserDAO userDAO) {
		this.userDAO = userDAO;
	}
	
	public Collection<User> findAllUsers() {
		return userDAO.findAllUsers();
	}

	@Transactional
	public User createUser(String login, String password) {
		User user = new User(login, password);
		return userDAO.saveUser(user);
	}
}

Test JPA

Test JPA/EclipseLink

Test JPA/EclipseLink – Derby

Créez le fichier XML Spring applicationContext-eclipselink-derby.xml dans le package org.dynaresume comme suit :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume-eclipselink-derby" />
	</bean>

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />	
	
	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	
</beans>

Ici, la déclaration du bean Spring entityManagerFactory utilise le persistence-unit dynaresume-eclipselink-derby de persistence.xml.

Créez la classe org.dynaresume.test.jpa.eclipselink.derby.FindAllUserDynaresumeDerbyEclipseLink qui permet d’afficher la liste des User de la table T_USER de la base Derby via JPA/Eclipselink :

package org.dynaresume.test.jpa.eclipselink.derby;

import java.util.Collection;

import org.dynaresume.domain.User;
import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FindAllUserDynaresumeDerbyEclipseLink {

	public static void main(String[] args) {

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"org/dynaresume/applicationContext-eclipselink-derby.xml");
		UserService userService = (UserService) applicationContext
				.getBean("userService");

		Collection<User> users = userService.findAllUsers();
		for (User user : users) {
			System.out.println("User [id=" + user.getId() + " login="
					+ user.getLogin() + ", password=" + user.getPassword()
					+ "]");
		}
	}
}

Lancez cette classe et la console affiche la liste des User de la table T_USER de la base Derby.

Créez la classe org.dynaresume.test.jpa.eclipselink.derby.CreateUserDynaresumeDerbyEclipseLink qui permet de créer un User dans la table T_USER de la base Derby via JPA/Eclipselink :

package org.dynaresume.test.jpa.eclipselink.derby;

import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CreateUserDynaresumeDerbyEclipseLink {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"org/dynaresume/applicationContext-eclipselink-derby.xml");
		UserService userService = (UserService) applicationContext
				.getBean("userService");
		userService.createUser("jpa-user (EclipseLink-Derby)", "");
	}
}

Lancez cette classe pour insérer un nouveau User puis lancez FindAllUserDynaresumeDerbyEclipseLink pour constater que le User a bien été inséré.

Test JPA/EclipseLink – H2
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume-eclipselink-h2" />
	</bean>

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />


	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

</beans>

Ici, la déclaration du bean Spring entityManagerFactory utilise le persistence-unit dynaresume-eclipselink-h2 de persistence.xml.

Créez la classe org.dynaresume.test.jpa.eclipselink.h2.FindAllUserDynaresumeH2EclipseLink qui permet d’afficher la liste des User de la table T_USER de la base H2 via JPA/Eclipselink :

package org.dynaresume.test.jpa.eclipselink.h2;

import java.util.Collection;

import org.dynaresume.domain.User;
import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FindAllUserDynaresumeH2EclipseLink {

	public static void main(String[] args) {

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"org/dynaresume/applicationContext-eclipselink-h2.xml");
		UserService userService = (UserService) applicationContext
				.getBean("userService");

		Collection<User> users = userService.findAllUsers();
		for (User user : users) {
			System.out.println("User [id=" + user.getId() + " login="
					+ user.getLogin() + ", password=" + user.getPassword()
					+ "]");
		}
	}

}}

Lancez cette classe et la console affiche la liste des User de la table T_USER de la base H2.

Créez la classe org.dynaresume.test.jpa.eclipselink.h2.CreateUserDynaresumeH2EclipseLink qui permet de créer un User dans la table T_USER de la base H2 via JPA/Eclipselink :

package org.dynaresume.test.jpa.eclipselink.h2;

import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CreateUserDynaresumeH2EclipseLink {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"org/dynaresume/applicationContext-eclipselink-h2.xml");
		UserService userService = (UserService) applicationContext
				.getBean("userService");
		userService.createUser("jpa-user (EclipseLink-H2)", "");
	}
}

Lancez cette classe pour insérer un nouveau User puis lancez FindAllUserDynaresumeH2EclipseLink pour constater que le User a bien été inséré.

Test JPA/Hibernate

Test JPA/Hibernate – Derby
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume-hibernate-derby" />
	</bean>

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />	
	
	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	
</beans>

Ici, la déclaration du bean Spring entityManagerFactory utilise le persistence-unit dynaresume-hibernate-derby de persistence.xml.

FindAllUserDynaresumeDerbyHibernate

Créez la classe org.dynaresume.test.jpa.hibernate.derby.FindAllUserDynaresumeDerbyHibernate qui permet d’afficher la liste des User de la table T_USER de la base Derby via JPA/Hibernate:

package org.dynaresume.test.jpa.hibernate.derby;

import java.util.Collection;

import org.dynaresume.domain.User;
import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FindAllUserDynaresumeDerbyHibernate {

	public static void main(String[] args) {

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"org/dynaresume/applicationContext-hibernate-derby.xml");
		UserService userService = (UserService) applicationContext
				.getBean("userService");

		Collection<User> users = userService.findAllUsers();
		for (User user : users) {
			System.out.println("User [id=" + user.getId() + " login="
					+ user.getLogin() + ", password=" + user.getPassword()
					+ "]");
		}
	}
}

Lancez cette classe et la console affiche la liste des User de la table T_USER de la base Derby.

CreateUserDynaresumeDerbyHibernate

Créez la classe org.dynaresume.test.jpa.hibernate.derby.CreateUserDynaresumeDerbyHibernate qui permet de créer un User dans la table T_USER de la base Derby via JPA/Hibernate:

package org.dynaresume.test.jpa.hibernate.derby;

import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CreateUserDynaresumeDerbyHibernate {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"org/dynaresume/applicationContext-hibernate-derby.xml");
		UserService userService = (UserService) applicationContext
				.getBean("userService");
		userService.createUser("jpa-user (Hibernate-Derby)", "");
	}
}

Lancez cette classe pour insérer un nouveau User puis lancez FindAllUserDynaresumeDerbyHibernate pour constater que le User a bien été inséré.

Test JPA/Hibernate – H2
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<h2>org.dynaresume.test.jpa_lfb</h2>

	<bean id="entityManagerFactory"

		class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume-hibernate-h2" />
	</bean>

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />	
	
	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	
</beans>

Ici, la déclaration du bean Spring entityManagerFactory utilise le persistence-unit dynaresume-hibernate-h2 de persistence.xml.

FindAllUserDynaresumeH2Hibernate

Créez la classe org.dynaresume.test.jpa.hibernate.h2.FindAllUserDynaresumeH2Hibernate qui permet d’afficher la liste des User de la table T_USER de la base H2 via JPA/Hibernate:

package org.dynaresume.test.jpa.hibernate.h2;

import java.util.Collection;

import org.dynaresume.domain.User;
import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FindAllUserDynaresumeH2Hibernate {

	public static void main(String[] args) {

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"org/dynaresume/applicationContext-hibernate-h2.xml");
		UserService userService = (UserService) applicationContext
				.getBean("userService");

		Collection<User> users = userService.findAllUsers();
		for (User user : users) {
			System.out.println("User [id=" + user.getId() + " login="
					+ user.getLogin() + ", password=" + user.getPassword()
					+ "]");
		}
	}

}

Lancez cette classe et la console affiche la liste des User de la table T_USER de la base H2.

CreateUserDynaresumeH2Hibernate

Créez la classe org.dynaresume.test.jpa.hibernate.h2.CreateUserDynaresumeH2Hibernate qui permet de créer un User dans la table T_USER de la base H2 via JPA/Hibernate:

package org.dynaresume.test.jpa.hibernate.h2;

import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CreateUserDynaresumeH2Hibernate {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"org/dynaresume/applicationContext-hibernate-h2.xml");
		UserService userService = (UserService) applicationContext
				.getBean("userService");
		userService.createUser("jpa-user (Hibernate-H2)", "");
	}
}

Lancez cette classe pour insérer un nouveau User puis lancez FindAllUserDynaresumeH2Hibernate pour constater que le User a bien été inséré.

org.dynaresume.test.jpa_lcfb_1

Le projet org.dynaresume.test.jpa_lcfb que nous venons de créer montre bien le problème de duplication des élements « class » et « provider » dans le fichier persistence.xml. Pour régler ce problème nous allons utiliser LocalContainerEntityManagerFactoryBean qui permet de gérer via des bean Spring les informations « provider » et « properties » et qui permet d’utiliser un seul fichier persistence.xml qui déclare uniquement les élements « class ». Dans cette section nous allons simplement remplacer dans nos fichiers XML Spring l’utilisation de LocalEntityManagerFactoryBean en LocalContainerEntityManagerFactoryBean.

Copiez collez le projet org.dynaresume.test.jpa_lfb et renommez le en org.dynaresume.test.jpa_lcfb_1.

Dans les 4 fichiers XML Spring applicationContext-*.xml remplacez org.springframework.orm.jpa.LocalEntityManagerFactoryBean par org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean. Voici l’exemple de la déclaration de l’entityManagerFactory du fichier applicationContext-eclipselink-derby.xml :

<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="dynaresume-eclipselink-derby" />
</bean>

Test JPA

Test JPA/Hibernate

Si vous relancez les classes de tests JPA/Hibernate contenu dans le package org.dynaresume.test.jpa.hibernate, vous pourrez constater qu’il n’y a aucun problème.

Test JPA/EclipseLink

Si vous relancez les classes de tests JPA/Eclipselink contenu dans le package org.dynaresume.test.jpa.eclipselink, l’erreur suivante s’affiche dans la console .

Caused by: java.lang.IllegalStateException: Cannot apply class transformer without LoadTimeWeaver specified
at org.springframework.orm.jpa.persistenceunit.SpringPersistenceUnitInfo.addTransformer(SpringPersistenceUnitInfo.java:78)
...

Cette erreur est du au LoadTimeWeaver qui n’a pas été paramétré. Avant d’expliquer comment résoudre ce problème de LoadTimeWeaver dans la section EclipseLink/Load Time Weaver, je vais tenter d’expliquer en quoi consiste le LoadTimeWeaver via des exemples simples, mais ce sujet mériterait un billet dédié.

LoadTimeWeaver & Lazy loading

Dans la documentation de Eclipselink, la section Using_EclipseLink_JPA_Weaving parle du sujet LoadTimeWeaver et indique que le weaving est notamment utilisé pour le « lazy loading ».

Dans une API d’ORM et notemment une implémentation JPA comme JPA/Hibernate ou JPA/EclipseLink, le « lazy loading » est géré. Si vous ne connaissez pas le « lazy loading », imaginez que vous ayez une entité User qui est associé à une entité Role et que lorsque vous chargez le User vous ne souhaitez pas charger le Role associé. Le Role associé ne se charge qu’à la demande, autrement dit que lorsque la méthode User#getRole() est appelée. En JPA le lazy loading s’écrit comme ceci :

public class User {

   ...
   private Role role = null;

  @OneToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="USR_ROL_ID_N", referencedColumnName="ROL_ID_N")	
  private Role role;

  public Role getRole() {
    return role;
  }

}

Le client qui appelle la méthode User#getRole() déclenchera une requête SQL qui permettra de charger le Role du User dans le cas ou celui-ci n’est pas initialisé. La méthode User#getRole() est un simple POJO et n’a pas de code de requête SQL pour charger la liste des Roles. Pour que la requête SQL se déclenche lors de l’appel de la méthode User#getRole(), son appel doit être surveillé (principe de l’AOP). Chaque implémentation JPA gère le lazy-loading avec sa propre technique. Je vous conseille de lire l’article JPA Implementation patterns : Lazy loading pour plus d’information à ce sujet.

JPA/Hibernate- Run-time proxies

Dans le cas d’Hibernate le lazy loading est gère via un Proxy (CGLIB ou Javassist) . Jusqu’à la version 3.3 d’Hibernate, ce dernier utilisait par défaut les Proxy CGLIB. Depuis la version 3.3, il utilise par défaut les Proxy Javassist (il est quand même possible d’utiliser CGLIB si vous renseignez la propriété hibernate.bytecode.provider=cglib dans le fichier hibernate.properties mis dans le répertoire src).

Lorsque le client récupère une entité User via Hibernate, les champs qui sont déclarés en lazy-loading (ex : dans notre cas le champs role) sont associé à des Proxy. J’ai fait des petits tests ou j’ai modifié la base dynaresume pour qu’elle gère l’association User -> Role. Voici une copie d’écran d’une instance User récupérée via JPA/Hibernate :

Cette copie d’écran montre que l’instance User à le champs privé role renseigné avec Role_$$_javassist_1 qui est un proxy Javassist qui est à l’écoute de l’appel de la méthode User#getRole(). A l’appel de cette méthode le proxy teste si le Role est déja chargé et dans le cas contraire il execute une reqête SQL qui charge le Role. C’est pour cela que la méthode User#getRole() doit impérativement être appelée dans une session hibernate ouverte.

Dans le cas d’Eclipselink le lazy loading est géré via la technique du load-time weaving qui consiste à changer le bytecode des classes persistentes, lorsque celle-ci est chargée en utilisant un agent Java (qui est renseigné au lancement de la JVM). Je vous conseille de lire l’article Java Agent – Instrumentez vos classes qui donne des explications sur ce qu’est un agent JAVA.

Il est aussi possible de désactiver le LoadTime Weaver de JPA/Eclipselink. J’explique tout cela dans la section EclipseLink/Load Time Weaver J’ai fait des petits tests ou j’ai modifié la base dynaresume pour qu’elle gère l’association User -> Role.

Voici une copie d’écran d’une instance User récupérée via JPA/Eclipselink AVEC le LoadTimeWeaver configuré (lancé via l’agent Spring):

Cette copie d’écran montre que de nouveau champs _persistence* ont été ajouté à la classe User. Le LoadTimeWeaver permet de modifier le bytecode de la classe User à la volée (a son chargement) pour lui ajouter entre autre des listeners sur la classe User pour surveiller les appels des méthodes de la classe. Le champs privé role est null à la différence d’Hibernate qui est associé à un Proxy.

Voici une copie d’écran d’une instance User récupérée via JPA/Eclipselink SANS le LoadTimeWeaver:

Cette copie d’écran montre que si le LoadTimeWeaver n’est pas activé, le lazy loading ne peut pas s’effectuer, autrement dit l’annotation

@OneToOne(fetch=FetchType.LAZY)

est ignoré.

EclipseLink/Load Time Weaver

Pour régler notre problème de Load Time Weaver avec JPA/Eclipselink, 2 solutions s’offrent à nous :

  1. désactiver le Load Time Weaver. Dans notre cas cette option est acceptable car nous n’avons pas de lazy loading à effectuer.
  2. configurer le Load Time Weaver dans la déclaration du fichier XML Spring et lancer nos classes Java de test en spécifiant à la JVM un agent JAVA.

org.dynaresume.test.jpa_lcfb_withoutLTW

Dans cette section nous allons désactiver le LoadTimeWeaver de JPA/Eclipselink qui consiste simplement à configurer la propriété Eclipselink eclipselink.weaving à false.

Copiez collez le projet org.dynaresume.test.jpa_lcfb_1 et renommez le en org.dynaresume.test.jpa_lcfb_withoutLTW.

Ajoutez la propriété

<property name="eclipselink.weaving" value="false" />

dans les déclaration des properties des persistence-unit de EclipseLink, ce qui donne pour le persistent-unit de dynaresume-eclipselink-derby :

<persistence-unit name="dynaresume-eclipselink-derby"
		transaction-type="RESOURCE_LOCAL">

	<provider>
		org.eclipse.persistence.jpa.PersistenceProvider
	</provider>

	<class>org.dynaresume.domain.User</class>

	<properties>
		<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
		<property name="javax.persistence.jdbc.url" value="jdbc:derby:C:/db/derby/dynaresume" />
		<property name="javax.persistence.jdbc.user" value="" />
		<property name="javax.persistence.jdbc.password" value="" />
		<property name="eclipselink.target-database"
			value="org.eclipse.persistence.platform.database.DerbyPlatform" />
		<property name="show-sql" value="true" />
		<property name="eclipselink.weaving" value="false" />
	</properties>

</persistence-unit>

Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.

org.dynaresume.test.jpa_lcfb_withLTW

Dans cette section nous allons configurer le LoadTimeWeaver de JPA/Eclipselink. Pour cela je vous conseille de lire la documentation officielle de Spring à la section LocalContainerEntityManagerFactoryBean. Selon l’environnement dans lequel notre programme est lancé (Tomcat, Glassfissh, …), Spring fournit une implémentation de LoadTimeWeaver qui se déclare sous forme de bean et qui est injecté au bean entityManagerFactory. Dans le cas ou Spring ne fournit pas de LoadTimeWeaver au contexte d’éxecution du programme, org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver peut être utilisé :

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="loadTimeWeaver">
    <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
  </property>
</bean>

lors du lancement du programme, l’agent Spring Java doit être renseigné dans les paramètres de la JVM :

-javaagent:spring-agent.jar

Depuis la version 2.5 de Spring, il est possible de détecter automatiquement l’implémentatation du LoadTimeWeaver à utiliser en fonction du contexte d’éxécution (Tomcat, Glassfish) à l’aide de la déclaration :

<context:load-time-weaver/>

C’est ce que nous allons utiliser dans cette section. Copiez collez le projet org.dynaresume.test.jpa_lcfb_1 et renommez le en org.dynaresume.test.jpa_lcfb_withLTW.

Ajoutez dans les 2 fichier XML Spring de JPA/Eclipslink applicationContext-eclipselink-derby.xml, et applicationContext-eclipselink-h2.xml, la déclaration :

<context:load-time-weaver/>

Un nouveau namespace context doit être définit :

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
...
	xmlns:context="http://www.springframework.org/schema/context"
	
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
...
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
...
</beans>

Voici le contenu du fichier applicationContext-eclipselink-derby.xml :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume-eclipselink-derby" />
	</bean>

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />	
	
	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	
	<context:load-time-weaver/>
	
</beans>

Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et la console affiche l’erreur suivante :

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Initialization of bean failed; nested exception is java.lang.IllegalStateException: ClassLoader [sun.misc.Launcher$AppClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:spring-agent.jar
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:480)

Cette erreur indique que le programme doit être lancé en spécifiant à la JVM le jar de l’agent Spring. Téléchargezle JAR spring-agent.jar de la distribution Spring que vous pouvez ensuite trouver dans le répertoire spring-framework-2.5.6-with-dependencies/spring-framework-2.5.6/dist/weaving.

Créez un répertoire lib dans le projet org.dynaresume.test.jpa_lcfb_withLTW et ajoutez la librairie spring-agent.jar. Accédez au Launch de la classe FindAllUserDynaresumeDerbyEclipseLink à l’aide du menu Run Configurations…. Sélectionnez le launch FindAllUserDynaresumeDerbyEclipseLink et cliquez sur l’onglet Arguments et ajoutez dans le champs VM Arguments l’agent Java Spring à utiliser :

-javaagent:lib/spring-agent.jar

Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.

REMARQUE : vous pouvez trouvez tous les launch de JPA/Eclipselink (comme expliqué ici) avec LoadTimeWeaver (se terminant par « – SpringAgent ») dans le répertoire launch du projet org.dynaresume.test.jpa_lcfb_withLTW.

org.dynaresume.test.jpa_lcfb_2

Dans les sections précédantes nous avons vu comment régler le problème de LoadTimeWeaver avec JPA/Eclipselink lorsque LocalContainerEntityManagerFactoryBean est utilisé. J’ai fait le choix de désactiver le Load Time Weaver dans cette section et les suivantes car nous n’avons pas de lazy-loading dans notre domaine User. De plus je n’ai pas testé le LoadTimeWeaver dans un contexte OSGi. Si vous êtes intéressés par ce sujet je vous conseille de lire le billet Load-Time Weaving for Spring-DM.

Dans cette section nous allons utiliser les possibilités de LocalContainerEntityManagerFactoryBean qui permet de déclarer dans des bean Spring les informations « provider » et « properties » du fichier JPA persistence.xml.

Copiez collez le projet org.dynaresume.test.jpa_lcfb_withoutLTW et renommez le en org.dynaresume.test.jpa_lcfb_2. Modifiez le fichier persistence.xml pour ne déclarer que les élements « class », comme suit :

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	version="1.0">

	<persistence-unit name="dynaresume"
		transaction-type="RESOURCE_LOCAL">

		<class>org.dynaresume.domain.User</class>

	</persistence-unit>

</persistence>

Comme vous pouvez le constater un seul persistence-unit a été déclaré identifié par son nom dynaresume.

JPA/EclipseLink

Pour utiliser l’implémentation JPA/EclipseLink nous avons déclaré l’élément « provider » du fichier persistence.xml :

<provider>
    org.eclipse.persistence.jpa.PersistenceProvider
</provider>

qui peut aussi se déclarer via un bean Spring jpaVendorAdapter :

<!-- JPA/EclipseLink Vendor with Derby dialect -->
<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
</bean>

qui doit être injecté au bean l’entityManagerfactory :

<bean id="entityManagerFactory"
	class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="persistenceUnitName" value="dynaresume" />
	<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
</bean>

JPA/EclipseLink – Derby

Pour configurer JPA/EclipseLink avec Derby nous avons utilisé les élements « property » du fichier persistence.xml :

<properties>
	<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
	<property name="javax.persistence.jdbc.url" value="jdbc:derby:C:/db/derby/dynaresume" />
	<property name="javax.persistence.jdbc.user" value="" />
	<property name="javax.persistence.jdbc.password" value="" />
	<property name="eclipselink.target-database"
		value="org.eclipse.persistence.platform.database.DerbyPlatform" />
	<property name="show-sql" value="true" />
	<property name="eclipselink.weaving" value="false" />
</properties>

Voici l’explication de ces élements « property » :

Configuration datasource – Derby

Les 4 propriétés de configuration de la datasource Derby sont configurées via des « property » dans le fichier persistence.xml :

<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:derby:C:/db/derby/dynaresume" />
<property name="javax.persistence.jdbc.user" value="" />
<property name="javax.persistence.jdbc.password" value="" />

qui peuvent se traduire via un bean Spring dataSource :

<!-- Derby DataSource -->
<bean id="dataSource"
	class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
	<property name="url" value="jdbc:derby:C:/db/derby/dynaresume" />
	<property name="username" value="" />
	<property name="password" value="" />
</bean>

qui doit être injecté au bean entityManagerFactory :

<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume" />
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
	</bean>
Configuration Platform Derby

La platform (dialect) Derby est configuré dans le fichier persitence.xml via la « property » :

<property name="eclipselink.target-database"
				value="org.eclipse.persistence.platform.database.DerbyPlatform" />

qui peut se configurer dans le bean Spring jpaVendorAdapter via la propriété databasePlatform :

<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
		<property name="databasePlatform" value="org.eclipse.persistence.platform.database.DerbyPlatform" />
	</bean>

Une configuration plus générique de la platform Derby peut s’effectuer via la propriété database qui est un enm Database (ceci évite de devoir mettre la classe de la platform spécifique à l’implémentation JPA) :

<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
	<property name="database" value="DERBY" />
</bean>
Configuration show SQL

La configuration show SQL qui permet de tracer les requêtes SQL est paramétrée dans le fichier persitence.xml via la « property » :

<property name="show-sql" value="true" />

Ceci peut se traduire via le bean Spring jpaVendorAdapter :

<!-- JPA/EclipseLink Vendor with Derby dialect -->
<bean id="jpaVendorAdapter"
	class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
	<property name="database" value="DERBY" />
	<property name="showSql" value="true" />
</bean>
Configuration propriété eclipselink.weaving

La désactivation du LoadTimeWeave qui est une propriété spécifique à JPA/EclipseLink s’effectue dans le fichier persitence.xml via la « property » :

<property  name="eclipselink.weaving" value="false" />

qui peut se traduire via un bean Spring jpaProperties (qui est un java.util.Properties) :

<bean id="jpaProperties"
		class="org.springframework.beans.factory.config.PropertiesFactoryBean">
	<property name="properties">
		<props>
			<prop key="eclipselink.weaving">false</prop>
		</props>
	</property>
</bean>

qui doit être injecté au bean entityManagerFactory :

<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="persistenceUnitName" value="dynaresume" />
	<property name="dataSource" ref="dataSource" />
	<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
	<property name="jpaProperties" ref="jpaProperties" />
</bean>

Modifiez le fichier applicationContext-eclipselink-derby.xml comme suit :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<!-- Derby DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
		<property name="url" value="jdbc:derby:C:/db/derby/dynaresume" />
		<property name="username" value="" />
		<property name="password" value="" />
	</bean>

	<!-- JPA/EclipseLink properties -->
	<bean id="jpaProperties"
		class="org.springframework.beans.factory.config.PropertiesFactoryBean">
		<property name="properties">
			<props>
				<prop key="eclipselink.weaving">false</prop>
			</props>
		</property>
	</bean>

	<!-- JPA/EclipseLink Vendor with Derby dialect -->
	<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
		<property name="database" value="DERBY" />
		<property name="generateDdl" value="false" />
		<property name="showSql" value="true" />
	</bean>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume" />
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
		<property name="jpaProperties" ref="jpaProperties" />
	</bean>

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

</beans>

Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.

JPA/EclipseLink – H2

Nous pouvons effectuer la même chose avec JPA/EclipseLink et H2. Modifiez le fichier XML Spring applicationContext-eclipselink-h2.xml comme suit :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<!-- H2 DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.h2.Driver" />
		<property name="url" value="jdbc:h2:C:/db/h2/dynaresume" />
		<property name="username" value="sa" />
		<property name="password" value="" />
	</bean>

	<!-- JPA/EclipseLink properties -->
	<bean id="jpaProperties"
		class="org.springframework.beans.factory.config.PropertiesFactoryBean">
		<property name="properties">
			<props>
				<prop key="eclipselink.weaving">false</prop>
			</props>
		</property>
	</bean>

	<!-- JPA/EclipseLink Vendor with H2 dialect -->
	<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
		<property name="database" value="H2" />
		<property name="generateDdl" value="false" />
		<property name="showSql" value="true" />
	</bean>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume" />
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
		<property name="jpaProperties" ref="jpaProperties" />
	</bean>

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

</beans>

Relancez la classe FindAllUserDynaresumeH2EclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.

JPA/Hibernate – Derby

Nous pouvons effectuer la même chose avec JPA/Hibernate et Derby en utilisant org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter. Modifiez le fichier XML Spring applicationContext-hibernate-derby.xml comme suit :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<!-- Derby DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
		<property name="url" value="jdbc:derby:C:/db/derby/dynaresume" />
		<property name="username" value="" />
		<property name="password" value="" />
	</bean>

	<!-- JPA/Hibernate properties -->
	<bean id="jpaProperties"
		class="org.springframework.beans.factory.config.PropertiesFactoryBean">
	</bean>

	<!-- JPA/Hibernate Vendor with Derby dialect -->
	<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<property name="database" value="DERBY" />
		<property name="generateDdl" value="false" />
		<property name="showSql" value="true" />
	</bean>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume" />
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
		<property name="jpaProperties" ref="jpaProperties" />
	</bean>

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>


</beans>

Relancez la classe FindAllUserDynaresumeDerbyHibernate et vous pourrez vérifier que la liste des User s’affiche dans la console.

JPA/Hibernate H2

Nous pouvons effectuer la même chose avec JPA/Hibernate et H2. Modifiez le fichier XML Spring applicationContext-hibernate-h2.xml comme suit :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<!-- H2 DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.h2.Driver" />
		<property name="url" value="jdbc:h2:C:/db/h2/dynaresume" />
		<property name="username" value="sa" />
		<property name="password" value="" />
	</bean>

	<!-- JPA/Hibernate properties -->
	<bean id="jpaProperties"
		class="org.springframework.beans.factory.config.PropertiesFactoryBean">
	</bean>

	<!-- JPA/Hibernate Vendor with H2 dialect -->
	<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<property name="database" value="H2" />
		<property name="generateDdl" value="false" />
		<property name="showSql" value="true" />
	</bean>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume" />
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
		<property name="jpaProperties" ref="jpaProperties" />
	</bean>

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

</beans>

Relancez la classe FindAllUserDynaresumeH2Hibernate et vous pourrez vérifier que la liste des User s’affiche dans la console.

org.dynaresume.test.jpa_lcfb_3

A ce stade nous avons 4 fichiers XML Spring qui définissent divers bean (DAO, Datasource, JPA….) qui sont redondants (ex : le bean userService est déclaré dans les 4 fichiers XML Spring). Dans cette section nous allons découper nos déclarations des beans dans plusieurs fichiers XML Spring. Ce découpage nous sera util dans le prochain billet pour découper nos bundles OSGi JPA/DAO.

Voici comment nous allons répartir nos beans dans différents fichiers XML Spring applicationContext :

  • applicationContext-services.xml : déclare le bean service userService.
  • applicationContext-dao-jpa.xml : déclare les beans entityManagerFactory et userDAO (implémentation DAO en JPA). La déclaration du bean entityManagerFactory attend qu’on lui injecte les beans datasource, jpaVendorAdapter et jpaProperties.
  • applicationContext-dao-jpa-*.xml pour chaque implémentation JPA :
    • applicationContext-dao-jpa-eclipselink.xml : qui déclare les beans jpaVendorAdapter et jpaProperties spécifiques à l’implémentation JPA/EclipseLink. La déclaration du bean jpaVendorAdapter attend qu’on lui injecte le bean database qui concerne le dialect à utiliser (DERBY ou H2).
    • applicationContext-dao-jpa-hibernate.xml qui déclare les beans jpaVendorAdapter et jpaProperties spécifiques à l’implémentation JPA/Hibernate. La déclaration du bean jpaVendorAdapter attend qu’on lui injecte le bean database qui concerne le dialect à utiliser (DERBY ou H2).
  • applicationContext-datasource-*.xml pour chaque base de données :
  • applicationContext-dao-jpa-database-*.xml pour chaque base de donnée :

Copiez collez le projet org.dynaresume.test.jpa_lcfb_2 et renommez le en org.dynaresume.test.jpa_lcfb_3.

Services – applicationContext-services.xml

Créez le fichier applicationContext-services.xml dans le package org.dynaresume :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl">
		<property name="userDAO" ref="userDAO" />
	</bean>
	
</beans>

Ce fichier XML Spring déclare le bean service userService qui attend une DAO userDAO.

DAO/JPA – applicationContext-dao-jpa.xml

Créez le fichier applicationContext-dao-jpa.xml dans le package org.dynaresume :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" />

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="dynaresume" />
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
		<property name="jpaProperties" ref="jpaProperties" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

</beans>

Ce fichier XML Spring déclare les beans entityManagerFactory et userDAO (implémentation DAO en JPA). La déclaration du bean entityManagerFactory attend qu’on lui injecte les beans datasource, jpaVendorAdapter et jpaProperties.

Créez le fichier applicationContext-dao-jpa-eclipselink.xml dans le package org.dynaresume :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<!-- JPA/EclipseLink properties -->
	<bean id="jpaProperties"
		class="org.springframework.beans.factory.config.PropertiesFactoryBean">
		<property name="properties">
			<props>
				<prop key="eclipselink.weaving">false</prop>
			</props>
		</property>
	</bean>

	<!-- JPA/EclipseLink Vendor -->
	<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
		<property name="database" ref="database" />
		<property name="generateDdl" value="false" />
		<property name="showSql" value="true" />
	</bean>

</beans>

Ce fichier XML Spring déclare les beans jpaVendorAdapter et jpaProperties spécifiques à l’implémentation JPA/EclipseLink. La déclaration du bean jpaVendorAdapter attend qu’on lui injecte le bean database qui concerne le dialect à utiliser (DERBY ou H2).

DAO-JPA/EclipseLink – applicationContext-dao-jpa-hibernate.xml

Créez le fichier applicationContext-dao-jpa-hibernate.xml dans le package org.dynaresume :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<!-- JPA/Hibernate properties -->
	<bean id="jpaProperties"
		class="org.springframework.beans.factory.config.PropertiesFactoryBean">
	</bean>

	<!-- JPA/Hibernate Vendor -->
	<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<property name="database" ref="database" />
		<property name="generateDdl" value="false" />
		<property name="showSql" value="true" />
	</bean>

</beans>

Ce fichier XML Spring déclare les beans jpaVendorAdapter et jpaProperties spécifiques à l’implémentation JPA/Hibernate. La déclaration du bean jpaVendorAdapter attend qu’on lui injecte le bean database qui concerne le dialect à utiliser (DERBY ou H2).

applicationContext-datasource-derby.xml

Créez le fichier applicationContext-datasource-derby.xml dans le package org.dynaresume :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<!-- Derby DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
		<property name="url" value="jdbc:derby:C:/db/derby/dynaresume" />
		<property name="username" value="" />
		<property name="password" value="" />
	</bean>
	
</beans>

Ce fichier XML Spring déclare un bean datasource avec la configuration de la base de donnée Derby.

applicationContext-datasource-h2.xml

Créez le fichier applicationContext-datasource-h2.xml dans le package org.dynaresume :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<!-- H2 DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.h2.Driver" />
		<property name="url" value="jdbc:h2:C:/db/h2/dynaresume" />
		<property name="username" value="sa" />
		<property name="password" value="" />
	</bean>

</beans>

Ce fichier XML Spring déclare un bean datasource avec la configuration de la base de donnée H2.

applicationContext-dao-jpa-database-derby.xml

Créez le fichier applicationContext-dao-jpa-database-derby.xm dans le package org.dynaresume :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" >

	<bean id="database" class="java.lang.String">
		<constructor-arg>
			<value>DERBY</value>
		</constructor-arg>
	</bean>
	
</beans>

Ce fichier XML Spring déclare un bean database qui retourne la String « DERBY » qui est le dialect Derby à utiliser en JPA.

applicationContext-dao-jpa-database-h2.xml

Créez le fichier applicationContext-dao-jpa-database-h2.xm dans le package org.dynaresume :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" >

	<bean id="database" class="java.lang.String">
		<constructor-arg>
			<value>H2</value>
		</constructor-arg>
	</bean>
	
</beans>

Ce fichier XML Spring déclare un bean database qui retourne la String « H2 » qui est le dialect H2 à utiliser en JPA.

Test JPA

A ce stade nous devons charger plusieurs fichiers XML Spring. Ce code n’est pas spécialement intéressant et vous pourrez le retrouvez dans le zip. Je vais montrer le code de la classe de test JPA avec JPA/EclipseLink et Deby. Pour cela modifiez la classe org.dynaresume.test.jpa.eclipselink.derby.FindAllUserDynaresumeDerbyEclipseLink comme suit :

package org.dynaresume.test.jpa.eclipselink.derby;

import java.util.Collection;

import org.dynaresume.domain.User;
import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FindAllUserDynaresumeDerbyEclipseLink {

	public static void main(String[] args) {

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				new String[] {
						"org/dynaresume/applicationContext-services.xml",
						"org/dynaresume/applicationContext-dao-jpa.xml",
						"org/dynaresume/applicationContext-datasource-derby.xml",
						"org/dynaresume/applicationContext-dao-jpa-database-derby.xml",
						"org/dynaresume/applicationContext-dao-jpa-eclipselink.xml" });

		UserService userService = (UserService) applicationContext
				.getBean("userService");

		Collection<User> users = userService.findAllUsers();
		for (User user : users) {
			System.out.println("User [id=" + user.getId() + " login="
					+ user.getLogin() + ", password=" + user.getPassword()
					+ "]");
		}
	}
}

Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.

org.dynaresume.test.jpa_lcfb_4

A ce stade, les valeurs de la configuration de la base de données se retrouvent en dur dans la déclaration du bean datasource. Il est beaucoup plus propre de mettre ces valeurs dans un fichier de prorpiérés.

Copiez collez le projet org.dynaresume.test.jpa_lcfb_3 et renommez le en org.dynaresume.test.jpa_lcfb_4.

Derby

derby.properties

Créez le fichier derby.properties dans le package org.dynaresume comme suit :

database.driverClassName=org.apache.derby.jdbc.EmbeddedDriver
database.url=jdbc:derby:C:/db/derby/dynaresume
database.username=
database.password=

applicationContext-datasource.xml

Créez le fichier générique de datasource applicationContext-datasource.xml dans le package org.dynaresume :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<!-- DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${database.driverClassName}" />
		<property name="url" value="${database.url}" />
		<property name="username" value="${database.username}" />
		<property name="password" value="${database.password}" />
	</bean>

</beans>

applicationContext-datasource-derby.xml

Jusqu’à maintenant le fichier applicationContext-datasource-derby.xml déclarait le bean datasource. Maintenant ce fichier XML Spring doit s’occuper uniquement de charger le fichier de propriétés derby.properties. Pour cela, modifiez le fichier applicationContext-datasource-derby.xml comme suit :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="propertyConfigurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location">
			<value>classpath:org/dynaresume/derby.properties</value>
		</property>
	</bean>
	
</beans>

H2

h2.properties

Créez le fichier h2.properties dans le package org.dynaresume comme suit :

database.driverClassName=org.h2.Driver
database.url=jdbc:h2:C:/db/h2/dynaresume
database.username=sa
database.password=

applicationContext-datasource-h2.xml

Jusqu’à maintenant le fichier applicationContext-datasource-h2.xml déclarait le bean datasource. Maintenant ce fichier XML Spring doit s’occuper uniquement de charger le fichier de propriétés h2.properties. Pour cela, modifiez le fichier applicationContext-datasource-h2.xml comme suit :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="propertyConfigurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location">
			<value>classpath:org/dynaresume/h2.properties</value>
		</property>
	</bean>

</beans>

Test JPA

Ajoutez dans toutes les classes de test JPA, le chargement du fichier XML Spring « org/dynaresume/applicationContext-datasource.xml », Modifiez toutes les classes Java de test JPA. Voici la classe org.dynaresume.test.jpa.eclipselink.derby.FindAllUserDynaresumeDerbyEclipseLink modifié :

package org.dynaresume.test.jpa.eclipselink.derby;

import java.util.Collection;

import org.dynaresume.domain.User;
import org.dynaresume.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FindAllUserDynaresumeDerbyEclipseLink {

	public static void main(String[] args) {

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				new String[] {
						"org/dynaresume/applicationContext-services.xml",
						"org/dynaresume/applicationContext-dao-jpa.xml",
						"org/dynaresume/applicationContext-datasource.xml",
						"org/dynaresume/applicationContext-datasource-derby.xml",
						"org/dynaresume/applicationContext-dao-jpa-database-derby.xml",
						"org/dynaresume/applicationContext-dao-jpa-eclipselink.xml" });

		UserService userService = (UserService) applicationContext
				.getBean("userService");

		Collection<User> users = userService.findAllUsers();
		for (User user : users) {
			System.out.println("User [id=" + user.getId() + " login="
					+ user.getLogin() + ", password=" + user.getPassword()
					+ "]");
		}
	}
}

Namespace p & applicationContext-datasource.xml

Le fichier applicationContext-datasource.xml qui déclare le bean datasource utilise l’élement property pour configurer la datasource.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<!-- DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${database.driverClassName}" />
		<property name="url" value="${database.url}" />
		<property name="username" value="${database.username}" />
		<property name="password" value="${database.password}" />
	</bean>

</beans>

Cette déclaration est assez verbeuse et il est possible d’utiliser le namespace p concaténé avec le nom de la propriété. Pour cela modifiez le fichier fichier applicationContext-datasource.xml comme suit :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<!-- DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource"
		p:driverClassName="${database.driverClassName}" p:url="${database.url}"
		p:username="${database.username}" p:password="${database.password}">
	</bean>

</beans>

Conclusion

Nous avons vu que l’utilisation de LocalContainerEntityManagerFactoryBean permet de déclarer les informations « provider » et « properties » du fichier JPA persistence.xml via des bean Spring. Nous avons découpé dans plusieurs fichiers XML Spring la déclaration des bean Spring par « module ». Ce découpage nous aidera dans le prochain billet à découper nos bundles qui s’occuperont de la couche DAO.

Vous pouvez lire le billet suivant [step19].

  1. Fred
    mars 29, 2010 à 7:19

    Très intéressant. Vivement l’arrivée des projets Eclipse Virgo et Eclipse Gemini pour industrialiser et standardiser tout ca🙂

    Ce qui serait intéressant dans un prochain billet c’est l’integration de Spring Security pour sécuriser l’accès à la couche business coté serveur.

  2. mars 29, 2010 à 11:16

    Bonsoir Fred,

    >Très intéressant.
    Merci.
    >Vivement l’arrivée des projets Eclipse Virgo et Eclipse Gemini pour >industrialiser et standardiser tout ca🙂
    Oui tout a fait. Nous tentons (Pascal et moi) de suivre un peu ces projets. Concernant Virgo il devrait peut etre intégrer ECF (Eclipse Communication Framework) qui propose notemment de faire du Remoting via le registre de services d’OSGi. J’ai un peu étudié ECF et développé el support Spring pour ECF http://wiki.eclipse.org/Using_Spring_with_ECF_Remote_Services qui va peut etre etre intégré à ECF ou Virgo.

    >Ce qui serait intéressant dans un prochain billet c’est l’integration de Spring >Security pour sécuriser l’accès à la couche business coté serveur.
    C’est un sujet très intéressant mais ce n’est pas prévu. Je dois terminer le billet step19 qui utilise JPA dans un contexte OSGi (qui n’est pas chose facile). De plus mes billets suivent un peu le développement de Dynaresume ou en ce moment on étudie comment transformer l’application RCP en application WEB. On est à létude de ce que propose E4 (SWT for dojo) et RAP (qui est mature).

    J’ai aussi étudié la question d’utiliser du pur Pojo avec JFace Databinding. J’ai proposé à Eclipse mon travail http://wiki.eclipse.org/JFace_Data_Binding/PojoBindable

    Angelo

  3. Fred
    avril 2, 2010 à 11:51

    Ce qui serait vraiment génial avec ECF, c’est le déploiement de services OSGi décentralisé et autonomes.

    Exemple: Un serveur d’application OSGi avec une app business a besoin de faire du reporting via BIRT.

    Il suffirait de démarrer une instance Equinox ou Virgo séparée contenant uniquement tous les bundles nécessaires à BIRT et exposant en Remote ses services de génération de rapports.

  1. mars 22, 2010 à 9:30
  2. avril 27, 2010 à 4:08

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :