Esta p�gina cubre c�mo crear un componente EJB con estado. Al contrario que los beans sin estado, los ejemplares de beans con estado est�n asociados con una sesi�n de cliente particular y por lo tanto pueden mantener informaci�n �til durante el tiempo de vida de esa sesi�n. Un ejemplo clasico y familiar dentro del contexto del comercio electr�nico es una carrito de la compra.
Probaremos algo un poco menos ambicioso para empezar! Este bean es similar al StoreAccess creado en la p�gina anterior excepto en que almacenar� el userID del cliente, despu�s de haber pasado la autentificacion.

Nota:
Este bean no se utilizar� m�s a lo largo del tutorial, y este cap�tulo demuestra lo �tiles que son los beans con estado. |
�Crear un Bean sin Estado:
- Ve al explorador de paquetes, expande el nodo del proyecto Mystore, selecciona src, pulsa con el bot�n derecho y aparecer� un men�.
- En el men� selecciona New > Lomboz EJB Creation Wizard.
- Introduce au.com.tusc.sessionState como el nombre del paquete, StoreAccessState como el nombre del bean y pulsa sobre Finish.
Esto crear� un paquete llamado au.com.tusc.sessionState bajo src y dentro de ese paquete crear� StoreAccessStateBean:

Como puedes ver en la figura anterior, se ha creado una etiqueta @ejb.bean a nivel de clase a la que se le ha asignado el tipo del bean, el nombre y el nombre JNDI que se generar�n en el interface Home. Esta etiqueta tambi�n generar� los descriptores de despliegue en los ficheros ejb-jar.xml y jboss.xml una vez generadas las clases EJB, lo que veremos un poco m�s adelante.
Nota:
Esto generar� el nombre del bean, el nombre JNDI y el tipo del bean en el fichero. Adem�s, al nombre del fichero se le a�adir� la palabra 'Bean' ya que s�lo le hemos dado el nombre StoreAccess. Debes ser cuidadoso con las convenciones de nombrado, s�lo tienes que especificar el nombre del bean en el wizard (es decir, sin la palabra 'Bean' ya que �l la a�adir� por ti). |

�Crear el Interface DAO:
Como vamos a utilizar un DAO para acceder a la base de datos para este Bean con Estado, utilizaremos la clase StoreAccesDAOImpl que implementamos en el cap�tulo anterior. Esto proporcionar� la implementaci�n para el interface DAO generado.
- Ve a tu clase Bean y declara esta etiqueta a nivel de clase (es decir, en la parte superior), para generar el interface DAO
@ejb.dao class="au.com.tusc.sessionState.StoreAccessStateDAO" impl-class="au.com.tusc.dao.StoreAccessDAOImpl"
- Expande el nodo StoreAccessStateBean en el explorador de paquetes.
- Pulsa con el bot�n derecho y en el m�nu que aparece selecciona Lomboz J2EE > Add EJB to module.
- Selecciona EJB MyStoreMgr y pulsa OK:
- Expande el nodo MyStoreMgr del proyecto MyStore en el explorador de paquetes.
- Pulsa con el bot�n derecho y en el men� que aparece selecciona Go to Lomboz J2EE > Generate EJB Classes:
Bajo el directorio ejbsrc se generan los interfaces EJB y las clases de ayuda. Se han generado un total de siete ficheros:

- StoreAccessState es el interface remoto.
- StoreAccessLocal es el interface local.
- StoreAccessStateSession extiende la clase bean llamada StoreAccesStateBean.
- StoreAccessStateHome es el interface home remoto.
- StoreAcessStateLocalHome es el interface home local.
- StoreAccessStateUtil es una clase de ayuda que tiene m�todos para acceder a los interfaces home y remoto adem�s de generar el GUID.
- StoreAccesStateDAO es el interface DAO, que implementa la clase StoreAccessDAOImpl bajo au.com.tusc.dao.
StoreAccessStateDAO se genera mediante la etiqueta declarada en StoreAccesStateBean como se muestra abajo. Si no declaras esta etiqueta en ese fichero no se generar� este interface.
@ejb.dao class=au.com.tusc.sessionState.StoreAccessStateDAO impl-class=au.com.tusc.dao.StoreAccessDAOImpl
Otros ficheros de inter�s que se generan son ejb-jar.xml y jboss.xml bajo MyStoreMgr/META-INF.
Como se ve en la siguiente figura, se han generado unos cuantos descriptores en el fichero ejb-jar.xml:

Estos descriptores se han generado mediante la siguiente etiqueta declarada en el fichero StoreAccessBean, que gener� Lomboz:
@ejb.bean name =StoreAccessSate jndi-name=StoreAccessStateBean type=Stateful
Esta etiqueta tambi�n genera los siguientes descriptores en jboss.xml:

�A�adir un M�todo de Negocio:
El siguiente paso es a�adir un m�todo de negocio al bean.
- Ve al nodo StoreAccesStateBean pulsa con el bot�n derecho y selecciona New en el men� que aparece.
- Selecciona Lomboz EJB Method Wizard.
- A�ade un m�todo de negocio con la siguiente firma:
public String loginUser (String username, String password).
- Selecciona el tipo de m�toco como Business y el interface como Remote:
Este wizard genera un m�todo loginUser en la clase bean, con la siguiente etiqueta a nivel de m�todo:

Esta etiqueta es la responsable de generar este m�todo en el interface remoto (en este caso es StoreAccessSate que se crear� cuando generemos las clases).
Ahora, este m�todo de negocio necesita invocar a un m�todo del DAO, que encapsula el acceso a la base de datos.
A�ade otra etiqueta a este m�todo para que se genere un m�todo con esta firma en el interface DAO. Podemos implementar este m�todo en la clase DAOImpl para que el m�todo de negocio pueda obtener el resultado deseado:
@dao.call name=loginUser
A�ade esta etiqueta a nivel de m�todo como se ve abajo:

Ahora genera de nuevo las clases EJB como se vi� en pasos anteriores.
OK, OK!, Como referencia aqu� tienes los pasos a seguir:
|
�A�adir M�todos de Retrollamada:
Al contrario que en el bean sin estado, el m�todo ejbCreate tendr� un argumento. Este se utilizar� para inicializar un campo persistente en el bean.
- A�ade este campo, y los m�todos accesores y mutadores para acceder a �l:
private String userID; /** * @ejb.interface-method * view-type="remote" */ public void setUserID(String userID) { this.userID = userID; } /** * @ejb.interface-method * view-type="remote" */ public String getUserID() { return userID; }
- Ahora a�ade el m�todo ejbCreate con la firma:
public void ejbCreate (String userID)
- Asigna el userID al campo persistente userID que hemos creado arriba:
Ahora, los otros dos m�todos de retrollamadas necesarios para completar este bean son:
- setSessionContext
- unsetSessionContext.
- A�ade un campo para contener sessionContext:
protected SessionContext ctx;
- A�ade un m�todo setSessionContext con sessionContext como par�metro y asignalo a la variable sessionContext:
- De forma similar, a�ade un m�todo unsetSessionContext que ponga a null la variable de contexto.
NOTA:
La clase StoreAccessStateSession desciende de la clase abstracta StoreAccessStateBean e implementa SessionBean, que sobrescribir� todos los m�todos del interface SessionBean. Por eso, despu�s de completar los m�todos de la clase Bean debes regenerar las clases EJB. Se sobreescribir�n los m�todos SessionContext como se vi� en la p�gina anterior. - Genera las Clases EJB:
NOTA:
En p�ginas anteriores ya vimos los pasos para generar las clases EJB.
�Implementar el Interface DAO:
No tenemos que implementar el interface DAO porque est�mos utilizando la clase StoreAccessDAOImpl creada en la p�gina anterior.
- Ve a la clase StoreAccessDAOImpl y modifica la sentencia de la declaraci�n de la clase, para que implemente el interface StoreAccessStateDAO, como se ve en el siguiente fragmento de c�digo:
Ya se han implementado todos los m�todos, s�lo quedan por terminar los descriptores de despligue.
�Desplegar el Bean:
Antes de desplegar el bean tenemos que declarar unas cuantas etiquetas en la clase StoreAccessStateBean:

- A�ade la siguiente etiqueta a nivel de clase en el fichero StoreAccessStateBean:
@ejb.resource-ref res-ref-name="jdbc/DefaultDS" res-type="javax.sql.Datasource" res-auth="Container"
Esta etiqueta generar� los descriptores de despliegue en ejb-jar.xml, ya que el bean tiene que saber a qu� fuentes de datos va a conectarse, de qu� tipo, etc. Esto generar� estos descriptores:
- A�ade esta otra etiqueta al mismo nivel en el mismo fichero:
@jboss.resource-ref res-ref-name="jdbc/DefaultDS" jndi-name="java:/DefaultDS"
Esta etiqueta generar� los descriptores de despliegue en jboss.xml, ya que el servidor de aplicaciones tiene que saber qu� nombre JNDI tendr� la fuente de datos. Esto generar� estos descriptores:
- A�ade esta otra etiqueta en el mismo sitio:
@jboss.container-configuration name ="Standard Stateful SessionBean"
Esta etiqueta generar� los descriptores de despliegue en jboss.xml, ya que el servidor de aplicaciones tiene que saber qu� configuraci�n va a leer el bean con estado desde standardjboss.xml bajo /opt/jboss/jboss-3.2.1/server/all/conf/. Esto generar� los siguientes descripores en jboss.xml:
<session> <ejb-name>StoreAccessState</ejb-name> <jndi-name>StoreAccessStateBean</jndi-name> <configuration-name>Standard Stateful SessionBean</configuration-name> <resource-ref> <res-ref-name>jdbc/DefaultDS</res-ref-name> <jndi-name>java:/DefaultDS</jndi-name> </resource-ref> </session>
NOTA:
Esta configuraci�n es para que el bean de sesi�n con estado lea el contenedor de JBoss. JBoss viene con un timeout de 60 minutos para los beans de sesi�n con estado. Cambia el atributo <max-bean-life> a 120 segundos y reinicia el servidor. Como puedes ver en el siguiente fragmento de c�digo del fichero /opt/jboss/jboss-3.2.1/servaer/all/conf/standardjboss.xml:<container-configuration> <container-name>Standard Stateful SessionBean</container-name> <call-logging>false</call-logging> <invoker-proxy-binding-name>stateful-rmi-invoker</invoker-proxy-binding-name> <container-interceptors> ------------------------------------------------------------------- ---------------------------------------------------------------------- --------------------------------------------------------------------- <container-cache-conf> <cache-policy>org.jboss.ejb.plugins.LRUStatefulContextCachePolicy</cache-policy> <cache-policy-conf> <min-capacity>50</min-capacity> <max-capacity>1000000</max-capacity> <!--remover-period>1800</remover-period--> <remover-period>120</remover-period> <max-bean-life>120</max-bean-life> <!-- By default Jboss comes withh 60 mins time out for stateful bean,change it to 120 secs (2 mins) and restart the server to read this config. --> <!--max-bean-life>1800</max-bean-life--> <!-- 1800 secs = 30 mins --> <overager-period>300</overager-period> <max-bean-age>600</max-bean-age> <resizer-period>400</resizer-period> <max-cache-miss-period>60</max-cache-miss-period> <min-cache-miss-period>1</min-cache-miss-period> <cache-load-factor>0.75</cache-load-factor> </cache-policy-conf> </container-cache-conf> ---------------------------------------------------------------------- ---------------------------------------------------------------------
Ahora, ya est� todo terminado y ha llegado el momento de desplegar el bean.
- Primero, regenera tus clases EJB como vimos en pasos anteriores y por �ltima vez.
NOTA:
Hemos regenerado las clases una y otra vez para poder explicar cada paso y su resultado. Una vez que est�s familiarizado con estos pasos s�lo necesitas generar tus clases de vez en cuando. De cualquier modo, no afecta a tu implementaci�n, por eso puedes (re)generar tus clases siempre que quieras. - Ve a la Vista Lomboz J2EE View y expande el nodo MyStore > MyStoreMgr, selecciona Jboss 3.2.1 ALL.
- Pulsa con el bot�n derecho y selecciona Debug Sever en el men� desplegable.
- Ve al nodo MyStoreMgr en la vista LombozJ2EE, pulsa con el bot�n derecho y selecciona Deploy en el men� desplegable.
Ahora espera un poco para ver el resultado del despliegue.
Si todo ha ido bien, obtendr�s en la consola un mensaje como este:

Ya que hemos desplegado con �xito nuestro bean creemos un cliente de prueba, que llamar� al m�todo loginUser de StoreAccessStateBean.
�Crear un Test de Cliente:
- Ve al nodo del proyecto MyStore, selecciona el nodo src y pulsa con el bot�n derecho.
- Selecciona New en el men� desplegable y selecciona el Lomboz EJB Test Client Wizard:
- Selecciona el nombre de paquete como au.com.tusc.client, el nombre como SessionStateClient y el Ejb Home como au.com.tusc.sessionState.StoreAccessStateHome y el Ejb Interface como au.com.tusc.sessionState.StoreAccessState:
Esto generar� los m�todos de ayuda necesarios en la clase SessionStateClient y simplemente tendremos que llamar al m�todo loginUser del bean.
- A�ade las siguientes l�neas de c�digo al m�todo testBean:
public void testBean() { String userID = null; try { au.com.tusc.sessionState.StoreAccessState myBean = getHome().create(userID); //-------------------------------------- //This is the place you make your calls. //System.out.println(myBean.callYourMethod()); System.out.println("Request from client : "); userID = myBean.loginUser("ANDY","PASSWD"); System.out.println("Reply from Server: Your userid is " + userID); myBean.setUserID(userID); System.out.println("Going to Sleep for 1 min ......................... " ); Thread.sleep(60000); // sleep for 1 minute. System.out.println("Reply from bean after 1min " + myBean.getUserID()); System.out.println("Again going to Sleep for 3 min ......................... " ); Thread.sleep(180000); // sleep for 3 minute. System.out.println("Resuming after 3 mins ......................... " ); //Next statement will not be executed as bean will timeout on the server side //resulting in exception. System.out.println("Reply from bean after 2mins " + myBean.getUserID()); }catch (InterruptedException e) { }catch (NoSuchObjectException e) { System.out.println("No Such Object Exception caught "); } catch (RemoteException e) { System.out.println("Remote Exception caught "); } catch (CreateException e) { e.printStackTrace(); } catch (NamingException e) { e.printStackTrace(); } catch (EJBException e) { System.out.println("EJB Exception caught "); } } public static void main(String[] args) { SessionStateClient test = new SessionStateClient(); test.testBean(); }
�Probar el Cliente
- Ahora, para poder probar el cliente, selecciona el nodo SessionStateClient ve al men� superior y selecciona el icono con el hombre corriendo.
- Selecciona Run as > Java Application
Ahora bajo la consola, si obtienes una respuesta U2 para ANDY, antes de un minuto, pero despu�s de 3 minutos se captura una NoSuchObjectException significar� que el bean con estado est� funcionando con �xito.
