JPA et Container JEE

publicité
Cedric Dumoulin
Un peu d’histoire
 Aujourd’hui EJB 3
 Bean Session, Message Driven
 Persistance avec JPA

Classe Java, annotation
 Auparavent – EJB2, EJB 1
 Bean Session, Message Driven
 Persistence par Bean Entity (CMP, BMP)



Classe héritant d’une classe particulière
Des méthodes à implémenter
Difficile !
JPA rappel
Entity
@Entity
public class Todo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String summary;
private String description;
// ...
}
Déclaration d’une
entity
ID
JPA rappel
Utilisation Java
public class Main {
private static final String PERSISTENCE_UNIT_NAME = "todos";
private static EntityManagerFactory factory;
public static void main(String[] args) {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
// read the existing entries and write to console
Query q = em.createQuery("select t from Todo t");
List<Todo> todoList = q.getResultList();
Recuperer
for (Todo todo : todoList) {
l’EntityManager
System.out.println(todo);
}
System.out.println("Size: " + todoList.size());
// create new todo
em.getTransaction().begin();
Todo todo = new Todo();
todo.setSummary("This is a test");
todo.setDescription("This is a test");
em.persist(todo);
em.getTransaction().commit();
em.close();
}
}
Utiliser une TX pour
rendre un objet
persistent
A propos de l’EntityManager
 Si plusieurs objets sont reliés
 Il faut faire l’association (le setXxx() ) entre des
objets gérés par le même EntityManager
  Attention à la création/destruction des EM
 Eviter d’avoir plusieurs EM lors de la
construction/manipulation d’un graphe d’objets reliés.
Exemple : HelloBean
Exemple : HelloBean
Les packages
A déployer dans un container JEE (Glassfish)
Bean Interface
package ipint.atelier1.hellobean;
import java.util.Date;
import javax.ejb.Remote;
@Remote
public interface HelloBean {
public String sayHello();
public Date getCreationDate();
}
BeanImpl
package ipint.atelier1.hellobean.impl;
import java.util.Date;
import javax.ejb.Stateful;
import ipint.atelier1.hellobean.HelloBean;
@Stateful
public class HelloBeanImpl implements HelloBean {
protected Date creationTime = new Date();
public HelloBeanImpl() {
// TODO Auto-generated constructor stub
}
@Override
public String sayHello() {
// TODO Auto-generated method stub
return "Hello The World";
}
public Date getCreationDate() {
return creationTime;
}
}
Client java (pour Glassfish)
import ipint.atelier1.hellobean.HelloBean;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class Main {
public static void main(String[] args) {
try {
// création du "contexte initial" = de la connexion à l'annuaire du serveur
InitialContext context = new InitialContext();
// requête sur le nom de la ressource que l'on veut, ici notre EJB
HelloBean helloWorld =(HelloBean)context.lookup("ipint.atelier1.hellobean.HelloBean");
System.out.println("Id = " + helloWorld.sayHello()) ;
} catch (NamingException e) {
e.printStackTrace();
}
}
public Main() { super(); }
}
Client Web
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page import="ipint.atelier1.hellobean.HelloBean,javax.naming.*"%>
<%!private HelloBean helloBean = null;
public void jspInit() {
try {
InitialContext context = new InitialContext();
helloBean = (HelloBean) context.lookup(HelloBean.class.getName());
} catch (Exception ex) {
System.out.println("Couldn't find bean."
+ ex.getMessage());
}
}
public void jspDestroy() {
helloBean = null;
}
%>
. . .
Client Web (suite)
. . .
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
Calling method (<%=new Date().toString()%>):
<br>
<%=helloBean.sayHello()%>
<br>
Id:<%=helloBean.getCreationDate()%>
<br>
--------------</body>
</html>
JPA et Container JEE
 Permet de gérer la persistance dans un container JEE
 Utilisation similaire à celle hors container,
excepté :
 Récupération de l’EntityManager
 Transaction gérée par le container
 Déclaration de l’unité de persistence (dans
persitence.xml)
JPA et Container JEE
 Récupérer l’EntityManager
 Utilisation
 Le fichier persitence.xml
 La transaction
Récupérer l’EntityManager
 Par injection dans le bean
@PersistenceContext
EntityManager em;
@Stateless
public class PersonCatalog implements PersonCatalogRemote {
@PersistenceContext
EntityManager em;
public PersonCatalog() {
}
public Person createPerson( String firstname, String
lastname, int age) {
Person p = new Person();
p.setFirstName(firstname);
p.setLastName(lastname);
p.setAge(age);
em.persist(p);
return p;
}
}
Récupérer l’EntityManager
2 modes
 Container-Managed Entity Managers
 Le container se charge de créer et d’injecter l’EM
 L’EM est propagé avec la transaction courante
 Comportement par défaut
