Home > Apache Geronimo v1.1 > Documentation > Apache Geronimo v1.1 - GuÃa de Usuario > Aplicaciones ejemplo > Ejemplo muy simple de Session EJB |
Este es un ejemplo de una página-JSP que llama a un Session Bean. El resultado es similar a:
Antes que todo, se que no puedo deletrear. Espero que puedas entenderlo.
En este ejemplo, no he usado algo que facilite al desarrollo EJB, como Eclipse, Ant ó Xdoclet. He intentado desmenuzarlo para hacer este ejemplo tan sencillo como sea posible para su entendimiento. (En el otro extremo, algunas cosas en todo descriptor de activación, deployment descriptor, no entiendo incluso yo, por lo cual podrÃa ser posible desmenuzarlo incluso más.) Este es un ejemplo que usa geronimo 1.1, java 1.4 y EJB 2.1.
Bien, lo que quiero es un EJB que me pueda decir el tiempo, lo siguiente es el código para el bean:
package mytimepak; public class MyTimeBean implements javax.ejb.SessionBean { public void ejbCreate() {} public void ejbActivate() {} public void ejbPassivate() {} public void setSessionContext(javax.ejb.SessionContext ctx) {} public void unsetSessionContext() {} public void ejbRemove() {} public String getTime() { String s = new java.util.Date().toString(); return s; } }
He puesto mi EJB en un paquete al cual llamo mytimepak. Los primeros 6 métodos son implementaciones de la interfaz javax.ejb.SessionBean. No se realmente que tan buenos sean, pero el método ejbCreate es como un constructor, en este caso un constructor vacÃo. Para permitir a los clientes el llamar al EJB se deben proporcionar a las famosas interfaces home y remote. La primera, la interfaz home, se usa para localizar al EJB y la otra, la interfaz remote, se usa para invocar métodos en el EJB. La interfaz remote es como una interfaz normal empleada para RMI. Como este EJB sólo será usado desde una página-JSP que se ejecuta en el mismo servidor (la misma JVM) yo uso otro tipo de interfaces que no emplean la red. Son conocidas como LocalHome y Local interface, aunque son lo mismo.
A continuación se muestra el código para la interfaz local home (la cual corresponde a la interfaz home):
package mytimepak; public interface MyTimeLocalHome extends javax.ejb.EJBLocalHome { public MyTimeLocal create() throws javax.ejb.CreateException; }
Como puedes ver, la interfaz LocalHome es como un constructor que devuelve MyTimeLocal.
A continuación se muestra el código para la interfaz Local (la cual corresponde a la interfaz remota)
package mytimepak; public interface MyTimeLocal extends javax.ejb.EJBLocalObject { public java.lang.String getTime() ; }
Esta es sólo una interfaz plana para los métodos (prefiero no llamarlos métodos de negocio) del EJB, en este caso el método getTime().
Ese código no es dÃficil entenderlo, la parte complicada son los descriptores de activación (deployment descriptors). Necesitas 2 de ellos, ejb-jar.xml y openejb-jar.xml. Asà es como se observan:
ejb-jar.xml:
<?xml version="1.0" encoding="UTF-8"?> <ejb-jar id="ejb-jar_1" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd" version="2.1"> <description>Ejemplo de un session bean</description> <display-name>MyTimeBeanEJBName</display-name> <enterprise-beans> <session id="Session_MyTime"> <description>Un EJB llamado MyTimeBean</description> <display-name>MyTimeBeanName</display-name> <ejb-name>MyTimeBean</ejb-name> <local-home>mytimepak.MyTimeLocalHome</local-home> <local>mytimepak.MyTimeLocal</local> <ejb-class>mytimepak.MyTimeBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> </ejb-jar>
Primero tienes algo que no se que tan bueno sea, por ejemplo el tag display-name. Creo que puedes escribir lo que quieras ahÃ. Me parece completamente innecesario, pero no he probado que pasa si lo asumo asÃ. Lo que importa son los tags ejb-name, local-home, local, ejb-class, session-type. Creo que ejb-name es parte de lo que usan los clientes para localizar al bean (consulta al siguiente archivo-xml). Los tags local-home, local y ejb-class apuntan a las clases. El tipo Session indica que se trata de un statefull (con estados) ó stateless (sin estados) session bean. Creo que el tipo de transacción no tiene sentido, ya que no hay transacciones en un session bean, ¿o si las hay? He intentado leer más sobre estos descriptores de activación aquÃ: http://cwiki.apache.org/GMOxDOC11/deployment-plans.html Pero no he podido deducirlo. En el otro extremo, creo que los archivos ejb-jar.xml no serán necesarios en la siguiente generación EJB 3.0, por lo que uno no deberÃa gastar mucho tiempo en tratar de entenderlo.
A continuación el archivo openejb-jar.xml:
<?xml version="1.0" encoding="UTF-8"?> <openejb-jar xmlns="http://www.openejb.org/xml/ns/openejb-jar-2.1" xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.1" xmlns:pkgen="http://www.openejb.org/xml/ns/pkgen-2.0" xmlns:sec="http://geronimo.apache.org/xml/ns/security-1.1" xmlns:sys="http://geronimo.apache.org/xml/ns/deployment-1.1"> <sys:environment> <sys:moduleId> <sys:groupId>default</sys:groupId> <sys:artifactId>TimeBean_artifact_in_openejb</sys:artifactId> <sys:version>1.0</sys:version> <sys:type>car</sys:type> </sys:moduleId> </sys:environment> <enterprise-beans> <session> <ejb-name>MyTimeBean</ejb-name> <ejb-ref> <ref-name>ejb/MyTimeBean</ref-name> <ejb-link>MyTimeBean</ejb-link> </ejb-ref> </session> </enterprise-beans> </openejb-jar>
------------------------------- > FALTA TRADUCCION
Again, I don't understand much of the first part, but the ejb-ref part is important. ref-name=ejb/MyTimeBean is what clients use to lookup the EJB. ejb-link=MyTimeBean is the same as ejb-name=MyTimeBean in ejb-jar.xml. The ejb-link and the ejb-name must be the same.
(Why this information has bean split up in 2 files is a mystery to me. I guess that it has something to do with what is generic for the application (ejb-jar.xml) and other stuff that is spesific to the application server. If you were to deploy this application on another application server than geronimo you would only have to change the openejb-jar file. That sounds good. On the other hand, now you have the extra complexity of knowing what goes where and that sure aint easier than having to rewrite one sigle deployment descriptor if you would face the rare situation of deploying your code on another type of server. But this is ofcourse my personal oppinion based on limited understanding of EJB.)
Allright, now for the JSP client of this EJB.
This is my JSP-page, I comment the code directly in the code:
<%@ page contentType="text/html" import="mytimepak.*, javax.naming.* " %> <html<head><title>Time</title></head><body> <% String s="-"; // Just declare a string try { // This creates a context, it can be used to lookup EJBs. Using normal RMI you would // have to know port number and stuff. The InitialContext holds info like // server names, ports and stuff I guess. Context context = new InitialContext(); // MyTimeLocalHome is a rference to the EJB MyTimeLocalHome myTimeHomeLocal = (MyTimeLocalHome)context.lookup("java:comp/env/ejb/MyTimeBean"); // java:comp:env is like a reference to the local server. ejb is where you find the EJBs and // MyTimeBean is the name of the EJB that is written in the deployment descriptors. // This is like a constructor returning a MyTimeLocal, an interface for the EJB on which you // can call methods (but not access variables as with any interface) MyTimeLocal myTimeLocal = myTimeHomeLocal.create(); // So, just go ahead and call a method (in this case the only method). s = myTimeLocal.getTime(); } catch (Exception e) { s=e.toString(); } %> This is the time returned from the EJB: <%=s%>
Note that this JSP-page also have to include mytimepak.MyTimeLocalHome and mytimepak.MyTimeLocal. I have done that in the first line import="mytimepak.*. This two class files must be in the WEB-INF/classes directory, and not only that, in the WEB-INF/classes/mytimepak directory. I'll get back to that later.
If the JSP is simple, again the deployment descriptors are hard (or at least that is what I think). This is what they look like:
geronimo-web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.1" xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.1" xmlns:sec="http://geronimo.apache.org/xml/ns/security-1.1" xmlns:sys="http://geronimo.apache.org/xml/ns/deployment-1.1"> <sys:environment> <sys:moduleId> <sys:groupId>default</sys:groupId> <sys:artifactId>MyTimeWeb</sys:artifactId> <sys:version>1.0</sys:version> <sys:type>car</sys:type> </sys:moduleId> </sys:environment> <context-root>/mytime</context-root> </web-app>
Only inportant here (as far as I understand) is the context-root that becomes the URI.
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name> MyTImeWeb</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- To refer local EJB's --> <ejb-local-ref> <ejb-ref-name>ejb/MyTimeBean</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <local-home>mytimepak.MyTimeLocalHome</local-home> <local>mytimepak.MyTimeLocal</local> <ejb-link>MyTimeBean</ejb-link> </ejb-local-ref> </web-app>
welcome-file is what file the server will show if no file name is in the URI. ejb-local-ref is important. Here you must get the data right in all the tags (or so I think). Note how ejb/MyTimeBean corresponds to ref-name int openejb-jar. ejb-link seams to be unessesary, but we can't deply it without the local-home and local tags pointing out the classes for the interfaces.
There are 2 more deployment descriptors, the ones for the application as a whole. This is what they look like:
application.xml
<?xml version="1.0" encoding="UTF-8"?> <application id="Application_ID" version="1.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"> <display-name>MyTimeEJBApp</display-name> <module> <ejb>mytime-ejb.jar</ejb> </module> <module id="WebModule_1158667626422"> <web> <web-uri>mytime-web.war</web-uri> <context-root>/mytime</context-root> </web> </module> </application>
This file tell which two modules, the ejb and the web, that the ear file consists of.
geronimo-application.xml:
<?xml version="1.0" encoding="UTF-8"?> <application xmlns="http://geronimo.apache.org/xml/ns/j2ee/application-1.1" xmlns:sec="http://geronimo.apache.org/xml/ns/security-1.1" xmlns:sys="http://geronimo.apache.org/xml/ns/deployment-1.1" application-name="timebeanexmaple"> <sys:environment> <sys:moduleId> <sys:groupId>default</sys:groupId> <sys:artifactId>MyTime_ArtifactId</sys:artifactId> <sys:version>1.0</sys:version> <sys:type>car</sys:type> </sys:moduleId> </sys:environment> </application>
This file is pretty empty. The only thing of importance is the artifactId, it shows if you look a the lists of modules at http://localhost:8080/console/portal/apps/apps_ear like this: default/MyPhonebook_ArtifactId/1.0/car
(Anybody knows what "car" stands for?)
Allright, this is how I have organised my files :
app-home (in my case c:\java\j2ee\mytime) ¦ ¦ +---ejb ¦ +---META-INF ¦ ¦ ejb-jar.xml ¦ ¦ openejb-jar.xml ¦ ¦ ¦ +---mytimepak ¦ MyTimeBean.java ¦ MyTimeLocal.java ¦ MyTimeLocalHome.java ¦ +---META-INF ¦ application.xml ¦ geronimo-application.xml ¦ +---web ¦ index.jsp ¦ +---WEB-INF ¦ geronimo-web.xml ¦ web.xml ¦ +---classes +---mytimepak MyTimeLocal.class this file must be copyed here MyTimeLocalHome.class this file must be copyed here
First we must compile the EJB.
Then copy the interface classes to the WEB-INF\classes\mytimepak directory
Last task is to pack the EJB-jar file the WEB-war file and finaly the EAR-file.
To compile the EJB we must have geronimo-ejb_2.1_spec-1.0.1.jar in the classpath. I have installed geronimo in C:\geronimo\geronimo-1.1 and This is a bat-script that does this. Modern programmers use ant ofcourse, but for clarity, this is exactly what is needed to get the ear. So beginning in the app-home directory (in my case cd c:\java\j2ee\mytime)
set CLPATH=C:\geronimo\geronimo-1.1\repository\org\apache\geronimo\specs\geronimo-ejb_2.1_spec\1.0.1\geronimo-ejb_2.1_spec-1.0.1.jar cd ejb javac -classpath %CLPATH% mytimepak\*.java copy mytimepak\MyTimeLocal.class ..\web\WEB-INF\classes\mytimepak\ copy mytimepak\MyTimeLocalHome.class ..\web\WEB-INF\classes\mytimepak\ jar -cf ../mytime-ejb.jar mytimepak META-INF cd ..\web jar -cf ../mytime-web.war index.jsp WEB-INF cd .. jar -cf mytime-ear.ear mytime-ejb.jar mytime-web.war META-INF
As you can see here I start with declaring a variable CLPATH just not to get to long lines. Then cd to the ejb-directory and compile the EJB. Then copy the interface flasses to the web application. Then I use jar to first create an jar file for the EJB, then a war-file for the web, and finaly put this to jars (or mor corectly the jar and the war) in an ear file. Note how the META-INF/WEB-INF is directly in the jar-file root directory for all the jars.
Finaly the ear must be deployed. I use the geronimo deploy tool like this:
c:\geronimo\geronimo-1.1\bin\deploy.bat --user system --password manager deploy mytime-ear.ear
(If you change anything, remake the jar, war and ear, and change to redeploy mytime-ear.ear.
Also, you need to change the path to deploy.bat if you have not installed geronimo 1.1 in the
directory c:\geronimo\geronimo-1.1)
Now we can look at the application at http://localhost:8080/mytime
The whole source code can be downloaded in this zip-file: mytime.zip
Next: the CMP EJB phonebook example.
<------------------------------- FALTA TRADUCCION
--------------------------------------------------------------------------------
Autor: Mattias Malmgren [email protected]
2006-09-28
Traducción al español: Waldo RamÃrez Montaño