(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.
|