@PersistenceContext
 Pas thread safe
EntityManager em;
 Application-Managed Entity Managers
 L’application se charge de gérer l’EM

Elle doit le partager ou le communiquer
 Thread safe
@PersistenceUnit
EntityManagerFactory emf;
EntityManager em = emf.createEntityManager();
Utilisation
@PersistenceContext
EntityManager em;
… // Ajout d’un Order à un Customer
public void enterOrder(int custID, Order newOrder) {
Customer cust = em.find(Customer.class, custID);
cust.getOrders().add(newOrder);
newOrder.setCustomer(cust);
}
@PersistenceContext
EntityManager em;
...
public LineItem createLineItem(Order order,
Product product, int quantity) {
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
return li;
}
La TX
n’apparaît
pas !!
JPA dans les EJB
 La transaction (TX) est géré par le container :
 Commence à l’entrée de la méthode
 Termine à la fin de la méthode
  il ne faut pas gérer la transaction
Début TX
Fin TX
@PersistenceContext
EntityManager em;
...
public LineItem createLineItem(Order order,
Product product, int quantity) {
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
return li;
}
Le fichier persitence.xml
 Il faut définir une unité de persistance
 C’est le nom utilisé dans le bean pas l’EntityManager
 Relier cette unité à une datasource
 La datasource devra être déclarée dans le container
 Spécifier les classes Entity
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="ipint.ejb.entreprise" transaction-type="JTA">
<jta-data-source>jdbc/myDatasource1</jta-data-source>
<class>ipint.ejb.entreprise.impl.Person</class>
. . .
</persistence-unit>
</persistence>
Unité de persistance
datasource
Déclaration des entity
Le fichier persitence.xml
Options possibles
 Création ou non des tables lors du déploiement de l’application
 javax.persistence.schema-generation.database.action
 Création a partir des entities ou d’un script
 javax.persistence.schema-generation.create-source
 Script pour peupler la DB
 Voir
 https://docs.oracle.com/javaee/7/tutorial/persistence-intro005.htm
 http://www.thoughts-on-java.org/standardized-schema-generation-data-loading-jpa-2-1/
<persistence …>
. . .
<properties>
<property name="javax.persistence.schema-generation.create-database-schemas"
value="true"/>
<property name="javax.persistence.schema-generation.database.action"
value="drop-and-create"/>
+ options pour eclipslink !!
</properties>
</persistence-unit>
</persistence>
persitence.xml
Le fichier complet
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="ipint.ejb.entreprise" transaction-type="JTA">
<jta-data-source>jdbc/myDatasource1</jta-data-source>
<class>ipint.ejb.entreprise.impl.Person</class>
<properties>
<property name="javax.persistence.schema-generation.create-database-schemas"
value="true"/>
<property name="javax.persistence.schema-generation.database.action"
value="drop-and-create"/>
</properties>
</persistence-unit>
</persistence>
persitence.xml
Editeur de properties
La datasource
 Elle doit être déclaré au niveau du serveur JEE
 Elle spécifie un nom JNDI
 Et une connexion à une BD
 Voir le tuto intro a JEE
 http://programming.manessinger.com/tutorials/aneclipse-glassfish-java-ee-6-tutorial
 Parties 6 et 29 a 32
La transaction
 Le container JEE se charge de la
transaction
 La transaction commence
 Quand on appel une méthode d’un bean
 La transaction se termine
 Quand on quitte la méthode
normalement
 Rollback
 En cas d’exception
TX et Appel de méthode imbriqué
 Et si la méthode du bean appel une autre méthode ?
 Le container crée la TX uniquement si elle n’existe pas déjà
 Comportement par défaut (TX=REQUIRED)
 Ce comportement peut être changé

Cours sur les TX
Les clients
 Ce sont les même que pour une application JEE
 On peut passer une instance de la classe entité entre le
serveur et le client
 Mais elle doit être « Serializable »
Bibliographie
 Introduction to the Java Persistence API
 Chap 37.1 - Java EE 7 Tutorial
 http://docs.oracle.com/javaee/7/tutorial/doc/
 Transactions in Java EE Applications
 Chap 51.1 - Java EE 7 Tutorial
 http://docs.oracle.com/javaee/7/tutorial/doc/
Ateliers
 tp5 – jpaEtContainer
 Atelier 1
 tutoJPAetContainer

Décrit comment installer glassfish avec Derby sous forme de
serveur.
Téléchargement