データ・アクセス API に対する拡張機能

シングル・データ・アクセス API により、ご使用のアプリケ ーションに完全なソリューションが提供されない場合、WebSphere® Application Server 拡張機能を使用し、JCA と JDBC API の間のインターオ ペラビリティーを実現してください。

多様で複雑なリソース管理構成からもたらされたアプリケーションで は、Java™ Platform, Enterprise Edition (Java EE) コネクター・アーキテクチャー (JCA) API と Java Database Connectivity (JDBC) API の両方を使用することが必要です。しかし、JDBC プ ログラミング・モデルは (完全な統合が JCA 仕様の基盤であっても) JCA と 完全に統合しないことがあります。 これらの矛盾によって、両方の API を使用するアプリケーションはデータ・アクセス・オプションを制限されることになります。 WebSphere Application Server は、その互換性問題を解決するために、API 拡張機能を提供します。

以下に例を示します。

拡張機能の利点なしでは、他のハンドルがその接続に存在している場合、 両方の API を使用しているアプリケーションは、接続要求を出した後、 共有可能な接続のプロパティーを変更することができません。(他のハンドルがその接続と関連していない場合、 接続プロパティーは変更することができます。) この制限は、API の接続ポリシーと構成ポリシー間の非互換性によるものです。

コネクター・アーキテクチャー (JCA) 仕様では、 接続を要求する時点で (getConnection() メソッドを使用して)、 ConnectionSpec オブジェクトを渡すことにより、 特定のプロパティーを設定すべきかをリソース・アダプターに伝えることができます。 ConnectionSpec オブジェクトには、接続を取得する際に必要な接続プロパティーが含まれています。 この環境から接続を取得した後は、 アプリケーションがプロパティーを変更する必要はなくなります。ただし、JDBC プログラミング・モデルには、 接続プロパティーを指定するための同じインターフェースがありません。 代わりに、このモデルは、まず接続を取得してから、接続でプロパティーを設定します。

JDBC および JCA 仕様の間のこのようなギャップを埋めるため、 WebSphere Application Server には以下の拡張機能が用意されています。

例: データベース接続のための IBM 拡張 API の使用

WSDataSource 拡張 API を使用して、接続を取得する前に、JDBC アプリケーションをコード化し、オブジェクトを介して接続プロパ ティーを定義することができます。この性質により、アプリケーションが CMP などの別のコンポ ーネントと接続を共有する可能性が高まります。

トランザクション内の他のコンテナー管理パーシスタンス (CMP) Bean と共有できる共有可能接続を用いて、アプリケーションを実行する場合、 WebSphere Application Server 拡張 API を使用して接続を取得することをお勧めします。 この API を使用すると、 アプリケーションを他のアプリケーション・サーバーに移植できません。

JDBC アプリケーションで拡張 API を使用して直接コード化することができ ます。接続を取得するのに DataSource インターフェースを使用するのでは なく、WSDataSource インターフェースを使用してください。以下のコード・セグメントは、 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);

例: CMP Bean と BMP Bean 間の接続を共有するための IBM 拡張 API の使用

JDBC オブジェクト (Bean 管理パーシスタンス (BMP) Bean など) を 介してデータにアクセスするアプリケーション・コンポーネント内で、接続を取得する前に、WebSphere 拡張 API を使用し、オブジ ェクトを介して接続プロパティーを定義することができます。この性質により、BMP Bean が コンテナー 管理パーシスタンス (CMP) Bean と接続を共有する可能性が高まります。

トランザクション内の他のコンテナー管理パーシスタンス (CMP) Bean と 共有できる共有可能接続を用いて BMP Bean を実行する場合、WebSphere Application Server 拡張 API を使用して接続を取得する ことをお勧めします。 この API を使用すると、 アプリケーションを他のアプリケーション・サーバーに移植できません。

この場合、DataSource インターフェースではなく、拡張 API WSDataSource インターフェースを使用してください。CMP Bean と BMP Bean の両方が同じ物理接続を必ず共有できるようにするために、両 者において同じアクセス・インテント・プロファイルを定義してください。 BMP メソッド内部で、リレーショナル・リソース・アダプターの helper クラスから、正しい分離レベルを取得できます。

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

トピックのタイプを示すアイコン 参照トピック



タイム・スタンプ・アイコン 最終更新: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rdat_cextiapi
ファイル名:rdat_cextiapi.html