Extensions des API d'accès aux données

Si une API d'accès unique aux données ne représente pas une solution complète pour vos applications, utilisez les extensions de WebSphere Application Server pour obtenir une interopérabilité entre les API JCA et JDBC.

Les applications qui reposent sur diverses configurations complexes de gestion des ressources peuvent nécessiter d'utiliser l'API Java™ Platform, Enterprise Edition (Java EE) Connector Architecture (JCA) et l'API Java Database Connectivity (JDBC). Cependant, dans certains cas, le modèle de programmation JDBC ne s'intègre pas pleinement à l'architecture JCA (J2EE Connector Architecture), bien que l'intégration totale constitue un fondement de la spécification JCA. Ces incohérences peuvent limiter les options d'accès aux données pour une application qui utilise les deux API. WebSphere Application Server fournit des extensions d'API dans le but de résoudre ces problèmes de compatibilité.

Exemple :

Sans l'aide d'une extension, les applications qui utilisent les deux API ne peuvent pas modifier les propriétés d'une connexion partageable après avoir effectué la demande de connexion si d'autres descripteurs existent pour cette connexion. (Si aucun autre descripteur n'est associé à la connexion, alors les propriétés de la connexion peuvent être modifiées.) Cette limitation découle d'une incompatibilité entre les règles de configuration des connexions en vigueur dans les API :

La spécification JCA (J2EE Connector Architecture) prend en charge la transmission à l'adaptateur de ressources des paramètres de propriétés spécifiques au moment où vous demandez la connexion (à l'aide de la méthode getConnection()) en les passant dans un objet ConnectionSpec. L'objet ConnectionSpec contient les propriétés de connexion nécessaires à l'obtention d'une connexion. Une fois que vous avez obtenu une connexion de cet environnement, votre application n'a plus besoin de modifier les propriétés. Cependant, le modèle de programmation JDBC n'offre pas la même interface pour spécifier les propriétés de la connexion. Dans ce modèle, la connexion est d'abord obtenue, puis ses propriétés sont définies.

WebSphere Application Server fournit les extensions suivantes pour pallier ce type d'incohérences entre les spécifications JDNC et JCA :

Exemple : utilisation des API étendues IBM pour les connexions de base de données.

A l'aide de l'API étendue WSDataSource, vous pouvez coder votre application JDBC afin de définir les propriétés de connexion par un objet avant d'obtenir la connexion. Ce comportement accroît les chances que l'application puisse partager une connexion avec un autre composant, tel qu'un CMP.

Si votre application fonctionne avec une connexion partageable susceptible d'être partagée avec d'autres beans CMP dans une transaction, il est conseillé d'obtenir cette connexion à l'aide des API étendues de WebSphere Application Server. Ces API étant propres à WebSphere Application Server, si vous les utilisez, votre application ne sera pas compatible (portable) avec d'autres serveurs d'applications.

Vous pouvez effectuer le codage avec l'API étendue directement dans votre application JDBC ; dans ce cas, pour obtenir une connexion, utilisez l'interface WSDataSource plutôt que l'interface DataSource. Le segment de code suivant illustre l'interface WSDataSource:

import com.ibm.websphere.rsadapter.*;
... 
// Create a JDBCConnectionSpec and set connection properties. If this connection
// is shared with the CMP bean, make sure that the isolation level is the same as
// the isolation level that is mapped by the Access Intent defined on the CMP bean. 

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

// Use WSDataSource to get the connection 
Connection conn = ((WSDataSource)datasource).getConnection(connSpec);

Exemple : utilisation des API étendues IBM pour partager des connexions entre des beans CMP et des beans BMP.

Au sein d'un composant d'application qui accède aux données par le biais d'objets JDBC (comme par exemple un bean BMP ou bean-managed persistence), vous pouvez utiliser une API étendue de WebSphere pour définir des propriétés de connexion à l'aide d'un objet avant d'obtenir la connexion. Ce comportement accroît les chances que le bean BMP puisse partager une connexion avec un bean CMP (container-managed persistence).

Si votre bean BMP fonctionne avec une connexion partageable susceptible d'être partagée avec d'autres beans CMP dans une transaction, il est conseillé d'obtenir cette connexion à l'aide des API étendues de WebSphere Application Server. Ces API étant propres à WebSphere Application Server, si vous les utilisez, votre application ne sera pas compatible (portable) avec d'autres serveurs d'applications.

Dans ce cas, utilisez l'interface WSDataSource de l'API étendue plutôt que l'interface DataSource. Pour que les beans CMP et BMP partagent la même connexion physique, définissez le même profil de tentative d'accès sur ces deux types de bean. A l'intérieur de votre méthode BMP, vous pouvez obtenir le niveau d'isolement correct à partir de la classe auxiliaire de l'adaptateur de ressources relationnelles.

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;

// following imports are used by the IBM extended API
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;

/**
 * Bean implementation class for Enterprise Bean: Simple
 */

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

 // Initial context used for lookup.

 private javax.naming.InitialContext ic = null;

 // define a JDBCConnectionSpec as instance variable

 private JDBCConnectionSpec connSpec;

 // define an AccessIntentService which is used to get 
 // an AccessIntent object.

 private AccessIntentService aiService;

 // AccessIntent object used to get Isolation level

 private AccessIntent intent = null;
 
 // Persitence table name

 private String tableName = "cmtest";

 // DataSource JNDI name

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

 // DataSource

 private DataSource ds = null;

 // bean instance variables.

 private int id;
 private String name;

 /**
  * In setEntityContext method, you need to get the AccessIntentService 
  * object in order for the subsequent methods to get the AccessIntent
  * object. 
  * Other ejb methods will call the private getConnection() to get the
  * connection which has all specific connection properties
  */

 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;

  // Insert SQL String

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

  id = newID;
  name = "";

  try {
                    // call the common method to get the specific connection

   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 {
                    // call the common method to get the specific connection

   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());
  }

  // You need to determine which select statement to be used based on the
  // AccessIntent type:
  // If READ, then uses a normal SELECT statement. Otherwise uses a 
  // SELECT...FORUPDATE statement
  // If your backend is SQLServer, then you can use different syntax for
  // the FOR UPDATE clause.

  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) {
   }
  }
 }

        /**
         * This method will use the AccessIntentService to get the access intent;
         * then gets the isolation level from the DataStoreHelper 
         * and sets it in the connection spec; then uses this connection 
         * spec to get a connection which has the specific connection 
         * properties.
         **/

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

  // get current access intent object using EJB context
  intent = aiService.getAccessIntent(myEntityCtx);
  
  // Assume this bean only supports the pessimistic concurrency
  if (intent.getConcurrencyControl()
   != AccessIntent.CONCURRENCY_CONTROL_PESSIMISTIC) {
   throw new EJBException("Bean supports only pessimistic concurrency");
  }

  // determine correct isolation level for currently configured database 
  // using DataStoreHelper
  int isoLevel =
   WSCallHelper.getDataStoreHelper(ds).getIsolationLevel(intent);
   connSpec = WSRRAFactory.createJDBCConnectionSpec();
  connSpec.setTransactionIsolation(isoLevel);

  // Get connection using connection spec
  Connection conn = ((WSDataSource) ds).getConnection(connSpec);
  return conn;
 }

Icône indiquant le type de rubrique Rubrique de référence



Icône d'horodatage Dernière mise à jour: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rdat_cextiapi
Nom du fichier : rdat_cextiapi.html