Esta lecci�n ampl�a el ejemplo de la lecci�n anterior para usar un bean de entidad. BonusServlet llama al bean de entidad para grabar informaci�n sobre el n�mero de la seguridad social y el bono y recuperarlo desde una tabla de la base de datos. Este funcionalidad de acceso a la base de datos a�ade la cuarta capa y la capa final al peque�o cliente empezado en la lecci�n anterior.
El SDK J2EE viene con una base de datos Cloudscape, y no necesitamos configuraci�n adicional en nuestro entorno para el bean de entidad. De echo en este jemplo, no escribimos ning�n c�digo SQL o JDBC� para crear las operaciones de acceso a la base de datos. La tabla y el c�digo SQL se generan con la herramienta de Despliegue durante en el ensamble y el despliegue. La lecci�n sobre Tecnolog�a JDBC y Persistencia Manejada por el Bean nos ense�ar� como escribir c�digo SQL para un bean de entidad.
�Crear el Bean de Entidad
Un bean de entidad representa datos persistentes almacenados en una fila de una tabla de una base de datos. Cuando se crea un bean de entidad, los datos se escriben en la fila apropiada de la tabla, y si se actualizan los datos de un bean de entidad, los datos de la fila apropiada de la tabla tambi�n se actualizan. La creaci�n de la tabla de la base de datos y la actualizaci�n de las filas ocurre sin escribir nada de c�digo SQL o JDBC.
Los datos de un bean de entidad son persistentes porque sobreviven a los crashs.
- Si ocurre un crash mientras se est�n actualizando los datos de un bean de entidad, estos datos son restaurados autm�ticamente al estado de la �ltima transaci�n enviada a la base de datos.
- si ocurre un crash en medio de una transaci�n a la base de datos, la transaci�n se "deshace" para evitar que un env�o parcial corrompa los datos.
�BonusHome
La principal diferencia entre el bean de sesi�n CalcHome de la lecci�n anterior y el bean de entidad BonusHome de esta lecci�n es el m�todo findByPrimaryKey. Este m�todo de b�squeda toma la clave primaria como un par�metro. En este ejemplo, la clave primara es el n�mero de la seguridad social, que se usa para recuperar la fila con el valor de la clave primaria que corresponde con el n�mero de la seguridad social pasado a este m�todo.
El m�todo create toma el valor del bono y de la clave primaria como par�metros. Cuando BonusServlet ejemplariza el interface home y llama a su m�todo create, el contenedor crea un ejemplar de BonusBean y llama a su m�todo ejbCreate. Los m�todos BonusHome.create y BonusBean.ejbCreate deben tener la misma firma , para que los valores del bono y la clave primaria puedan ser pasados desde el interface home al bean de entidad mediante el contenedor del bean de entidad. Si una fila para una clave primada dada (n�mero de seguridad social) ya existe, se lanza una java.rmi.RemoteException que es manejada por el c�digo cliente BonusServlet.
package Beans; import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.FinderException; import javax.ejb.EJBHome; public interface BonusHome extends EJBHome { public Bonus create(double bonus, String socsec) throws CreateException, RemoteException; public Bonus findByPrimaryKey(String socsec) throws FinderException, RemoteException; }
�Bonus
Despu�s de crear el interface home, el contenedor crea el interface remoto y el bean de entidad. El interface Bonus declara los m�todos getBonus y getSocSec para que el servlet pueda recuperar los datos desde el bean de entidad
package Beans; import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Bonus extends EJBObject { public double getBonus() throws RemoteException; public String getSocSec() throws RemoteException; }
�BonusBean
BonusBean es un bean de entidad controlado por contenedor. Esto significa que el contenedor maneja la persistencia de los datos y el control de las transaciones sin tener que escribir c�digo para transferir datos entre el bean de entidad y la base de datos o definir paquetes de transaciones.
Si por alguna raz�n queremos que el bean de entidad maneje su propia persistencia o las transaciones, podr�amos proporcionar implementaciones para algunos de los m�todos vac�os mostrados en el c�digo de BonusBean de abajo.
Cuando BonusServlet llama a BonusHome.create, el contenedor llama al m�todo BonusBean.setEntityContext. El ejemplar de EntityContext pasado al m�todo setEntityContext tiene m�todos que permiten al bean devolver una referencia a s� mismo o para obtener su clave primaria.
Luego, el contenedor, llama al m�todo ejbCreate. Este m�todo asigna datos a las variables de ejemplar del bean, y luego el contenedor escribe los datos en la base de datos. Se llama al m�todo ejbPostCreate despu�s de ejbCreate y realiza cualquier proceso necesario despu�s de que se cree el bean. Este sencillo ejemplo no hace procesamiento post-creacci�n.
Los otros m�todos vac�os son m�todos de retrollamada usados por el contenedor para notificar al bean alg�n evento que va a ocurrir. Podr�amos proporcionar comportamiento para algunos de estos m�todos si est�mos usando persistencia controlada por el bean, y otros si necesitamos proporcionar limpieza espec�fica del bean u operaciones de limpieza. Estas operaciones de limpieza e inicializaci�n tienen lugar en momentos espec�ficos durante el ciclo de vida del bean, y el contenedor se lo notifica al bean y llama al m�todo aplicable en el momento apropiado. Aqu� tenemos una breve descripci�n de los m�todos vac�os:
- Los m�todos ejbPassivate y ejbActivate los llama el contenedor antes de que el contenedor mueva el bean de su almacenamiento. Este proceso es similar al concepto de intercambio de una p�gina de memoria virtual entre la memoria y el disco.
- El contenedor llama al m�todo ejbRemove si el interface home tiene el correspondiente m�todo remove que es llamado por el cliente.
- Los m�todos ejbLoad y ejbStore los llama el contenedor antes de que se sincronize el estado del bean con la base de datos subyacente.
Los m�todos getBonus y getSocSec son llamados por los clientes para recuperar datos almacenados en variables de ejemplar. Este ejemplo no tiene m�todos del tipo set< type >, pero si los tuviera, el cliente podr�a llamarlos para modificar los datos de las variables de ejemplar del bean. Cualquier cambio hecho en una variable de ejemplar resulta en una actualizaci�n de la fila de la tabla de la base de datos subyacente.
package Beans; import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EntityBean; import javax.ejb.EntityContext; public class BonusBean implements EntityBean { public double bonus; public String socsec; private EntityContext ctx; public double getBonus() { return this.bonus; } public String getSocSec() { return this.socsec; } public String ejbCreate(double bonus, String socsec) throws CreateException{ //Called by container after setEntityContext this.socsec=socsec; this.bonus=bonus; return null; } public void ejbPostCreate(double bonus, String socsec) { //Called by container after ejbCreate } //These next methods are callback methods that //are called by the container to notify the //Bean some event is about to occur public void ejbActivate() { //Called by container before Bean //swapped into memory } public void ejbPassivate() { //Called by container before //Bean swapped into storage } public void ejbRemove() throws RemoteException { //Called by container before //data removed from database } public void ejbLoad() { //Called by container to //refresh entity Bean's state } public void ejbStore() { //Called by container to save //Bean's state to database } public void setEntityContext(EntityContext ctx){ //Called by container to set Bean context } public void unsetEntityContext(){ //Called by container to unset Bean context } }
�Cambiar el Servlet
El c�digo de esta lecci�n es muy similar al de la p�gina anterior con cambios en los m�todos init y doGet. El m�todo init de esta lecci�n busca el bean de sesi�n CalcBean, y el bean de entidad BonusBean.
public class BonusServlet extends HttpServlet { CalcHome homecalc; BonusHome homebonus; Bonus theBonus, record; public void init(ServletConfig config) throws ServletException{ try { InitialContext ctx = new InitialContext(); Object objref = ctx.lookup("bonus"); Object objref2 = ctx.lookup("calcs"); homebonus=( BonusHome)PortableRemoteObject.narrow( objref, BonusHome.class); homecalc=(CalcHome) PortableRemoteObject.narrow( objref2, CalcHome.class); } catch (Exception NamingException) { NamingException.printStackTrace(); } }
La sentencia try en el m�todo doGet crea los interfaces home de CalcBean y BonusBean. Despu�s de llamar a calcBonus para calcular el bono, se llama al m�todo BonusHome.create para crear un ejemplar del bean de entidad y la correspondiente fila en la tabla de la base de datos subyacente. Despu�s de crear la tabla, se llama al m�todo BonusHome.findByPrimaryKey para recuperar el mismo registro por su clave primaria (n�mero de la seguridad social). Luego, se devuelve una p�gina HTML al navegador mostrado los datos pasados originalmente, el bono calculado, y los datos recuperados desde la fila de tabla de la base de datos.
La sentencia catch captura y maneja los valores de claves primaria duplicados (n�meros de seguridad social. La tabla de la base de datos subyacente no puede tener dos filas con la misma clave primaria, por eso si pasamos el mismo n�mero de la seguridad social, el servlet captura el error antes de intentar crear el bean de entidad. En el evento de una clave duplicada, el servlet devuelve una p�gina HTML con los datos pasados originalmente, el bono calculado, y un mensaje de error de clave duplicada:
try { Calc theCalculation; //Retrieve Bonus and Social Security Information String strMult = request.getParameter( "MULTIPLIER");//Calculate bonus Integer integerMult = new Integer(strMult); multiplier = integerMult.intValue(); socsec = request.getParameter("SOCSEC"); //Calculate bonus double bonus = 100.00; theCalculation = homecalc.create(); calc = theCalculation.calcBonus( multiplier, bonus); //Create row in table theBonus = homebonus.create(calc, socsec); record = homebonus.findByPrimaryKey(socsec); //Display data out.println("<H1>Bonus Calculation</H1>"); out.println("<P>Soc Sec passed in: " + theBonus.getSocSec() + "<P>"); out.println("<P>Multiplier passed in: " + multiplier + "<P>"); out.println("<P>Bonus Amount calculated: " + theBonus.getBonus() + "<P>"); out.println("<P>Soc Sec retrieved: " + record.getSocSec() + "<P>"); out.println("<P>Bonus Amount retrieved: " + record.getBonus() + "<P>"); out.println("</BODY></HTML>"); //Catch duplicate key error } catch (javax.ejb.DuplicateKeyException e) { String message = e.getMessage(); //Display data out.println("<H1>Bonus Calculation</H1>"); out.println("<P>Soc Sec passed in: " + socsec + "<P>"); out.println("<P>Multiplier passed in: " + multiplier + "<P>"); out.println("<P>Bonus Amount calculated: " + calc + "<P>"); out.println("<P>" + message + "<P>"); out.println("</BODY></HTML>"); } catch (Exception CreateException) { CreateException.printStackTrace(); } }
�Compilar
Primero, compilamos el Bean de entidad y el servlet. Puedes volver a la lecci�n anterior para ver la configuraci�n del path, classpath y d�nde situar los ficheros fuentes.
�Compilar el Bean de Entidad
Unix
#!/bin/sh cd /home/monicap/J2EE J2EE_HOME=/home/monicap/J2EE/j2sdkee1.2.1 CPATH=.:$J2EE_HOME/lib/j2ee.jar javac -d . -classpath "$CPATH" Beans/BonusBean.java Beans/BonusHome.java Beans/Bonus.java
Windows
cd \home\monicap\J2EE set J2EE_HOME=\home\monicap\J2EE\j2sdkee1.2.1 set CPATH=.;%J2EE_HOME%\lib\j2ee.jar javac -d . -classpath %CPATH% Beans/BonusBean.java Bean s/BonusHome.java Beans/Bonus.java
�Compilar el Servlet
Unix:
cd /home/monicap/J2EE/ClientCode J2EE_HOME=/home/monicap/J2EE/j2sdkee1.2.1 CPATH=.:$J2EE_HOME/lib/j2ee.jar:/home/monicap/J2EE javac -d . -classpath "$CPATH" BonusServlet.java
Windows:
cd \home\monicap\J2EE\ClientCode set J2EE_HOME=\home\monicap\J2EE\j2sdkee1.2.1 set CPATH=.;%J2EE_HOME%\lib\j2ee.jar; \home\monicap\J2EE javac -d . -classpath %CPATH% BonusServlet.java
�Arrancar la Plataforma y las Herramientas
Para ejecutar este ejemplo, necesitamos arrancar el servidor J2EE, la herramienta Deploy y la base de datos Cloudscape. En diferentes ventanas, tecleamos los siguientes comandos.
j2ee -verbose deploytool cloudscape -start
Si esto no funciona, tecleamos esto desde el directorio J2EE:
Unix
j2sdkee1.2.1/bin/j2ee -verbose j2sdkee1.2.1/bin/deploytool j2sdkee1.2.1/bin/cloudscape -start
Windows
j2sdkee1.2.1\bin\j2ee -verbose j2sdkee1.2.1\bin\deploytool j2sdkee1.2.1\bin\cloudscape -start
�Ensamblar y Desplegar
Los pasos de esta secci�n son:
- Actualizar el Fichero de Aplicaci�n
- Crear el Bean de Entidad
�Actualizar el Fichero de Aplicaci�n
El archivo web (WAR) contiene BonusServlet y bonus.html. Como hemos modificado BonusServlet, tenemos que actualizar la aplicaci�n J2EE con el nuevo c�digo del servlet.
- Ventana Local Applicatons: Iluminamos la aplicaci�n BonusApp.
- Men� Tools Menu: Seleccionamos Update Application Files .
Nota: Se desinstalar� autom�ticamente la aplicaci�n BonusApp de la lecci�n anterior. |
�Crear el Bean de Entidad
Los pasos para crear el EJB JAR para el bean de entidad son muy similares a los pasos del bean de sesi�n cubiertos en la lecci�n anterior. Sin embargo, hay algunas diferencias, y se explican aqu�:
Nota: En esta lecci�n, el bean de entidad va en un ficjero JAR separado del bean de sesi�n para continuar el ejemplo de la lecci�n anterior con el menor n�mero de cambios. Sin embargo, como estos beans tienen funcionalidades relacionadas podr�amos empaquetarlos y desplegarlos en el mismo fichero JAR. Vermos como hacer esto en la siguiente lecci�n. |
Menu File:
- Seleccionamos New Enterprise Bean.
Introducci�n :
- Leer y Pulsar Next
EJB JAR :
- Nos aseguramos de que BonusApp se ve en Enterprise Bean will go in field.
- Especificamos BonusJar como nombre.
- Pulsamos Add (el m�s cercano a la ventana Contents).
A�adir Componentes al JAR:
- Cambiamos el directorio para que el directorio de beans muestre su contenido.
- Seleccionamos Bonus.class
- Pulsamos Add.
- Selecionamos BonusBean.class
- Pulsamos Add.
- Seleccionamos BonusHome.class
- Pulsamos Add.
- Pulsamos OK.
EJB JAR:
- Pulsamos Next .
General:
- Beans.BonusBean es el nombre de la clase.
- Beans.BonusHome es el interface Home.
- Beans.Bonus es el interface Remoto.
- Introducimos BonusBean como nombre a mostrar.
- Pulsamos Entity .
- Pulsamos Next .
Configuraci�n Entity:
- Seleccionamos Container-Managed persistence.
- En la ventana inferior, marcamos bonus y socsec .
- Especificamos java.lang.String para la clase de la clave primaria. Observa que la clave primaria tiene que ser un tipo de clase. Los tipos primitivos no pueden ser claves primaria.
- Especificamos socsec para el nombre de campo de la clave primaria.
- Pulsamos Next .
Entradas de Entorno:
- Pulsamos Next. Este sencillo bean de entidad no usa propiedades (entradas de entorno).
Referencias a Beans Enterprise:
- Pulsamos Next. Este sencillo bean de entidad no referencia otros beans enterprise.
Referencias a Recursos:
- Pulsamos Next. Este sencillo bean de entidad no busca un objeto database o JavaMail� session.
Seguridad:
- Pulsamos Next. Este sencillo bean de entidad no usa roles de seguridad.
Control de Transaci�n :
- Seleccionamos Container-managed transactions (si no est� ya seleccionado).
- En la lista hacemos que sean requeridos create, findByPrimaryKey, getBonus y getSocSec. Esto significa que el contenedor empieza una nueva transaci�n antes de ejecutar estos m�todos. Las transaciones se env�an justo antes de que los m�todos terminen.
- Pulsamos Next .
- Pulsamos Finish .
Aplicaciones Locales:
- Seleccionamos BonusApp .
- En la ventana Inspecting, seleccionamos JNDI names
- La damos a BonusBean el nombre JNDI de bonus
- Pulsamos la tecla Return
Antes de poder desplegar la aplicaci�n J2EE, necesitamos especificar las condiciones de despliegue para el bean de entidad y generar el SQL. Aqu� est� c�mo hacerlo:
Ventana Local Applications:
- Seleccionamos BonusBean .
Ventana Inspecting:
- Seleccionamos Entity
- Pulsamos el bot�n Deployment Settings de la parte inferior izquierda.
Configuraci�n de Despliegue:
- Especificamos jdbc/Cloudscape (con una C ma�uscula en Cloudscape) para el nombre JNDI de la base de datos.
- Pulsamos Return.
- Nos aseguramos de que las cajas Create table on deploy y Delete table on Deploy est�n marcadas.
- Ahora pulsamos Generate SQL.
Nota: Si obtenemos un error de que la conexi�n fue rechazada, arrancamos la base de datos como se describe en Arrancar la Plataforma y las Herramientas. |
- Cuando se complete la generaci�n de SQL, seleccionamos el m�todo findByPrimaryKey en la caja EJB method. Aparecer� una secuencia SQL a la derecha. Deber�a leerse SELECT "socsec" FROM "BonusBeanTable" WHERE "socsec"=?. El interrogante representa el par�metro pasado por el m�todo findByPrimaryKey.
- Pulsamos OK.
�Verificar y Desplegar la aplicaci�n J2EE
Verificar:
- Con BonusApp seleccionado, elegimos Verifier desde el men� Tools.
- En el di�logo que aparece, pulsamos OK. La ventana deber�a decirnos que no ha fallado ning�n test.
- Cerramos la ventana del verificador porque ya estamos listos para desplegar la apliaci�n.
Nota: En la versi�n 1.2 del software podr�a obtener un error tests app.WebURI. La Aplicaci�n J2EE se desplegar� de todas formas. |
Despliegue:
- En el Men� Tools: Seleccionamos Tools.Deploy Application.
Nota: No marcamos la caja "Return Client Jar". El �nico momento en que debemos chequear esta caja es cuando usamos persistencia controlada por el bean o desplegamos una aplicaci�n solitaria para el programa cliente. Este ejemplo usa un servlet y una p�gina HTML por lo que no debe est�r marcada. Esta caja crea un fichero JAR con toda la informaci�n de despliegue necesaria para una aplicaci�n solitaria. |
- Pulsamos Next. Nos aseguramos de que JNDI names muestra calcs para CalcBean y bonus para BonusBean . Tecleamos cualquier nombre JNDI que no est� y pulsamos la tecla Return.
- Pulsamos Next. Nos aseguramos que el nombre Context Root muestra BonusRoot. Si no lo hace, lo tecleamos nosotros mismos y pulsamos la tecla Return.
- Pulsamos Next.
- Pulsamos Finish para empezar el despliegue.
- Cuando se haya completado el despliegue, pulsamos OK.
�Ejecutar la Aplicaci�n J2EE
El servidor web se ejecuta por defecto en el puerto 8000. Para abrir la p�gina bonus.html apuntamos nuestros navegador a http://localhost:8000/BonusRoot/bonus.html, que es donde DeployTool puso el fichero HMTL.
Rellenamos un n�mero de la seguridad social y un m�ltiplicador, y pulsamos el bot�n Submit. BonusServlet procesa nuestros datos y devuelve una p�gina HTML con el bono calculado.
Bonus Calculation Soc Sec passed in: 777777777 Multiplier passed in: 25 Bonus Amount calculated: 2500.0 Soc Sec retrieved: 7777777777 Bonus Amount retrieved: 2500.0
Si volvemos al c�digo de bonus.html y cambiamos el multiplicador por 2, pero usamos el mismo n�mero de la seguridad social, veremos esto:
Bonus Calculation Soc Sec passed in: 777777777 Multiplier passed in: 2 Bonus Amount calculated: 200.0 Duplicate primary key.
�C�digo Fuente de los Ejemplos
Aqu� tienes un fichero Zip con los ficheros fuente de los ejemplos de esta p�gina: