(Anterior)
BMP ("Bean Managed Persistence")
Debido a la longitud de esta clase, es fraccionada en cuatro partes describiendo el funcionamiento de cada sección.
Clase CuentaBancariaBean
package com.osmosislatina.ejb.cuenta;
import java.sql.*;
import javax.sql.*;
import java.util.*;
import javax.ejb.*;
import javax.naming.*;
public class CuentaBancariaBean implements EntityBean {
private String id;
private String nombre;
private String apellido;
private double saldo;
private EntityContext context;
private Connection con;
private String dbName = "java:/DefaultDS";
|
public void deducir(double cantidad)
throws SaldoInsuficiente {
if (saldo - cantidad < 0) {
throw new SaldoInsuficiente();
}
saldo -= cantidad;
}
|
public void abonar(double cantidad) {
saldo += cantidad;
}
|
public String getNombre() {
return nombre;
}
|
public String getApellido() {
return apellido;
}
|
public double getSaldo() {
return saldo;
}
|
En esta primer sección se importan las diversas clases que serán utilizadas a lo largo del EJB, vale notar que dentro de éstas se incluyen java.sql y javax.sql las cuales son empleadas para accesar Bases de Datos.
Posteriormente se inicia la declaración de la clase, misma que por ser un "Entity EJB" debe implementar la interfase EntityBean.
De inmediato se definen los 7 campos utilizados dentro del EJB.
Son definidos e implementados los métodos correspondientes al "Remote Interface": deducir, abonar, getNombre, getApellido, getSaldo.
A continuación se describen las implementaciones de los métodos del "Home Interface"
public String ejbCreate(String id, String nombre,
String apellido, double saldo)
throws CreateException {
if (saldo < 0.00) {
throw new CreateException
("No puede generarse una cuenta con Saldo Inicial menor que 0");
}
try {
insertarFila(id, nombre, apellido, saldo);
} catch (Exception ex) {
throw new EJBException("Error al intentarse crearse EJB (ejbCreate) : " +
ex.getMessage());
}
this.id = id;
this.nombre = nombre;
this.apellido = apellido;
this.saldo = saldo;
return id;
}
|
public String ejbFindByPrimaryKey(String primaryKey)
throws FinderException {
boolean resultado;
try {
resultado = selectByPrimaryKey(primaryKey);
} catch (Exception ex) {
throw new EJBException("Error al intentarse buscar el EJB por PrimaryKey : " + ex.getMessage());
}
if (resultado) {
return primaryKey;
}
else {
throw new ObjectNotFoundException
("Informacion sobre la cuenta numero " + primaryKey + " no fue encontrada.");
}
}
|
public Collection ejbFindPorApellido(String apellido)
throws FinderException {
Collection resultado;
try {
resultado = seleccionarPorApellido(apellido);
} catch (Exception ex) {
throw new EJBException("Error al intentarse buscar el EJB por Apellido : " + ex.getMessage());
}
return resultado;
}
|
public Collection ejbFindEnRango(double inferior, double superior)
throws FinderException {
Collection resultado;
try {
resultado = seleccionarEnRango(inferior, superior);
} catch (Exception ex) {
throw new EJBException("Error al intentarse buscar el EJB por Rango : " + ex.getMessage());
}
return resultado;
}
|
La función ejbCreate a diferencia de aquella utilizada en un "SessionBean" contiene lógica de ejecución; esta lógica se encarga de dos procesos :
Se inserta una copia de la información proporcionada por el Cliente(JSP/Servlet) en la Base de Datos, la creación de esta fila/renglón es llevada acabo por el método insertarFila-- descrito posteriormente. Lo anterior permite que la información del "Application Server"/"EJB Container" refleje aquella de la Base de Datos.
Se inicializa la instancia del EJB a través de los campos definidos con anterioridad.
ejbFindByPrimaryKey realiza una búsqueda por la instancia del EJB en base a los parámetros pasados por el cliente; esta búsqueda es realizada a través del método selectByPrimaryKey -- también descrito posteriormente.
Los métodos ejbFindPorApellido y ejbFindEnRango realizan búsquedas por EJB's en base a Apellidos y rangos de Saldo respectivamente; dichas búsquedas son realizadas por los métodos seleccionarEnRango y seleccionarPorApellido descritos en otra sección de código.
A continuación se describen las implementaciones de los métodos necesarios para terminar de cumplir con los requerimientos de un "Entity EJB":
public void ejbRemove() {
id = (String)context.getPrimaryKey();
try {
eliminarFila(id);
} catch (Exception ex) {
throw new EJBException("Error al intentarse eliminar EJB (ejbRemove): " +
ex.getMessage());
}
}
|
public void setEntityContext(EntityContext context) {
this.context = context;
}
|
public void unsetEntityContext() {
context = null;
}
|
public void ejbActivate() {
id = (String)context.getPrimaryKey();
}
|
public void ejbPassivate() {
id = null;
}
|
public void ejbLoad() {
id = (String)context.getPrimaryKey();
try {
cargarFila(id);
} catch (Exception ex) {
throw new EJBException("Error al intentarse cargar informacion para el EJB (ejbLoad) : " +
ex.getMessage());
}
}
|
public void ejbStore() {
try {
guardarFila();
} catch (Exception ex) {
throw new EJBException("Error al intentarse guardar informacion para el EJB (ejbStore) : " +
ex.getMessage());
}
}
|
public void ejbPostCreate(String id, String nombre,
String apellido, double saldo) { }
|
La función ejbRemove también a diferencia de aquella utilizada en un "SessionBean" contiene cierta lógica de ejecución, esta lógica elimina tanto la instancia del EJB así como la respectiva fila en la Base de Datos; la eliminación de esta fila es llevada acabo por el método eliminarFila -- descrito en la siguiente sección.
Los métodos setEntityContext y unsetEntityContext como ya fue mencionado son utilizados para adquirir recursos que son empleados con distintas instancias de EJB's.
ejbActivate y ejbPassivate son métodos utilizados en caso de ser necesario pasar a memoria secundaria instancias de EJB's.
ejbLoad y ejbStore son dos métodos utilizados para cargar y guardar información hacia la Base de Datos, ambos emplean los métodos auxiliares cargarFila y guardarFila para realizar esta tarea; ambos métodos forman una parte critica de la sincronización entre la Base de Datos y EJB's, además su uso esta fuertemente vinculado a transacciones
Finalmente se describen las funciones utilizadas para interactuar con la Base de Datos; en la sección de CMP ("Container Managed Persistence") Entity Beans se observará como estas funciones son generadas por el "Application Server"/"EJB Container").
/*********************** Rutina para Base de Datos *************************/
private void realizarConexion() throws NamingException, SQLException {
InitialContext ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup(dbName);
con = ds.getConnection();
}
private void liberarConexion() throws NamingException, SQLException {
con.close();
}
|
private void insertarFila (String id, String nombre, String apellido,
double saldo) throws SQLException,NamingException {
realizarConexion();
String insertStatement =
"insert into cuentas_bancarias values ( ? , ? , ? , ? )";
PreparedStatement prepStmt =
con.prepareStatement(insertStatement);
prepStmt.setString(1, id);
prepStmt.setString(2, nombre);
prepStmt.setString(3, apellido);
prepStmt.setDouble(4, saldo);
prepStmt.executeUpdate();
prepStmt.close();
liberarConexion();
}
|
private void eliminarFila(String id) throws SQLException,NamingException {
realizarConexion();
String deleteStatement =
"delete from cuentas_bancarias where id = ? ";
PreparedStatement prepStmt =
con.prepareStatement(deleteStatement);
prepStmt.setString(1, id);
prepStmt.executeUpdate();
prepStmt.close();
liberarConexion();
}
|
private boolean selectByPrimaryKey(String primaryKey)
throws SQLException,NamingException {
realizarConexion();
String selectStatement =
"select id " +
"from cuentas_bancarias where id = ? ";
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setString(1, primaryKey);
ResultSet rs = prepStmt.executeQuery();
boolean resultado = rs.next();
prepStmt.close();
liberarConexion();
return resultado;
}
|
private Collection seleccionarPorApellido(String apellido)
throws SQLException,NamingException {
realizarConexion();
String selectStatement =
"select id " +
"from cuentas_bancarias where apellido = ? ";
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setString(1, apellido);
ResultSet rs = prepStmt.executeQuery();
ArrayList a = new ArrayList();
while (rs.next()) {
String id = rs.getString(1);
a.add(id);
}
prepStmt.close();
liberarConexion();
return a;
}
|
private Collection seleccionarEnRango(double inferior, double superior)
throws SQLException,NamingException {
realizarConexion();
String selectStatement =
"select id from cuentas_bancarias " +
"where saldo between ? and ?";
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setDouble(1, inferior);
prepStmt.setDouble(2, superior);
ResultSet rs = prepStmt.executeQuery();
ArrayList a = new ArrayList();
while (rs.next()) {
String id = rs.getString(1);
a.add(id);
}
prepStmt.close();
liberarConexion();
return a;
}
|
private void cargarFila(String id) throws SQLException,NamingException {
realizarConexion();
String selectStatement =
"select nombre, apellido, saldo " +
"from cuentas_bancarias where id = ? ";
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setString(1, this.id);
ResultSet rs = prepStmt.executeQuery();
if (rs.next()) {
this.nombre = rs.getString(1);
this.apellido = rs.getString(2);
this.saldo = rs.getDouble(3);
prepStmt.close();
}
else {
prepStmt.close();
throw new NoSuchEntityException("Fila para la cuenta numero " + id +
" no fue encontrada en la Base de Datos.");
}
liberarConexion();
}
|
private void guardarFila() throws SQLException,NamingException {
realizarConexion();
String updateStatement =
"update cuentas_bancarias set nombre = ? ," +
"apellido = ? , saldo = ? " +
"where id = ?";
PreparedStatement prepStmt =
con.prepareStatement(updateStatement);
prepStmt.setString(1, nombre);
prepStmt.setString(2, apellido);
prepStmt.setDouble(3, saldo);
prepStmt.setString(4, id);
int rowCount = prepStmt.executeUpdate();
prepStmt.close();
liberarConexion();
if (rowCount == 0) {
throw new EJBException("No fue posible guardar informacion de la cuenta numero " + id);
}
}
} //
|
El método realizarConexion es utilizado para adquirir una conexión hacia la Base de Datos; es importante notar que esta búsqueda se esta realizando a través de JNDI, esto es, para el EJB la Base de Datos es un Objeto que esta disponible en la Red , la ubicación exacta de la Base de Datos es definida al nivel de "Application Server"; observe que el parámetro de entrada es llamado dbName, dicho parámetro es definido al inicio de la Clase con un valor java:/DefaultDS el cual representa una ubicación JNDI, dicho nombre JNDI es asociado en el "Application Server"/"EJB Container" con una ubicación física de la Base de Datos.
Los métodos que siguen definen la lógica que será utilizada para interactuar con la Base de Datos, y contienen en su mayoría declaraciones comunes del API JDBC.
|