Documents http://ltiwww.epfl.ch/ProgrammationInternet > J2SE APIs > J2EE APIs http://ltiwww.epfl.ch/WebLang > Bibliographical references > Description of All Components
Applications Web 1 Appel d’une page HTML (browser/telnet), appel d’une servlette (telnet, FORM) Création/appel d’une servlette en WebLang, en WTP 2 La servlette affiche un lien sur le fichier de la FORM. Elle affiche la FORM elle-même. utilisation de sendRedirect 3 Passage des données par String, par Java bean. <Usebean>. Source JSP. Une seule JSP pour le tout. 4 Créer un CMP bean. Voir dans Hypersonic. Initialiser au moyen d’une servlette. 5 Relation pays – ville – capitale. Connecter les composants. Mettre le code dans des session beans. 6 Session bean retournant une collection provenant d’une relation. Parcours de cette relation dans une servlette 7 Villes d’un pays, pays d’une capitale, pays d’une ville. Effacement d’une ville. Remplissage au moyen de ant 8 Test 9 Liste de villes dans un rich client. Client avec un topic. Diffusion de messages. Jeu papier-caillou-ciseaux. 10 Jeu sur une FSM. 11 Struts: bibliothèque. 12 Struts: enregistrement des utilisateurs vérifiés par un manager 13 Test
J2EE Java php Websphere CVS Weblogic Visual Age .net ant RMI Eclipse JDO Hybernate Java J2EE MySQL Javascript HTML Entity Bean JSF Servlet Cookie XML JBoss JSP MDBean taglib Tomcat http://www.topjobs.ch/ Struts Rechercher: J2EE, PHP, Apache
LAMP (pas présenté) DB Linux, Apache, MySQL, PHP Server Client Network Browser DB PHP <html> <head> <title>Test PHP</title> </head> <body> <?php echo ‘Bonjour '; ?> </body> </html> Network
Application Web sur J2EE Tomcat JBoss Server Session EJB DB Client proxy Browser Entity EJB proxy Servlet Entity EJB x.html proxy Network
Pages HTML et Servlettes Livre Software Engineering Sections 7.5, 7.7
Page HTML <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>Tests/test</title> <script type="text/javascript"> function init() { // Javascript alert("Bonjour") } </script> </head> <body onload="init()"> Contenu de la page </body> </html>
Elements HTML <h1>Un grand titre</h1> <p>Un paragraphe</p> <table cellspacing="6" cellpadding="6" border="1" bgcolor="yellow"> <tr> <td bgcolor="#FFE0E0"> ligne1 <br> colonne 1</td> <td bgcolor="#E0E0FF"> ligne1, colonne 2</td> </tr> </table>
Elements actifs dans une form <form method="get" name="record" action="http://localhost:8080/xxxx"> <input type="text" name="txInput1"/> <br> <input type="text" name="txInput2" value="initial"/> <input type="button" name="something" value="button"/> <input type="checkbox" name="checkB1" value="aaa"/>AAA <input type="checkbox" name="checkB2" value="bbb"/>BBB <input type="radio" name="radioB" value="ccc"/>CCC <input type="radio" name="radioB" value="ddd"/>DDD
Sélections <p> <select name="simpleSelection"> <option value="eee">EEE </option> <option value="fff">FFF </option> </select> </p> <p> <select multiple name="multipleSelection"> <option value="hhh">HHH </option> <option value="jjj">JJJ </option> </select> </p>
Autres éléments <p><input type="hidden" name="myValue" value="not_seen"/> </p> <p> <textarea name="thetext" rows="8" cols="80"> ha ! ha ! ha ! </textarea> </p> <p> <button name="button" value="button" type="button"/> Click<br> <img width="100" src="green.gif“ alt="wow"> </button> </p> <p><input type="submit" name="button"/> <input type="reset"/> </p> </form>
Form Envoyé au serveur (une seule ligne) <form method="get" name="record" action="http://localhost:8080/xxxx"> . . . elements des pages précédentes . . . </form> Envoyé au serveur (une seule ligne) http://localhost:8080/xxxx?txInput1= &txInput2=initial &simpleSelection=eee &myValue=not_seen &thetext=+++++ha+!+ha+!+ha+!%0D%0A++ &button=Envoyer
Upload de fichiers <form method="post" name="upform" action="http://localhost:8080/check" enctype="multipart/form-data"> <input type="file" name="uploading"/> <input type="submit"/> </form>
Accès au serveur HTML Browser (client) Tomcat, Apache . . . (serveur) HTML: Test.html <A HREF="URL">link</a> Internet
Servlet Objet généralisé Possède une méthode doGet Serveur Web Browser Servlet doGet() { … } URL avec paramètres Objet généralisé Possède une méthode doGet Est exécuté dans un serveur Web Appelé par un browser
Servlet qui lit les données entrées dans des champs Bouton submit
Formulaire HTML <form action=“http://localhost:8080/test"> <input type=“submit” name=“add“> <input type=“text” name=“val"> </form>
Formulaire HTML (Paragraphe 7.5.2) <form action=“http://localhost:8080/test"> add: <input type=“submit” name=“add"> <p> val: <input type=“text” name=“val"> </form>
Appeler une servlette Browser Serveur JBoss servlet: Test.java HTML page <form action="URL"> <input type = "text" name="field"> </form> servlet: Test.java Internet Exécution de Java page HTML
Servlette: traitement des données public class Test extends HttpServlet { public void doGet ( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { PrintWriter out = response.getWriter(); response.setContentType("text/html"); out.println ("<html><body>"); out.println ("<h1>Title</h1></body>"); } Javadoc J2EE La page html est produite automatiquement quand la méthode se termine.
Classes Http Servlet HttpServletRequest.html, ServletRequest.html HttpServletResponse.html, ServletResponse.html HttpSession.html
Décodage d’un paramètre dans une servlette (voir J2EE Javadoc) <form action="http:www.epfl.ch/servletName//"> http://www.epfl.ch/servletName?txtInp=yyy <input type = text name = "txtInp"> Servlette yyy
Décodage d’un paramètre dans une servlette (voir J2EE Javadoc) Navigateur http://www.epfl.ch/servletName?txtInp=yyy valueParam = request.getParameter("txtInp"); dans la servlette valueParam.equals("yyy") Java
Production du contenu d’une page HTML par une servlette java.io.PrintWriter out = response.getWriter(); out.println(“<h1>Titre</h1>”);
WebLang Crée les sources des composants, les fichiers auxiliaires et les fichiers ant
Fichier .cg http://ltiwww.epfl.ch/WebLang/Modules.html#servlets @@deploypath="C:/jboss-4.2.3.GA/server/default/deploy/" servlet SomeServlet { package servletPack; public void someCall (PrintWriter out, String name, double number) { out.println(name + " " + number); }
Module servlet en WebLang servlet TestServlet { package packageName; int attribute; // dangereux public void add ( PrintWriter out, int number) { attribute += number; out.println(attribute); } public void sub (int number) { attribute = number; determine la form HTML
WebLang génère les fichiers: html: InputForms <FORM action= "test"> a b m1 c m2 servlet: Test.java doGet() { . . . } m1(int a, String b) { ... } m2(String c, long d) { ... }
Avec plus de détails html: InputForms servlette: Test.java <form action= "test"> <input ... name="a"> <input ... name="b"> <submit name="m1"> </form> <input ... name="c"> <submit name="m2"> servlette: Test.java doGet() { a = getParameters(“a”); m1(a, b); or m2(c, d); } m1(int a, String b) { ... } m2(String c, long d) { ... }
Préparation et chargement d’une servlette Eclipse fichier.cg CodeGen myServlet.java @web doGet() { } xdoclet packaging web.xml projet.ear WebLang Navigateur Serveur web.xml myServlet.java myPage.html
Compilation d’un fichier.cg bouton droit de la souris Compilation d’un fichier.cg
Déploiement d’un projet WebLang Run As… > CGxdoclet.xml Run As… > CGpackaging.xml
Démarrer le serveur JBoss Il est possible de gérer le serveur JBoss, ou d’autres serveurs à partir d’Eclipse. Les manipulations de préparation sont présentées ci-dessous. Ces manipulations préparent en même temps les librairies nécessaires aux projets J2EE http://ltiwww.epfl.ch/WebLang/JBossInit
Nettoyer les programmes dans JBoss Eliminez les programmes et structures laissés par l'étudiant précédent. Pensez à le faire dans les leçons suivantes également ! Effacez les répertoires tmp, data, log et work qui se trouvent dans C:\jboss-4.2.3.GA\server\default Effacez tous les fichiers se terminant par .ear (pour archive) ou .war se trouvant dans C:\jboss-4.2.3.GA\server\default\deploy Pour arrêter JBoss, cliquer le carré rouge dans la fenêtre serveur et attendez qu’il se termine!
Singleton (pour l’exercice) Une seule instanciation, à la première utilisation. public class BD { private static BD localBD = null; public static BD getBD() { if (localBD==null) { localBD = new BD(); } return localBD; private String name; // autres paramètres // utilisation BD.getBD().list();
Définition d’une classe en WebLang class MyClass { package aPackage; import java.util; access remote; // optional, default is local outputchannel myCh (queue, A); // future Bean bean; public void aMethod() throws Exception { System.out.println("a method called"); Bean b = beanHome.create(); // future b.method(); } Génère une classe habituelle et introduit les références et fonctions qui permettront de la charger dans le serveur.
Affichage pour dépanner System.out.print(“xxx”); affiche ses sorties dans la console d’Eclipse
Exercice 1: une application Web nom incorrect Servlet login() cancel() Page HTML entrée Singleton (à la place d’une base de données) correct Servlet store(String x) list() quit() Page HTML entrée transition entre états introduction de données
Structure et scripts d’un projet JEE
Structure d’un projet JEE servlets librairies JEE fichier d’appel de tous les objets générés fichiers d’appel des méthodes des servlets JSP définition des servlets scripts ant de préparation tout est génére à partir de ce fichier
xDoclets Outil standard pour créer une partie des fichiers indiqués dans les pages précé- dentes http://xdoclet.sourceforge.net/xdoclet/index.html
xDoclet crée le fichier web.xml import javax.rmi.PortableRemoteObject; . . . /** * @web.servlet * name = "MyServletServlet" * display-name = "TestServlet" * description = "A simple Servlet" * @web.servlet-mapping * url-pattern = "/MyServlet" */ public class TestServlet extends HttpServlet { public void doGet (HttpServletRequest request,
Script ant pour appeler XDoclet généré automatiquement par WebLang <?xml version="1.0" encoding="UTF-8" ?> <project default="N2" name="XDoclet Generator"> <path id="xdoclet.classpath"> <pathelement location="C:/jboss-4.0.4.GA/server/default/lib/javax.servlet.jar"/> <fileset dir="C:\eclipse\xdoclet_lib/"> <include name="*.jar" /> </fileset> </path> <target name="N2" description="Servlet/Taglib"> <taskdef classpathref="xdoclet.classpath“ classname="xdoclet.modules.web.WebDocletTask“ name="webdoclet" /> <webdoclet destDir="WEB-INF" verbose="true" mergeDir="WEB-INF/merge"> <fileset dir="src"> <include name="package/AServlet.java" /> <deploymentdescriptor Servletspec="2.3" /> </webdoclet> </target> </project>
Contenu de web.xml généré automatiquement par xdoclet <servlet> <servlet-name>MyServletServlet</servlet-name> <display-name>MyServlet</display-name> <description><![CDATA[A simple Servlet]]></description> <servlet-class>serv.MyServlet</servlet-class> </servlet> <servlet-mapping> <url-pattern>/MyServlet</url-pattern> </servlet-mapping> <!-- look for "servlet-name" tutorial in Google! -->
CGPackaging.xml <!--********************WEB class*******************--> <target name="WEB" description="Lecon3.war"> <jar destfile="lib/Lecon3.war"> <zipfileset dir="WebContent/WEB-INF" prefix="WEB-INF"> <include name="*.xml"/> <include name="*.wsdd"/> </zipfileset> <zipfileset dir="WebContent/WEB-INF/lib" prefix="WEB-INF/lib" includes="**/*.jar"/> <zipfileset dir="bin" prefix="WEB-INF/classes"> <include name="applicationWeb/Login*.class"/> <include name="applicationWeb/Manage*.class"/> <zipfileset dir="lib" prefix="WEB-INF/lib"> <include name="Lecon3-CL.jar"/> <zipfileset dir="WebContent" prefix=""> <include name="appliWeb/Manager.jsp"/> <include name="applicationWeb/Login.html"/> <include name="applicationWeb/Manage.html"/> </jar> </target>
Session de client (Paragraphe 7.8.5) Chaque client a une zone pour ses variables Lié à la session par les cookies La servlette retrouve les variables de l’appelant automatiquement
Objets de session dans des servlettes Client 2 Client 21 Serveur Client 1 (cookie) Servlet y = session.getAttribute("xx"); Java bean “xx” Client 2 (cookie) Java bean “xx”
Trouver les Java beans dans la session public public void doGet ( HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); MyObject myObject = new MyObject (); session.setAttribute("myObject", myObject); x = session.getAttribute("myObject"); . . .
JSP: Java Server Page (Section 7.8) JSP (exécuté sur le serveur) ≠ Javascript (exécuté dans le browser) http://java.sun.com/products/jsp/docs.html voir Servlets and JavaServer Pages: A Tutorial
Comparaison servlettes - JSPs public class Test extends HttpServlet { public void doGet (request, response) { out.println ("<html><body>"); out.println ("<h1>"); out.println ( x.toString() ); out.println ("</h1></body>"); } } Servlette <html><body> <h1> <%= x.toString() %> </h1></body JSP
Création d’une JSP JSP ( code ) ( + ) ( html ) Servlet Java source JSP compilateur Java compilateur Exécution JSP ( code ) ( + ) ( html ) Servlet Java source Servlet Java code html html serveur browser http://www.ch/xxxx.jsp Réseau
Exemple d’une page JSP (Vue globale) <html> <head><title>File</title></head> <body> <h1>Example</h1> <%! declarations %> <% code Java %> Nouvelle valeur de l'attribut: <%= attribute %> <p> <form action="http://localhost:8080/Exercice3-WEB/File.jsp"> <input type="text" name="attribute"/> <input type="submit"/> </form> </body> </html>
Page JSP: déclaration <%! declarations %> <!-- déclaration d’attributs Attention, le même objet servlette est partagé par tous les clients -->
Page JSP: affichage Affichage d’une valeur de variable: Affichage du retour d’une méthode: <%= myClass.text() %> <% // Java code out.println( "Text <p>" ); %>
Conditional statements <% if (error!=null) { %> <b>Error: <%=error.message()%><b> <% } %>
Conditional statements (code généré) if (error!=null) { out.print(“<b>Error:”); out.print(error.message(); }
URL d’une JSP http://localhost:8080/Exercice3/File.jsp
Autres instructions JSP <%@ pageimport="packName.*" %> request, response et session sont définis par défaut dans une JSP
Standard Tags JSP jsp:include jsp:useBean jsp:setProperty jsp:getProperty jsp:forward jsp:plugin http://java.sun.com/products/jsp/docs.html Voir 2.0 PDF ou HTML et Servlets and JavaServer Pages: A Tutorial
Applet <jsp:plugin type="applet" code="package.HorlogeApplet" width="370" height="50"> </jsp:plugin>
Session / Java bean <jsp:useBean id = "myForm" scope = "session" class = "app.InputForm" /> <jsp:setProperty name = "myForm" property = "attribute" value ="<%= x %>" /> class InputForm { int attribute; // getter/setter créés au moyen d’Eclipse }
Utiliser un tag non standard Définition: <%@ taglib uri = "pack/myTag.tld" prefix = "tag"%> Utilisation: <tag:myTag/>
Classe tag Correspondante package pack; import java.io.IOException; /** * @jsp.tag * name = "myTag" * description = "A test class for tags" */ public class myTag extends TagSupport { public int doStartTag() { JspWriter out = pageContext.getOut(); out.println("I am a tag"); return 33; } } Classe tag Correspondante
Description d’un tag: MyTag.tld Créé par les xDoclets ?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>xdoclet-build</short-name> <tag> <name>myTag</name> <tag-class>pack.myTag</tag-class> <description><![CDATA[A test class for tags]]></description> </tag> </taglib>
Où se retrouve le fichier JSP compilé en Java? C:\jboss-4.0.0\server\default\work… (n’est compilé que lorsqu’on l’appelle)
Java bean package p; public class Result implements Serializable { public Result() { } // optionnel int xxx; public int getXxx() { return xxx; } public void setXxx(int xxx) { this.xxx = xxx; Dans Eclipse: sélectionner int xxx clic-droit sur la sélection Source > Generate Getter…
Utilisation d’une session et d’un Java bean sendRedirect Page HTML Servlet Page JSP Servlet Session client (cookies) Java bean Java bean Java bean
Architecture de l’exercice 1 Java Bean Résultat Page.jsp Affichage résultat Nouvelle entrée Servlette.java Calcul
Architecture de l’exercice 2 Même Page.jsp Page.jsp Calcul + Affichage résultat Nouvelle entrée Page.jsp Calcul + Affichage résultat Nouvelle entrée Java bean Résultat
Database access with the help of persistent objects EJB: Enterprise Java Beans
Web Application (J2EE) DB Server Client Network Container Container JBoss Server Container Container Session EJB Entity EJB DB Client Tomcat Browser Servlet proxies Container Entity EJB x.html Network
Client-server Application (J2EE) JBoss Container Container Client Session EJB Entity EJB Client proxies DB Container Network Entity EJB
CMP entity beans (Container Managed Persistency) BMP, Bean Managed Persistency will not be studied as there are better alternatives
Specification of CMP entity beans in WebLang CMP bean: relations methods attributes finders / creators
Definition of an object in WebLang cmpbean Town { package geo; String name; // DB attributes int numero; public void myMet (String s) { System.out.println(s); } // creators - finders
CMP Bean: method create cmpbean Person { package beans; String firstName; String lastName; // attributes = DB columns int age; public Person createPerson ( String firstName, String lastName ); // age not initialised } // the arguments of the create must correspond // to the attributes. They are stored in the latter.
Creation and use of an object in WebLang Town t ; Country c ; t = townHome.create("Lausanne"); c = countryHome.create("Switzerland"); System.out.println( t.getName() ); c.setName( "Suisse" );
CMP Bean: finder method Town findByName (String s) { query = "SELECT OBJECT(o) FROM Town o WHERE o.name=?1" } // more details later
Find an object in WebLang Town t ; try { t = townHome.findByName("Lausanne"); } catch (javax.ejb.FinderException fe) { t = townHome.create("Lausanne"); } System.out.println( t.getNumber() );
Servlet using a bean servlet myservlet { package servlets; public void newPerson ( PrintWriter out, String firstName, String lastName, int age) throws Exception { Person aPers; aPers = personHome.createPerson (firstName, lastName); aPers.setAge(age); } // it is a simple means to test CMP beans, an html // file that calls this servlet is created automatically
Java Client (remote) jclient Ouf { package clientPack; public void method1 (String s1, String s2) { Person aPers; Course aCourse; aPers = personHome.createPerson("a", s1); aCourse = courseHome.createCourse("prof", s2); } // WebLang generates automatically a remote access
Reading the HSQLDB database http://localhost:8080/jmx-console Select: service=Hypersonic (fifth line under jboss) Select invoke (below startDatabaseManager) Look at the task bar and let the DB window appear. Click View/Refresh tree in this window Examine the tables (Command > Select …)
Fichiers auxiliaires des CMP entity beans (générés par WebLang et par XDoclet)
Files generated by WebLang and by the xDoclets src/control Game.java GameCMP.java GameLocalHome.java GameLocal.java GameHome.java GameUtil.java sources of the beans interfaces of the proxies
Parts of a CMP entity bean EJBContainer servlet other EJB XxxxLocalHome create findByPrimaryKey Xxxx ejbCreate ejbPostCreate ejbFindByPrimaryKey ejbLoad ejbStore userMethods XxxxEntityBean XxxxLocal userMethods
Instantiation of a persistent object InitialContext lookup 1 XxxxHomeProxy create findByPrimaryKey 2 client servlet bean XxxxObjectProxy userMethods EJB EJB XxxxObjectProxy userMethods EJB XxxxObjectProxy userMethods 3
Lookup to get a home proxy TownLocalHomeProxy townLocalHomeProxy = null; Context context = new InitialContext(); Object ref = context.lookup("store_PersonLocal"); townLocalHomeProxy = (TownLocalHomeProxy) PortableRemoteObject.narrow ( ref, TownLocalHomeProxy.class ); // narrow = cast from object to TownLocalHomeProxy
Class specifying a CMP entity bean package store.ejb; import javax.ejb.EntityBean; import javax.rmi.PortableRemoteObject; /** * @ejb.bean * name = "Customer" * display-name = "CMP Entity Bean" * description = "Description of the CMP Entity Bean" * view-type = "both" * type = "CMP" * primkey-field = "pk" * jndi-name = "store_CustomerRemote" * local-jndi-name = "store_CustomerLocal" * @ejb.pk * class ="java.lang.Long" */ public abstract class Customer implements EntityBean { EntityContext entityContext; . . .
CMP entity bean (primary key) /** * Attribute Pk is used as primary key by default. * @ejb.persistent-field */ public abstract java.lang.Long getPk(); public abstract void setPk(java.lang.Long pk); * Default remove method * @throws RemoveException * @ejb.remove-method public void ejbRemove() throws RemoveException { }
CMP entity bean: Attributes /** * A pair of getter / setter for each attribute * * @ejb.persistent-field * @ejb.interface-method * view-type = "both" */ public abstract String getAtt() ; public abstract void setAtt(String att) ;
Control files generated by the xDoclets META-INF ejb-jar.xml jboss.xml jbosscmp-jdbc.xml
Extrait de ejb-jar.xml (src/META-INF) <display-name>CMP Entity Bean</display-name> <ejb-name>Patient</ejb-name> <home>predimed.PatientHome</home> <remote>predimed.Patient</remote> <local-home> predimed.PatientLocalHome </local-home>
Fichier.ear deploy Fichier.ear application.xml // références les fichiers ci-dessous Fichier.jar // contient les EJBs Fichier.war // contient les servlettes, passé à Tomat <module> <ejb>Test.jar</ejb> </module> <module> data/jboss-app/application.xml <web> <web-uri>Test.war</web-uri> <context-root>/Test</context-root> </web>
Session beans (Pattern de façade)
Collections gérées par une session bean Server collection JBoss Entity EJB Client Session EJB Entity EJB Entity EJB Browser Servlet proxies Entity EJB proxies proxies Network Les collections (relations) doivent être gérées dans des session ou CMP beans
Une session bean en WebLang sbean ControllerSession { package beans; state Stateful; // optionnel String st; public ControllerSession create (String st); public void newPerson (String firstName, String lastName, int age) throws Exception { Person aPers; aPers = personHome.createPerson(firstName, lastName, age); } }
Bean Managed Transaction sbean ControllerSession { package beans; (Container managed transaction) transaction Bean; // optionnel, par défaut une CMT est créée state Stateful; // optionnel String st; public ControllerSession create (String st); public void newPerson (String firstName, String lastName, int age) throws Exception { Person aPers; beanContext.getUserTransaction().begin(); // optionnel aPers = personHome.createPerson(firstName, lastName, age); beanContext.getUserTransaction().commit(); // abort() } }
Relations entre CMP beans
1:N Relation Y X N 1 4 23 8 5 WebLang, object view: cmpbean X { relation <hasY 1:N hasX> Y; } 23
1:1 Relation (bidirectionnelle) Y X 23 4 23 WebLang: cmpbean X { relation <hasY 1:1 target hasX> Y; } cmpbean Y { relation <hasX 1:1 hasY> X;
N:M Relation 23 4 27 X 8 Y 24 23 5 5 23 8 27 8 24 4
N:M Relation (toujours bidirectionnelle) WebLang: cmpbean X { relation <possessesY N:M hasX> Y; …attributes… } cmpbean Y { relation <hasX N:M possessesY> X;
xdoclets pour les relations /** * Implementation of the relationship: getCollection * @ejb.interface-method * view-type = "local" * @ejb.relation * name="Courses-Students-NM" * role-name="Courses-N-role" * target-ejb="Students" * target-role-name="Students-M-role" * target-multiple="yes" * @jboss.relation-mapping * style="relation-table" * @jboss.relation-table * table-name="CoursesXStudents" * @jboss.relation * related-pk-field = "pk" * fk-column="students_pk" * fk-constraints = "false" * @jboss.target-relation * fk-column = "courses_pk" */ public abstract java.util.Collection getStudentsN(); xdoclets pour les relations
Operations concernant les relations entre beans (WebLang)
Relations utilisées dans les pages suivantes cmpbean Country { relation <hasCapital 1:1 isCapitalOf> Town; relation <hasTown 1:N isLocatedIn> Town; } cmpbean Town { relation <isCapitalOf 1:1 hasCapital> Country; relation <isLocatedIn N:1 hasTown> Country;
Utilisation d’une référence bidirectionnelle 1:1 Country-Capital Town t = townHome.create("Bern"); Country c = countryHome.create("Switzerland"); t.setIsLocatedIn(c); System.out.println( t.getIsLocatedIn().getName() ); // setIsLocatedIn est automatiquement définie quand on spécifie la relation isLocatedIn
Addition d’un élément à une relation Country (1) – Town (N) Town v ; Country c ; t = townHome.create("Lausanne"); c = countryHome.create("Switzerland"); t.setIsLocatedIn(c); // 1:1 side t = townHome.create("Bern"); c.addHasTown(t); // 1:N side
Déposer une relation et y accéder Collection collection = aCountry.getHasTown(); Iterator it = collection.iterator(); while (it.hasNext()) { // Java 1.4 System.out.println( ( (Town) it.next() ) .getName() ); }
Déposer une relation et y accéder Collection collection = aCountry.getHasTown(); for (Object o: collection) { // Java 1.6 System.out.println( ( (Town) o ) .getName() ); }
addHasTown est introduit par WebLang void addHasTown(t) { getHasTown().add(t); } // standard add et remove de Collections // ajouté automatiquement par WebLang removeHasTown(t) { getHasTown().remove(t); Les collections doivent être manipulées à l’intérieur de transactions
Résumé des relations et de leurs méthodes indication in Xxxx Other end in Yyyy methods available <elemY 1:1 elemX> Yyyy no relation <elemX 1:1 target elemY> Xxxx <collX 1:N elemY> Xxxx Yyyy y = getElemX() setElemX(yyyy) <elemY 1:1 target elX> Yyyy no relation <elX 1:1 elemY> Xxxx Yyyy y = getElemY() setElemY(yyyy) <collY 1:N elemY> Yyyy no relation <elemX N:1 collY> Xxxx Collection y = getCollY() setCollY(collection) addCollY(yyyy), removeCollY(yyyy) <collY N:M collX> Yyyy no relation <collX N:M collY> Xxxx
Comparaisons entre objets CB h1 = cBHome.create("5"); CB h2 = cBHome.findH("5"); if (h1 == h2) ; // pas valable ! if (h1.getPrimaryKey().equals(h2.getPrimaryKey()) System.out.println("2 x the same bean"); if ( ((Long)h1.getPrimaryKey()).intValue() == ((Long)h2.getPrimaryKey()).intValue()) System.out.println("2 x the same bean");
(voir exemple du paragraphe 11.2.6.8) Finders http://ltiwww.epfl.ch/~petitpie/ProgrammationInternet/ejb-2_1-fr-spec.pdf (voir exemple du paragraphe 11.2.6.8)
Finder retournant un objet ( WebLang ) Course findCourse (java.lang.String name) { query = "SELECT OBJECT(o) FROM Course o WHERE o.courseName=?1" }
Source d’un finder /** * Pays CMP Entity Bean * * @ejb.bean * name = "Pays" * display-name = "CMP Entity Bean" * description = "Description of the CMP Entity Bean" * view-type = "both" * type = "CMP" * primkey-field = "pk" * jndi-name = "geo_PaysRemote" * local-jndi-name = "geo_PaysLocal" * @ejb.pk * class ="java.lang.Long" * @ejb.finder * signature = "java.util.Collection findByVilleAvecM (java.lang.String s)" * query = "SELECT OBJECT (p) FROM Pays p, IN (p.contient) v WHERE v.nom LIKE CONCAT(?1, '%')" * @generated */ public abstract class PaysBean implements EntityBean { Source d’un finder
Build/classes/META-INF/ejb-jar.xml <query> <query-method> . . . <query> <query-method> <method-name>findVille</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <ejb-ql><![CDATA[SELECT OBJECT(v) FROM Ville v WHERE v.nom=?1]]> </ejb-ql> </query>
Tester si un objet existe en WebLang Country c = null; try { c = countryHome.findByName("Switzerland"); } catch (javax.ejb.FinderException fe) { c = countryHome.create("Switzerland"); }
Finder retournant une collection (ici la table entière) java.util.Collection findCourses () { query = "SELECT OBJECT(o) FROM Course o" } Note: les collections retournées par les finders peuvent être manipulées dans servlets.
Références cascadées 1:1 Option findOptionByProf (java.lang.String profName) { query = "SELECT OBJECT(s) FROM Option o WHERE o.course.profName=?1" } // le finder doit être inclus dans le CMP bean // qui définit l’objet retourné
Relation 1:1 retournant une collection de membres appartenant à la relation public java.util.Collection findCountryByCapital (java.lang.String capital) { query = "SELECT c.capital FROM Country c WHERE c.capital.name LIKE CONCAT('_', CONCAT(?1, '%‘)) " } // On utilise une collection, parce qu’on suppose que // plusieurs beans peuvent correspondre au même critère
Relation 1:N Country <contains 1:N isIn> Town public java.util.Collection findCountryByTownName (java.lang.String name) { query = Country "SELECT OBJECT(c) FROM Country c, IN (c.contains) t WHERE t.name=?1" }
Relations 1:N cascadées Country : contains Town : hasNb Number public java.util.Collection findCountryByNumber (int number, java.lang.String name) { query = "SELECT OBJECT(n) FROM Country c, IN (c.contains) t, IN (t.hasNb) n WHERE c.name = CONCAT("%", ?2) AND n.value < ?1" }
Relations cascadées A 1:1 B 1:1 C 1:1 D - dd public A findAByX (java.lang.String name) { query = "SELECT OBJECT (o) FROM A o WHERE o.b.c.d.dd=?1" }
Relations cascadées An 1:N Bn 1:N Cn 1:N Dn - dd public java.util.Collection findA(java.lang.String name) { query = "SELECT OBJECT (o) FROM An o, IN(o.bnN) bx, IN(bx.cnN) cx, IN(cx.dnN) dx WHERE dx.dd=?1" }
Relations en cascade (la query retourne un An) An 1:1 Bn 1:N Cn 1:1 Dn - dd public java.util.Collection findAn (java.lang.String name) { query = "SELECT OBJECT (o) FROM An o, IN(o.bn.cnN) cx WHERE cx.dn.dd=?1" } // à introduire dans un bean An
(la query retourne un Bn) Relations en cascade (la query retourne un Bn) An 1:1 Bn 1:N Cn 1:1 Dn - dd public java.util.Collection findBn (java.lang.String s) { query = "SELECT o.bn FROM An o, IN(o.bn.cnN) cx WHERE o.aa=?1" } // à introduire dans un bean Bn car il retourne une // collection de Bn
Transactions
Transactions dans les session beans transaction Bean; La transaction n’est pas gérée automatiquement, le développeur doit insérer le code qui la gère.
Relation N:M manipulée depuis une session bean Cours Etudiants N M Expérience: Enregistrer un étudiant dans un cours Voir si l’étudiant est visible depuis le cours
beanContext.getUserTransaction().begin(); s1.addCourse(c1); // s1, s2 are students and s1.addCourse(c2); // c1,c2 courses s1.addCourse(c3); s2.addCourse(c3); System.out.println("Additions terminées"); Thread.sleep(10000); // suspendue pendant 10 sec pour voir // dans la base de données for (Students s : c3.getStudentsN()) { System.out.println("c3.collection"+s.getName()); } beanContext.getUserTransaction().commit();
Transactions CMP Bean A Transaction présente avant d’entrer B CMP Bean B Transaction crée par le conteneur pour B
Dans le CMP bean (WebLang) transaction RequiresNew; Dans la méthode du CMP bean beanContext.setRollbackOnly();
Transaction avant l’exécution Types de transaction Type de transaction Transaction avant l’exécution Réaction du conteneur Required présente aucune est gardée une nouvelle RequiresNew Mandatory erreur
Appels locaux/distants Les programmes situés sur des ordinateurs autres que le serveur peuvent accéder à une session beans ou une CMP entity beans de la même manière que les servlets ( mais par le biais de XxxRemoteHomeProxy ) Il ne peuvent pas manipuler les relations des CMP beans (pour plusieurs raisons)
Classes / jclients de WebLang WebLang gèrent les home interfaces, les entités CMP et les noms des classes des session beans de même que les input/output channels dans la plupart des modules En particulier dans les jclients et dans les classes. Note: les classes doivent contenir l’indication access Remote; si elles ne sont pas dans le serveur.
class or jclient Module jclient Ouf { package clientPack; inputchannel varName (topic, "TopicName") { … } void method1 (String s) { Person aPers; Course aCourse; aPers = personHome.createPerson(s+"pers"); // CMP bean aCourse = courseHome.createCourse(s+"course"); } void method2 () { List aList; String str = "Text = "+listHome.create().text(); // session bean System.out.println(str); } }
Struts
Basic structure of struts PersonManagement SportManagement Servlet Servlet Servlet Servlet JSP JSP sport person sportName location personName sportForm The forms are saved in the HTTP session Under the name derived from the class ! personForm
Output of data (same for input) sportForm location Struts sportForm.setLocation("xxx") JSP <bean:write name="sportForm" property="location"/> <html:text name="location"/> No direct connection !
Basic structure of struts PersonManagement SportManagement Servlet Servlet Servlet Servlet JSP JSP sport person 2 1 3 personName sportName location personForm sportForm The forms are saved in the client session Under the name derived from the class !
1 Librairies Struts: Action Form ( = java bean ) /** * @struts.form name="personForm" */ public final class PersonForm extends ActionForm { private String name; public String getName() { return (this.name); } public void setName(String name) { this.name = name; } // ActionForm has code to fill in the form from the URL
2 Librairie JSP pour Struts: HTML Form JSP: input.jsp <h3>personForm.sportForm</h3> <html:form action="/personManagement"> sportName <html:text property="name"/> <html:submit/> </html:form> // Plusieurs paramètres de l’action sont définis dans struts-config.xml // en particulier une form est attribuée à cette action et name est le nom d’un // champ de cette form
3 Struts: Action Servlet public final class PersonManagement extends Action { PersonForm f; public ActionForward execute (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { try { f = (PersonForm) form; f.getName(); return (mapping.findForward("sport")); } catch(Exception e) { // trap exceptions that may occur in your servlet e.printStackTrace(); // you will get better error messages ! return (mapping.findForward("error")); } } } // L’action form passèe comme argument est automatiquement // remplie à partir des arguments de l’URL 3 Struts: Action Servlet
Fichier auxiliaire: struts-config.xml (généré par xDoclet) <action-mappings> <action path="/personManagement" type="management.PersonManagement" // servlet class name="personForm" // name in HTTP session scope="session" input="/pages/Error.jsp" unknown="false" validate="true" > <forward name="sport" // name that can be used as next page path="/pages/sport.jsp" redirect="false" /> </action>
Action Forms CMP Beans Main personForm[] Action forms Course Person[] PersonForm finder ou getCollection Person Recrée une collection et copie ses éléments dans l’autre collection CMP beans // code prochaine page
Action Forms CMP Beans Course Person[] per Main personForm[] per PersonForm PersonForm Person Person Pseudo-code course.setPer( new ArrayList() ) for (each main.per[]) { x = personHome.create(per[].attributes) course.addPer(x) }
- Action forms, - arrays of action forms, - trees of action forms
Java beans composés person In/out Action Action In/out Input sport job SportManagement In/out PersonManagement Action Action In/out Input sport job jobName location personName jobName location sportName location jobName location personName jobName location jobName location sportForm[ ] jobName location jobName location Pas supporté jobName location personForm jobForm[] sportName location jobForm[ ] sportForm // Toutes les Action Form envoyées à // une action doivent avoir le même type
Tree of action forms /** * @struts.form name="personForm" */ public final class PersonForm extends ActionForm { . . . private SportForm sportForm; // sub-form public SportForm getSportForm () { return (this.sportForm); } public void setSportForm (SportForm sportForm) { this.sportForm = sportForm;
Array of sub-action forms ( x[ ] or Collection or Set ) /** * @struts.form name="personForm" */ public final class PersonForm extends ActionForm { . . . private Collection sportForms; public Collection getSportForms () { return (this.sportForms); } public void setSportForms (Collection sportForms) { this.sportForms = sportForms;
Reference to an attribute of an Action Form In the action servlet f.getName(); In the JSP <html:text property="name"/> the form in which name is looked for is linked to the JSP by a definition introduced in struts-config.xml
Reference to an attribute of a Sub-Action Form In the action servlet f.getSportForm().getName(); In the JSP <html:text property="sportForm.name"/> the form is linked to the JSP within struts-config.xml
Reference to an array of Sub-Action Forms In the action servlet (first element ! ) o = ((ArrayList) f.getSportForms(); name = ((SportForm) o.get(0)).getName(); // f is linked to the JSP in struts-config.xml In the JSP <html:text property="sportFormN[0].name"/> // The element passed to the property can be // an ArrayList or an array such as String[]
Tags in the JSP and the Struts <jsp:useBean id="managementForm" scope="session" class="man.ManagementForm"/> <bean:write name="managementForm" property="warning" filter="false"/> // prints the value of the property on the page http://localhost:8080/struts-documentation http://ltiwww.epfl.ch/WebLang/references.html
HTML form in a JSP <h3>PetForm</h3> <html:form action="/Supplier_State_0_Action" > <html:hidden name="petForm" property="<%= page_prop_token %>" value="<%= pageId %>" /> <table border=0><tr> <tr><td> name <td><html:text property="name"/> <tr><td colspan=2 align=center> <html:submit property="submit">submit</html:submit> </table> </html:form>
Array in an HTML form <html:form action="/Supplier_State_0_Action" > <html:hidden name="petForm" property="<%= page_prop_token %>" value="<%= pageId %>" /> <table border="0" cellspacing="1"> <tr><td> <table border="0" width="100%"><td>subName</table> <td> <table border="0" width="100%"><td>number</table> <td> <table border="0" width="100%"><td>check</table> <tr><td> <table border="0" cellspacing="1"></table> <!-- tableau transparent suivant <tr><td colspan=10 align=center> <html:submit property="submit">submit</html:submit> </table> </html:form>
Iteration on the array (or collection) <logic:iterate name="petForm" property="thingN" id="item1" indexId="index1"> <tr><td> <table border="0" width="100%"<%=color[index1.intValue()%2]%>> <td> <bean:write name="item1" property="subName"/> </table> <td> <td><bean:write name="item1" property="number"/> <table border="0" width="100%" <%=color[index1.intValue()%2]%>> <td><html:checkbox property='<%="thingN["+index1.intValue()+"].check"%>'/> </logic:iterate> cette valeur est retournée dans l’URL
Internationalization (a.k.a. i18n) Properties defined in resources/application.properties resources/application_fr.properties Introduced in the JSPs by <bean:message key=“struts.page.form.text"/> (see the file for details) If the browser is set to French application_fr.properties is used
Translation of the properties Copy resources/application.properties to resources/application_fr.properties and edit the content of the new file
Struts in WebLang Architecture pour: Machine à états finie Gestion des pages
Assurer une confirmation! L’utilisateur clique le bouton Confirm L’ordre est exécuté par le serveur L’utilisateur clique le bouton BACK du browser Il reclique Confirm erreur: double entrée Comment le serveur évite-t-il le doublon ?
Eviter le doublon Chaque page contient un hidden field avec un numéro unique Avant de lire les paramètres de la page, on vérifie que le numéro est celui de la dernière page envoyée Cela implique un code homogène
State Machine Login Register Fill a cart Confirm the cart Show the bill Confirm the order (only once)
WebLang use of the JSPs and servlets personName sportName location state == 1 transition from state 1 state = 2 state == 2 transition from state 2 state = 1 JSP JSP State_1 State_2
WebLang use of the JSPs and servlets sportName location FSM bean FSM bean JSP JSP Where to start ? In the bean! Same bean, but different states personName
Finite State Machine in a Struts page_0 not confir- med showBasket page_1 1 confirmed 2 page_2 OK
WebLang Module : states and pages struts PersonManagement { package management; stateMachine state State_0 > person; state State_1 > job; . . . FSM . . . page person { personForm; personForm.sportForm[ ]; personForm ("Comment", submitName) ; }
WebLang Module : Finite State Machine state State_0 > supply; state State_1 > supplyConfirmation; switch (sessionState) { case State_S: sessionState = State_0; break; case State_0: Pet pet = petHome.create( petForm.getName() ); sessionState = State_1; case State_1: if (supplyConfirmation.getConfirmation()) } // Pure Java code
WebLang Module : Forms (Java beans) form SportForm { package fmPack; String sportName; int location); } form PersonForm { // sub-form String name ; JobForm jobForm; SportForm sportFormN [ ] ; form JobForm { String jobName; int location;
Different display formats page SomePage { petForm; // displays all the fields petForm.thingN[ ]; petForm.bbb (MySubmit); // displays a MySubmit button petForm.ccc (Cancel); // display a button petForm.aaa (); // displays no button }
Struts JSP struts Supplier { . . . page supply { petForm; petForm.thingN[ ]; } form PetForm { package fp; String name; Thing thingN[]; form Thing { String subName, int number, boolean check;
Selection of the visible fields page SomePage { petForm () { readwrite nom; hidden age; } petForm.thingN[ ]; petForm.bbb (MySubmit); }
Selection of the visible fields page SomePage { petForm () ; petForm2<PetForm> () petForm.thingN[ ]; petForm3<PetForm>.bbb (MySubmit); }
Characteristics of the fields hidden message readonly readwrite radio (aaa,bbb) combo (aaa,bbb) password readonly radio (aaa,bbb) | readwrite | combo (aaa,bbb) | password // last lines: one of each group, e.g. readwrite radio
Struts in WebLang Action Forms CMP bean JSPs Action Servlet Struts browseForm.petForm[ ] (form) Struts Action Forms browser (JSP) not confir- med basket.petFrom[ ] (form) showBasket 1 showBasket (JSP) confirmed order- registered (JSP) 2 PetOrder status = ordered OrderItems* (CMP+CMR) CMP bean OK JSPs Action Servlet
Three tiers (overview) browseForm.petForm[ ] (form) Buying Struts browser (JSP) Administrator Struts PetOrder status = toBeChecked OrderItems* (CMP+CMR) areYouThe- Administrator (JSP) not confir- med basket.petFrom[ ] (form) showBasket login showBasket (JSP) 1 checkOrders (JSP) confirmed OrderForm.petForm[ ] not accept (form) select 1 order- registered (JSP) 2 confirmed OK PetOrder status = ordered OrderItems* (CMP+CMR) SendSupplierPO MDBean Queue Three tiers (overview) file PetOrder status = awaitInvoice OrderItems* (CMP+CMR) Display Business Layer Database + Dataflow Business Layer Display
Prints in WebLang out print println Struts print JSP 1 In the Struts, WebLang automatically defines a stream named out, which contains methods out.print(“xxx”); and out.println(“yyy”); the text produced is automatically printed on the next JSP
Sub-FSMs display enter application display ignore start timeout enter next previous start timeout enter display 2 ignore display_francs 1 display_euros
Sub-FSM Struts A Struts B State_0 State 0 State_1 State_3 State_S (start) State 0 State_R (redirect) 1st return 1st call subsequent calls State_1 Goto B Continue State_3 Return 2nd return
Page_1 Page_0 Groupe Personnes Introduire personnes/ groupes EntrerGroupe EntrerGroupe EntrerGroupe Lister/former groupes Page_2 EntrerPersonne EntrerPersonne EntrerPersonne Nom groupe Personnes Quitter Quitter nomP NomG v Entrer Quitter
JMS: Java Message Services Channels (queues, topics, durable topics) Message driven beans Architecture
Message Driven Bean queue, topic Server Clients Sender queue/topic MDBean Listener queue topic SynReceiver
Types de canaux Each message is rec-eived by a single client Queues Topics Each client receives all messages Durable Topics Each client receives all messages, even if it is temporarily discon-nected Requires (only in input) subscription name username, passwd
Création de queues et topics Queolques queues et topics sont créés quand le serveur JBoss est démarré: A, B, C, D, testTopic (lire les informations imprimées quand JBoss démarre) La queue ou le topic d’un MDBean est créé à la création du MDBean. On peut créer d’autres queues et topics en modifiant les fichiers qui définissent l’environment de JBoss selon http://ltiwww.epfl.ch/WebLang/JBossQueues.html
Canaux disponibles dans WebLang: MDBeans (1 input / 0-n outputs) Servlets, (0-n outputs) JSPs, Struts CMP beans (0-n outputs) jclient, class (0-n inputs / 0-n outputs)
Listener de queue / topic Client inputchannel ch { } Serveur Object operation1() operation2() queue topic Listener Needs C:\jboss-4.0.0\client\jbossall-client.jar
Envoyer des messante à une queue ou un topic Client outputchannel ch { } Server Object ch.send(message) queue topic proxy
Module client ou classe en WebLang jclient MyClient { // or class package myPackage; inputchannel inputName (topic, "MDBTopic") { String s = ((TextMessage)msg).getText()); varName.publish(msg); } outputchannel varName (topic, "testTopic"); public void method(String s) { . . . }
Listener généré par WebLang public class alarmChListener implements javax.jms.MessageListener { public void onMessage(javax.jms.Message msg) { try { System.out.print ((javax.jms.TextMessage)msg).getText(); } catch (Exception t) { t.printStackTrace(); } } } Text specifié dans l’inputchannel
Lecture synchrone // Lire la queue en mode synchrone // (attente de 5 secondes au plus) tmpQueue = (javax.jms.Queue) queueCtx.lookup("queue/C"); queueObj = queueSession.createReceiver(tmpQueue); for (;;) { Message msg = (Message) queueObj.receive(5000); if (msg == null) System.out.println("Timed out"); else System.out.println(msg.getText()); }
Message driven bean
Module MDBean en WebLang Pas de nom (à la diférence des autres) mdbean MyMDB { package myPackage; inputchannel (queue, "MDBQueue") { String s = ((TextMessage) msg).getText()); varName.send(msg); } outputchannel varName (queue, "B"); // executed when a message arrives
Module servlet en WebLang servlet MyClient { package myPackage; // pas d’inputchannel possible ! outputchannel varName (queue, "A"); public void method(String s) { TextMessage tm = queueSession.createTextMessage(s); varName.send(tm); }
Proxy d’un topic (généré by WebLang, similaire pour les queues) public void newTopicEnv(String name, String passwd) throws Exception { Object tmp = initCtx.lookup("UIL2ConnectionFactory"); TopicConnectionFactory tcf = (TopicConnectionFactory) tmp; topicConn = tcf.createTopicConnection(name, passwd); topicSession = topicConn.createTopicSession( false, javax.jms.TopicSession.AUTO_ACKNOWLEDGE ); topicConn.start(); }
Connexion à un topic (généré by WebLang) tmpTopic = (javax.jms.Topic) initCtx.lookup("topic/testTopic"); fromTopic = topicSession.createSubscriber(tmpTopic); fromTopic.setMessageListener(new fromTopicListener());
Exemples d’architecture
Exemple d’environnement pour un jeu dans lequel un dé tourne parmis les joueurs (une fois qu’ils se sont enregistrés) Server Browser Initialise le jeu game Servlet CMP beans (nom de partie) Java client Java client topic Java client
Java client topic GUI setUsername () getUsername () setPosition () setError () Java client Message Listener onMessage () { } topic GUI Listeners actionPerformed() { } invokeLater Business layer FSM () { }
Classes in WebLang class Business { package ppp; outputchannel ch (topic, “testTopic”); access Remote; public Business(LoterieGUI gui) { this(); this.gui = gui; }
La machine d’état est exécutée sur le thread du GUI et le sur le thread qui gère le topic java.awt.EventQueue.invokeLater( new Runnable() { public void run() { // access to the GUI } } );
Machine à états finie public void transition(String source) { try { switch (state) { case 0: if (source != "username") return; game = gameHome().findByName(gui.getGameName()); . . . state = 1; break; case 1: if (source != "nextmove") return; state = 2; case 2: if (source != "done") return; game.moveTerminated(); } } catch (Exception e) { }
Web Services SOAP Simple Object Access Protocol ou Service Oriented Architecture Protocol HTTP remote call SOA Service oriented architecture WSDL Web Services Description Language UDDI Universal Description Discovery and Integration ( tombe dans l’oubli )
Schéma d’un web service Application (standalone) stub Serveur remote object == Java bean Application (sur serveur) stub
Documentation sur la création des Web Services Help > Help Contents > Documentation
Bottom Up: Java bean service . . . <wsdl:types> <schema elementFormDefault="qualified" <element name="grow"> <complexType> <sequence> <element name="p" type="impl:Person"/> </sequence> </complexType> </element> WSDL package web; public class Test { public Person grow(Person p){ p.setSize(p.getSize()+1); return p; }
Web Services Description Language (WSDL) <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://web" /" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" <!--WSDL created by Apache Axis version: 1.3 Built on Oct 05, 2005 (05:23:37 EDT)--> <wsdl:types> <schema elementFormDefault="qualified" <element name="grow"> <complexType> <sequence> <element name="p" type="impl:Person"/> </sequence> </complexType> </element> . . . <wsdl:port binding="impl:TestSoapBinding" name="Test"> <wsdlsoap:address location="http:// </wsdl:port> </wsdl:service> </wsdl:definitions>
Creation d’un Web Service L’accès à une application est fait au moyen de servlettes développées dans le projet Axis et qui appellent l’objet désigné par l’utilisateur
Test du service (après avoir compilé la classe) Service Explorer WebContent/wsdl/Xxx.wsdl > right click > Web Services > Test with Web Services Explorer JSP de test classe.java > right click > Web Services > Generate Sample JSPs
Top Down: Java bean service WSDL file (par exemple sur une page WEB qui décrit le service) On obtient un squelette à compléter
Web service en WebLang (seuls les types simples supportés) webservice Simple { package xxx; public int add (int i, int j) { return i+j; }
From an action form to a CMP bean and vice-versa Transfer of data From an action form to a CMP bean and vice-versa
Action Forms CMP Beans Main resultFormN Action forms Course personN PersonForm finder or getCollection Person Recreates a collection and copies one into the other member by member CMP beans // code next page
Action Forms CMP Beans String courseName = result.getCourseForm().getName(); // reads an action form java.util.Collection<Person> coll = personHome.findPersonInCourse(courseName); java.util.Collection<PersonForm> c = new ArrayList<PersonForm> (); for (Person aPerson: coll) { // scan the collection of CMP beans PersonForm personF = new PersonForm(); personF.setFirstName(aPerson.getFirstName()); personF.setLastName(aPerson.getLastName()); c.add(personF); // creates the collection of action forms } result.setPersonFormN( c );
Checking which submit has been clicked If (submit.equals(“OK”)) { . . . } page supply { petForm.thingN [ ] (OK, Cancel) readwrite name; } }
Exercise Lottery application implemented with Struts Draw first a diagram with the html forms, the action forms, the state machine and the database WebLang modules CMP bean: Customer name Generated automatically struts: Lottery - register(String) - login() - displayResults() html: lottery Start struts CMP bean: Token number
EJB - Hibernate 3 Hibernate 3 allows the beans to be either attached to or detached from the database The beans can thus be used as action forms too, which avoids the tedious transfers from the beans to the action forms The version we will use is based on the @annotations introduced in Java 1.5 See the page WebLang about Hibernate Quelques commentaires ont été ajoutés sous les transparents dans les pages suivantes
Annotations (replace xDoclets) /** * @struts.form name="jeton" */ @Entity public class Jeton implements java.io.Serializable { . . . @Id(generate = GeneratorType.AUTO) public long getId() { return id; } @ManyToOne public loterie.Client getClient() { return (client); Note: En WebLang, tous les ejb3 doivent se trouver dans le même package ------------------------------------------------------------------------- Ces annotations sont générées automatiquement par WebLang
WebLang module (same as cmpbean, but no finders, no creators: they are made in the user’s space) ejb3 MyCountry { package myPackage; relations (Town=1:N); String name; int number; public Country(String name) throws Exception { this.name = name; } public String toString() { String str = "Country id=" + getId() + " name=" + getName(); java.util.Collection<Town> tlist = getTownN(); for (Town town: tlist) { str = str + "\n Town=" + town; return (str);
Configuration parameters config { deploypath = "C:/jboss-4.0.0/server/standard/deploy/"; hibernate_driver = "org.hsqldb.jdbcDriver"; hibernate_url = "jdbc:hsqldb:hsql://localhost:1701"; // for the JBoss database as prepared here hibernate_username = "sa"; hibernate_password = ""; hibernate_dialect = "org.hibernate.dialect.HSQLDialect"; hibernate_dbauto = "create-drop"; // if present, // recreates the tables at each restart } ---------------------------------------------------------------------------- Les paramètres de configurations sont indiqués ci-dessus pour la configuration standard utilisée dans les salles d’ordinateurs
Use of a Hibernate bean javax.persistence.EntityManager em; javax.persistence.EntityTransaction tx; em = hibernate_utility.Manager.open(); tx = em.getTransaction(); tx.begin(); Country c = new Country("Switzerland"); em.persist(c); c.setNumber(1291); // DB updated at commit tx.commit(); // tx.commit() or tx.rollback(); hibernate_utility.Manager.close(); ---------------------------------------------------------------- Les instructions de stockage dans la base de données doivent être placées dans des transactions, ouvertes par les 5 premières lignes de ce transparent et fermées par les deux dernières. L’instruction em.persist(c) attache l’objet c à la transactions, qui mémorise toutes les modifications et les exécute au plus tard au commit Toutes les modifications peuvent être annulées par l’instruction rollback
Finding objects with Hibernate javax.persistence.Query qt; qt = em.createQuery( "select t from Town t where t.name=?"); qt.setParameter(1, name); try { town = (Town)qt.getSingleResult(); } catch (javax.persistence.EntityNotFoundException enf) { town = new Town(name); em.persist(town); } ---------------------------------------------------------------- La recherche d’objets de la base de données est faite au moyen des instructions ci-dessus. Si elle est effectuée dans une transaction (pas montrée ici), l’objet est automatiquement attaché et les modifications qu’il subira seront mémorisées et effectuées au commit. Sinon, l’objet est retourné en tant que simple objet. Dans l’exemple ci-dessus, on vérifie si l’objet existe. Si ce n’est pas le cas, on le crée ce qui demande une transaction.
Finding lists of objects with Hibernate javax.persistence.Query qt; qt = em.createQuery("select t from Town t"); try { townN = (Collection)qt.getResultList(); } catch (Exception e) { // some error } ---------------------------------------------------------------- Pour rechercher une collection, on utilise la méthode indiquée ci-dessus.
Using Hibernate objects (size() not written - lazy evaluation) tx.begin(); . . . proprietaire = qt.getSingleResult(); Collection c = proprietaire.getVoitureN(); // The elements of the . . . // collection are retrieved only when needed tx.commit(); for (Voiture v: proprietaire.getVoitureN()) { out.println(v.getName()); // accessed outside the transaction } 09:22:28,774 INFO [STDOUT] org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: package.Proprietaire.voitureN, no session or session was closed ---------------------------------------------------------------- Lorsque l’on recherche un objet qui possède une collection d’autres objets dans une relation, les objets de la relations ne sont recherchés dans la vbase de données que lorsque le programme les appelle (lazy évaluation) pour optimiser les transferts. Donc la transaction doit encore être ouverte à cet instant. Lorsque les objets de la collections sont affichés dans un tableau dans une JSP, la transaction a déjà été fermée, ce qui provoque l’erreur indiquée ci-dessus. À suivre
Using the objects of a Hibernate relationship outside the transaction Owner Car 1 N tx.begin(); . . . owner = qt.getSingleResult(); owner.getCarN().size(); tx.commit(); required to force the computation (other functions may also be used) for (Car c: owner.getCarN()) { otherwise not available out.println(v.getName()); } ---------------------------------------------------------------- Pour assurer que le programme recherche les éléments de la collection, il suffit d’appeler une fonction qui les utilise, par exemple size() comme cela est fait ci-dessus.
Both Action form and Hibernate bean ejb3 MyCountry extends strutsStateMachine.StateForm { package myPackage; relations (Town=1:N); String name; int number; } ---------------------------------------------------------------- Un bean Hibernate peut être également un e ActionForm (les deux sont des Java beans). Pour cela, il suffit d’hériter de StateForm comme ci-dessus. Dans ce cas, il ne faut pas définir la form, elle est automatiquement déclarée par le compilateur WebLang. Les relations d’un ejb3 correspondent aux sous-formes des ActionForm. Cela est valable aussi bien pour les tableaux (1:N, N:M) que pour les objets simples (1:1)
Create and Persist an Action Form // town is assumed to be a form filled in by the user town.setId(0); // be sure it has not been left // attached by some previous action javax.persistence.EntityManager em; javax.persistence.EntityTransaction tx; em = hibernate_utility.Manager.open(); tx = em.getTransaction(); tx.begin(); em.persist(town); tx.commit(); hibernate_utility.Manager.close(); } ---------------------------------------------------------------- Avant de rendre un objet persistant, il faut être sûr qu’il n’est plus attaché. Cela est fait en mettant son ID à zéro. Il faut éviter qu’il soit dans une transition à ce moment-là, évidemment.
Transactions and display No transaction Transaction Transaction get from the DB display, let the user modify the data store into the DB Must reconnect the bean to a transaction ---------------------------------------------------------------- La situation représentée ci-dessus est fondamentale dans les applications Web. Les deux transactions en vert sont effectuées sur deux appels d’un utilisateur, par exemple dans deux transitions d’un automate construit dans un Struts. Dans la première, on lit des données de la base de données, puis après avoir fermé la transaction, on passe l’objet ou les objets (par exemple le Java bean en jaune) à la couche de présentation (JSP, GUI…) pour que l’utilisateur puisse le modifier. Losque le système doit entrer les modifications dans la base de données, il faut réintroduire l’objet dans un nouvelle transaction (si on gardait la première, le système se bloquerait rapidement). Pour cela, il faut utiliser les instructions présentées sur le prochain transparent. Java bean (ActionForm/EJB)
Reconnect an EJB3 to the DB tx.begin(); // a first call to a servlet em.persist(x); tx.commit(); …Displaying… tx.begin(); // a subsequent call y = em.merge(x); // copy x to a new y y.setName(“new value”); // and persists y tx.commit(); ---------------------------------------------------------------- Le merge détermine s’il y a déjà un objet avec le même ID dans la transaction. Si c’est le cas, il copie les données du nouvel objet dans l’objet attaché et il retourne l’objet de la transaction. Si ce n’est paas le cas, il crée un nouvel objet dans la transaction, copie les données du nouvel objet dans l’objet nouvellement créé et retourne ce dernier (ce qui n’est pas très rusé, mais il semble que ce soit bien le cas).
Handling a relationship Owner Car tx.begin(); em.persist(owner); for (Car c: cars) { em.persist(c) owner.add(c); c.setCar(owner); // indispensable to introduce it into the DB } // because the reference is defined in table car tx.commit(); 1 N ---------------------------------------------------------------- Les connections des relations ne sont pas effectuées automatiquement dans les deux sens, il faut le faire explicitement. La base de données n’est correctement mise à jour que si l’objet qui correspond à la table de la base de données est connecté à la relation: setXxxx(yy) pour une relation xxxx -> yy (1:1) setXxxx(yy) pour une relation yy -> xxxx (1:1 target ou 1:N)
Merging a relationship (could be done by using cascade) Owner Car 1 N tx.begin(); x = em.merge(owner); for (Car c: owner.getCarN()) { x.add(em.merge(c)); // reintroduce the merged } // objects into the new object owner = x; // optional: remettre l’objet dans son pointeur request.getSession().setAttribute(“owner”, owner); // et tx.commit(); // dans la servlet-session x : Owner c : Car 1 N ---------------------------------------------------------------- Quand un objet est “mergé”, les collections de ses relations ne sont pas automatiquement “mergées”. Pour cela il faudrait utiliser l’annotation cascade qui n’est pas encore disponible en WebLang. Pour une relation simple (1:1), il suffit de “merger” l’objet référencé. Pour une relation N:M ou 1:N, il faut “merger” chaque objet et pour cela les copier dans la collection du nouvel objet comme indiqué ci-dessus. Note: La première version de ce transparent utilisait un moyen un peu plus compliqué (et avec une erreur!)
SQL beans SQL beans have been devised at the EPFL: they present the same structure as Hibernate 3 (particularly within WebLang), but they only use JDBC and the standard SQL Much simpler to debug, as all statements may be traced within the debugger No home, the object must be created to hold the finder (instantiation by new)
SQL Bean Example sqlbean Town extends strutsStateMachine.StateForm { package appliT; relations ( Country = N:1, <isCapitalOf 1:1 hasCapital> Country); String name; public long findPK_OfTown() throws Exception { query = "SELECT * FROM Town WHERE name=$name;" } } TownN { public void findN_TownList(String s) throws Exception { query = "SELECT * FROM Town WHERE name>$s" }
Use of an SQL bean // we assume that country has been created // and filled by the Struts mechanism case State_1: long pkC = country.findPK_OfCountry(); if (pkC!=0) { country.reloadAll(pkC); } else { country.store(); } country.addTownN(town); // town.setCountry(country); // either this line or the line // above; the second one is // called automatically
Finders TownN tn = new TownN(); try { tn.findTownList(“N”); } catch (weblangUtils.SQLException we) { System.out.println(“Not found”); } for (Town t: tn) { System.out.println(“t.getName()); } …………………………………………………………….. TownN { String name; public void findTownList (String s) throws Exception { query = "SELECT * FROM Town WHERE name>$s" } } Finders
FSM of the SQL beans o = new Xxx() Detached object o.set(o1) o.add(o1) o.store() o.set(null) o.remove(o1) pk=o.findPKXx() o.findXx() o.reload(pk) o.store() o.delete() Attached object pk!=0 o.delete() Linked object pk==0 o.reload(0) o.delete() o.set(null) o.remove(o1) o.set(o1) o.add(o1) o.reloadAll() o.storeAll() Attached + linked + connected object pk!=0 rel!=0 o.deleteAll() o.reload() o.reloadAll() o.update() o.updateAll()
States of the SQL objects Detached: The object has been instantiated Attached: The object has a corresponding set of data in the database Linked: The object is embedded in a structure, but it has no primary key Attached, linked The object is available in the database, and connected: as well as in memory, within some relationship
Operations of the SQL beans store Copies the data of the object into the database, new primary key inserted in the object findXxx Query method returning a DB row, the object must be instantiated before the method is called findPKXxx Returns the value of the primary key (or 0), method may also throw an exception reload(pk) Method copies the data of the object into a DB row with primary key pk update Dual of the reload, updates the database row that has the PK found in memory
More Operations delete Removes the data in the database, not the memory, resets the object’s primary key set, add Establishes connections between remove the objects, the two directions of the relationship are handled storeAll Call all the objects bound by deleteAll a relationship (not recursively) reloadAll updateAll
RMI Application interface interface Xxxx Xxxx Client Server Xxxx Xxxx RemoteXxxx Xxxx (stub) Xxxx (skeleton)
RMI: inverse communication (by transmitting the stub) Server rmiregistry Transfer (skeleton) Client 1 Transfer (stub) 2 myRemStub MyRemote (skeleton) MyRemote (stub) 3
RMI Module rmi Test { package rmis; public void print (String s) { System.out.println("X "+s); } } jclient Client { package rmis; Test x; // as Test corresponds to an rmi interface, // x is automatically initialized RemoteTest y; // y is not automatically initialized, the client // must call new RemoteConnection(true) public void print (String s) { try { x.print(s); } catch (Exception e) { e.printStackTrace(); } } }
Software Engineering
Application / implementation Craig: (http://www.codegeneration.net/tiki-read_article.php?articleId=27) Specifying software means components, interfaces, archit-ectures, or what is sometimes referred to as the "How". Specifying applications means features, capabilities, options, or what is sometimes referred to as the "What". So, it seems odd to me (i.e., Craig ) to use UML (a "how" language) as a universal specification language.
My View Actually, you want to describe the software, the how. The customer can often not read any schema and will require a fast prototype, which is indeed the software. Library (Librarian, book shelves, quiet room) Soft Library (simulator) (terminals, server, software) Each time a book is borrowed in the real library, the librarian borrows a book here = Borrow a book Look for a user A book has been lost Check differences Sort books Reserve a book Software application (terminals, server, software)
Three tiers (overview) browseForm.petForm[ ] (form) Buying Struts browser (JSP) Administrator Struts PetOrder status = toBeChecked OrderItems* (CMP+CMR) areYouThe- Administrator (JSP) not confir- med basket.petFrom[ ] (form) showBasket login showBasket (JSP) 1 checkOrders (JSP) confirmed OrderForm.petForm[ ] not accept (form) select 1 order- registered (JSP) 2 confirmed OK PetOrder status = ordered OrderItems* (CMP+CMR) SendSupplierPO MDBean Queue Three tiers (overview) file PetOrder status = awaitInvoice OrderItems* (CMP+CMR) Display Business Layer Database + Dataflow Business Layer Display
Exercise of Software Engineering (8) Creation of a stock exchange application. Customers are connected to the bank. The bank keeps a portfolio for each client, transmits the customer orders to the stock exchange. The stock exchange keeps an “order book” that contains the stocks that customers want to buy or sell, with the prices (or price range) they are willing to pay or get. Create a diagram that specifies a customer, a bank and a stock exchange, with CMP beans, queues, session beans… Create a diagram of the software system that will run the application, not of the application itself.
Exercice: Compléter la loterie pour que le client voie une annonce quand le manager a sélectionné les jetons Créer les fonctions qui permettent d’entrer des jetons depuis le client Java (rich client)
Loterie Client Serveur html généré Java bean: LotteryData - constantes générales - client html: display_Manager - tireJetons(int) servlet: Manager - tireJetons(int) - afficheJetons() cmpbean: Client String nom 1 N html: display_GestionJeton - remplitJeton(int) - afficheResultats() servlet: GestionJeton - remplitJeton(int) - afficheResultats() sbean: AccesJetons - addJeton(Client, Jeton) - listeResultats(Client) cmpbean: Jeton int numero attente int etat gagnant perdant html: display_Enregistrement - enregistre(String) - login(String) servlet: Enregistrement - enregistre(String) - login(String) html généré
Loterie Browser Serveur Client Java bean: LotteryData - constantes générales - client html: display_Manager - tireJetons(int) servlet: Manager - tireJetons(int) - afficheJetons() Client topic: testTopic cmpbean: Client String nom listener: class: LoterieGUI (created with Visual Editor) 1 N cmpbean: Jeton int numero attente int etat gagnant perdant
Loterie Browser Serveur Client Java bean: LotteryData - constantes générales - client html: display_Manager - tireJetons(int) servlet: Manager - tireJetons(int) - afficheJetons() Client topic: testTopic cmpbean: Client String nom class: LoterieGUI - display: TextArea - login: TextField - tireJeton: TextField display(String) listener: 1 N cmpbean: Jeton int numero attente int etat gagnant perdant sbean: ClientBean - login(String) - tireJeton(int) invokeLater class: Business - login(String) - tireJeton(int)