Extensiones a las API de acceso a datos

Si una API de acceso a datos individual no proporciona una solución completa para las aplicaciones, utilice las extesiones de WebSphere Application Server para obtener la interoperatividad entre las API de JCA y JDBC.

Es posible que las aplicaciones que proceden de diferentes configuraciones de gestión de recursos complejas requieran utilizar tanto la API JCA (Java™ Platform, Enterprise Edition (Java EE Connector Architecture) como la API JDBC (Java Database Connectivity). No obstante, en algunos casos el modelo de programación JDBC no se integra completamente con JCA (aún cuando la integración completa sea una base de la especificación de JCA). Estas incoherencias pueden limitar las opciones de acceso a datos para las aplicaciones que utilizan las dos API. WebSphere Application Server proporciona extensiones de la API para solucionar los problemas de compatibilidad.

Por ejemplo:

Sin las ventajas de la extensión, las aplicaciones que utilizan las dos API no pueden modificar las propiedades de conexiones que se pueden compartir después de realizar la solicitud de conexión, si existen otros manejadores para esa conexión. (Si no hay ningún otro manejador asociado a la conexión, entonces se pueden alterar las propiedades de la conexión. Esta limitación proviene de una incompatibilidad entre las políticas de configuración de conexión de las API:

La especificación JCA (Connector Architecture) admite confiar al adaptador de recursos los valores de propiedades específicas en el momento en que se solicita la conexión (utilizando el método getConnection()) pasando un objeto ConnectionSpec. El objeto ConnectionSpec contiene las propiedades de conexión necesarias que se utilizan para obtener una conexión. Después de obtener una conexión desde este entorno, la aplicación no necesita alterar las propiedades. El modelo de programación JDBC, no obstante, no tiene la misma interfaz para especificar las propiedades de la conexión. Obtiene primero la conexión, y luego establece las propiedades en ella.

WebSphere Application Server proporciona las siguientes ampliaciones para completar los huecos entre las especificaciones JDBC y JCA:

Ejemplo: Utilización de las API ampliadas de IBM para las conexiones de base de datos.

Utilizando la API ampliada de WSDataSource, puede codificar la aplicación JDBC para definir las propiedades de conexión mediante un objeto antes de obtener una conexión. Este comportamiento aumenta las posibilidades de que la aplicación pueda compartir una conexión con otro componente como, por ejemplo, un CMP.

Si la aplicación se ejecuta con una conexión que se puede compartir con otros beans CMP (persistencia gestionada por contenedor) dentro de una transacción, se recomienda utilizar las API aplicadas de WebSphere Application Server para obtener la conexión. Cuando se utilizan estas API, la aplicación no se puede transportar a otros servidores de aplicaciones.

Puede codificar con la API ampliada directamente en las aplicaciones JDBC. En lugar de utilizar la interfaz DataSource para obtener una conexión, utilice la interfaz WSDataSource. El siguiente segmento de código ilustra WSDataSource:

import com.ibm.websphere.rsadapter.*;
... 
// Crear un JDBCConnectionSpec y establecer las propiedades de la conexión. Si esta conexión
// se comparte con el bean CMP, asegúrese de que el nivel de aislamiento es el mismo que
// el nivel de aislamiento
que se correlaciona mediante el Intento de acceso definido en el bean CMP.

JDBCConnectionSpec connSpec = WSRRAFactory.createJDBCConnectionSpec(); 
connSpec.setTransactionIsolation(CONNECTION.TRANSACTION_REPEATABLE_READ); 
connSpec.setCatalog("DEPT407");

// Utilice WSDataSource para obtener la conexión
Connection conn = ((WSDataSource)datasource).getConnection(connSpec);

Ejemplo: Utilización de las API ampliadas de IBM para compartir conexiones entre beans CMP y beans BMP.

En un componente de aplicación que accede a datos a través de objetos JDBC como, por ejemplo, un bean BMP (persistencia gestionada por bean), puede utilizar una API ampliada de WebSphere para definir las propiedades de la conexión mediante un objeto antes de obtener una conexión. Este comportamiento aumenta las posibilidades de que el bean BMP comparta una conexión con un bean CMP (persistencia gestionada por contenedor).

Si el bean BMP se ejecuta con una conexión que se puede compartir con otros beans CMP (persistencia gestionada por contenedor) dentro de una transacción, se recomienda utilizar las API ampliadas de WebSphere Application Server para obtener la conexión. Cuando se utilizan estas API, la aplicación no se puede transportar a otros servidores de aplicaciones.

En este caso, utilice la interfaz WSDataSource de la API, en lugar de la interfaz DataSource. Para asegurarse de que los beans CMP y BMP (persistencia gestionada por bean) comparten la misma conexión física, defina el mismo perfil de intento de acceso en los beans CMP y BMP. Dentro del método BMP, puede obtener el nivel de aislamiento correcto de la clase de ayudante del adaptador de recursos relacional.

package fvt.example;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.ejb.CreateException;
import javax.ejb.DuplicateKeyException;
import javax.ejb.EJBException;
import javax.ejb.ObjectNotFoundException;
import javax.sql.DataSource;

// La API ampliada de IBM utiliza las siguientes importaciones
import com.ibm.websphere.appprofile.accessintent.AccessIntent;
import com.ibm.websphere.appprofile.accessintent.AccessIntentService;
import com.ibm.websphere.rsadapter.JDBCConnectionSpec;
import com.ibm.websphere.rsadapter.WSCallHelper;
import com.ibm.websphere.rsadapter.WSDataSource;
import com.ibm.websphere.rsadapter.WSRRAFactory;

/**
 * Clase de implementación de bean para enterprise bean: Sencilla
 */

public class SimpleBean implements javax.ejb.EntityBean {
 private javax.ejb.EntityContext myEntityCtx;

 // Contexto inicial utilizado para la búsqueda.

 private javax.naming.InitialContext ic = null;

 // definir una JDBCConnectionSpec como variable de instancia

 private JDBCConnectionSpec connSpec;

 // definir un AccessIntentService que se utiliza para obtener 
 // un objeto AccessIntent.

 private AccessIntentService aiService;

 // Objeto AccessIntent utilizado para obtener el nivel de aislamiento

 private AccessIntent intent = null;
 
 // Nombre de tabla de persistencia

 private String tableName = "cmtest";

 // Nombre JNDI de DataSource

 private String dsName = "java:comp/env/jdbc/SimpleDS";

 // DataSource

 private DataSource ds = null;

 // variables de instancia de bean.

 private int id;
 private String name;

 /**
  * En el método setEntityContext, debe obtener el objeto AccessIntentService 
  * para que los siguientes métodos obtengan el objeto
  * AccessIntent. 
  * Los otros métodos ejb llamarán al método privado getConnection() para obtener la
  * conexión que tiene todas las propiedades de conexión específicas
  */

 public void setEntityContext(javax.ejb.EntityContext ctx) {
  myEntityCtx = ctx;

  try {
   aiService =
    (AccessIntentService) getInitialContext().lookup(
     "java:comp/websphere/AppProfile/AccessIntentService");
   ds = (DataSource) getInitialContext().lookup(dsName);
  }
  catch (javax.naming.NamingException ne) {
   throw new javax.ejb.EJBException(
    "Naming exception: " + ne.getMessage());
  }
 }

  /**
  * ejbCreate
  */

 public fvt.example.SimpleKey ejbCreate(int newID)
  throws javax.ejb.CreateException, javax.ejb.EJBException {
  Connection conn  = null;
  PreparedStatement ps = null;

  // Insertar serie SQL

  String sql = "INSERT INTO"  + tableName +  "(id, name) VALUES (?, ?)";

  id = newID;
  name = "";

  try {
                    // llamar al método común para obtener la conexión específica

   conn = getConnection();
  }
  catch (java.sql.SQLException sqle) {
   throw new EJBException("SQLException caught: " + sqle.getMessage());
  }
  catch (javax.resource.ResourceException re) {
   throw new EJBException(
    "ResourceException caught: " + re.getMessage());
  }

  try {
   ps = conn.prepareStatement(sql);
   ps.setInt(1, id);
   ps.setString(2, name);

   if (ps.executeUpdate() != 1){
    throw new CreateException("Failed to add a row to the DB");
   }
  }
  catch (DuplicateKeyException dke) {
   throw new javax.ejb.DuplicateKeyException(
    id + "has already existed");
  }
  catch (SQLException sqle) {
   throw new javax.ejb.CreateException(sqle.getMessage());
  }
  catch (CreateException ce) {
   throw ce;
  }
  finally {
   if (ps != null) {
    try {
     ps.close();
    }
    catch(Exception e){
    }
   }
  }
  return new SimpleKey(id);
 }

  /**
  * ejbLoad
  */

 public void ejbLoad() throws javax.ejb.EJBException {

  Connection conn  = null;
  PreparedStatement ps = null;
  ResultSet rs = null;

  String loadSQL = null;

  try {
                    // llamar al método común para obtener la conexión específica

   conn = getConnection();
  }
  catch (java.sql.SQLException sqle) {
   throw new EJBException("SQLException caught: " + sqle.getMessage());
  }
  catch (javax.resource.ResourceException re) {
   throw new EJBException(
    "ResourceException caught: " + re.getMessage());
  }

  // Debe determinar qué sentencia select se va a utilizar según el
  // tipo de AccessIntent:
  // Si es READ, utiliza una sentencia SELECT normal. De lo contrario, utiliza 
  // una sentencia SELECT...FORUPDATE
  // Si el programa de fondo es SQLServer, puede utilizar una sintaxis diferente
  // para la cláusula FOR UPDATE.

  if (intent.getAccessType() == AccessIntent.ACCESS_TYPE_READ) {
   loadSQL = "SELECT * FROM"  + tableName +  "WHERE id = ?";
  }
  else {
   loadSQL = "SELECT * FROM"  + tableName +  "WHERE id = ? FOR UPDATE";
  }

  SimpleKey key = (SimpleKey) getEntityContext().getPrimaryKey();

  try {
   ps = conn.prepareStatement(loadSQL);
   ps.setInt(1, key.id);
   rs = ps.executeQuery();
   if (rs.next()) {
    id = rs.getInt(1);
    name = rs.getString(2);
   }
   else {
    throw new EJBException("Cannot load id = " + key.id);
   }
  }
  catch (SQLException sqle) {
   throw new EJBException(sqle.getMessage());
  }
  finally {
   try {
    if (rs != null)
     rs.close();
   }
   catch(Exception e){
   }
   try {
    if (ps != null)
     ps.close();
   }
   catch(Exception e){
   }
   try {
    if (conn != null)
     conn.close();
   }
   catch(Exception e){
   }
  }
 }

        /**
         * Este método utilizará AccessIntentService para obtener el intento de acceso;
         * después obtiene el nivel de aislamiento desde el DataStoreHelper 
         * y lo establece en la especificación de conexión; después utiliza esta 
         * especificación de conexión para obtener una conexión que tenga las propiedades 
         * las propiedades personalizadas.
         **/

 private Connection getConnection()
  throws java.sql.SQLException, javax.resource.ResourceException, EJBException {

  // obtener objeto de intento de acceso actual utilizando el contexto de EJB
  intent = aiService.getAccessIntent(myEntityCtx);
  
  // Supongamos que este bean sólo soporta la simultaneidad pesimista
  if (intent.getConcurrencyControl()
   != AccessIntent.CONCURRENCY_CONTROL_PESSIMISTIC) {
   throw new EJBException("Bean supports only pessimistic concurrency");
  }

  // determinar el nivel de aislamiento correcto de la base de datos configurada 
  // utilizando DataStoreHelper
  int isoLevel =
   WSCallHelper.getDataStoreHelper(ds).getIsolationLevel(intent);
   connSpec = WSRRAFactory.createJDBCConnectionSpec();
  connSpec.setTransactionIsolation(isoLevel);

  // Obtener la conexión utilizando la especificación de conexión
  Connection conn = ((WSDataSource) ds).getConnection(connSpec);
  return conn;
 }

Icon that indicates the type of topic Reference topic



Timestamp icon Last updated: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rdat_cextiapi
File name: rdat_cextiapi.html