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.