IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  WebSphere  >

WebSphere JCA Adapter 开发入门

一步步开发符合 JCA 规范的 WebSphere Adapter

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 中级

刘 冬清 (liudongq@cn.ibm.com), 工程师,中国软件实验室(CSDL BJ)

2007 年 6 月 28 日

IBM WebSphere JCA Adapter 是沟通 WebSphere Process Server 和 EIS 之间的桥梁,本文通过一个简单实例介绍了开发 WebSphere JCA Adapter 的基本步骤。

JCA (Java 2 Enterprise Edition (J2EE) Connector Architecture)是J2EE规范中重要的一环,为J2EE应用程序和其它企业信息系统(EIS)之间的交互制定了标准。IBM WebSphere Process Server(WPS)是构筑在J2EE之上的企业应用集成服务器,IBM WebSphere JCA Adapter就是配合WPS使用的,既符合JCA规范又支持WPS优秀集成特性的产品家族。目前最新的是6.0.2版,主要包括如下Adapter:

  • IBM WebSphere Adapter for JDBC
  • IBM WebSphere Adapter for Flat Files
  • IBM WebSphere Adapter for PeopleSoft Enterprise
  • IBM WebSphere Adapter for SAP Software
  • IBM WebSphere Adapter for Siebel Business Applications
  • IBM WebSphere Adapter for Email
  • IBM WebSphere Adapter for FTP
  • IBM WebSphere Adapter for JD Edwards EnterpriseOne
  • IBM WebSphere Adapter for Oracle E-Business Suite

IBM WebSphere JCA Adapter 架构

所需知识背景

本文假定读者熟悉J2EE,并对JCA规范有所了解。如果不熟悉JCA,最好先读一下JCA 1.5规范的以下章节:概述,包括1,2,3章;Outbound 相关,包括6,15章。

WebSphere Adapter使用Service Data Object(SDO)规范来表示数据,如果读者有SDO相关知识,将有助于理解相关内容。

IBM WebSphere JCA Adapter完全符合JCA 1.5规范。JCA Adapter规范规定了连接和操作EIS的协议,但是对所交换的数据规范没有指定。在WPS中,核心的数据规范是Business Object,简称BO。BO从技术实现的角度讲是Service Data Object(SDO),一种标准化的数据接口。WebSphere JCA Adapter使用SDO与WPS来交换数据。

连接不同的EIS的Adapters有很多共性,对每个Adapter都完全从实现JCA接口开始白手起家显然是没有必要的。因此,IBM开发了Adapter Foundation Classes作为WebSphere JCA Adapter的开发框架。它提供了JCA 接口的抽象实现,以及在Adapter之间可以重用的基本功能,并提供了Assured Event Delivery等QoS服务,而将与EIS密切相关的功能留给具体的Adapter来实现,从而大大简化了Adapter的开发工作。

下图表明WebSphere Adapter的基本架构:


图 1. Adapter的基本架构
Adapter的基本架构

从上图可以看出,Adapter Foundation Classes提供了JCA 1.5规范的框架实现,Adapter特有部分扩展并细化这一框架,实现对EIS的操作,并通过SDO规范与WPS交换数据。有了Adapter Foundation Classes,开发Adapter的工作量大为减少,只要实现上图中的蓝色部分,开发主要关注点为对不同EIS的操作。

古人云:绝知此事要躬行,以下本文将以一个连接虚拟的EIS(Mock EIS)的MockAdapter为例简要描述了如何基于WebSphere Adapter Foundation Classes 6.0.2 版,一步步开始开发符合WebSphere 框架的JCA Adapter。以此来更好的了解Adapter的工作原理。MockAdapter将只支持由J2EE应用程序发起的对EIS的操作(在JCA规范中称为Outbound操作)。

开发工具和Adapter Foundation Classes库文件

和WPS配套的开发工具是WebSphere Integration Developer(WID),它是基于Eclipse技术的企业应用集成开发环境。我们需要使用WID这个工具来开发WebSphere JCA Adapter。在WID 6.0.2的安装目录下,可以找到Resource Adapters目录,其中包括了所有可用的JCA Adapter。将某个Adapter,如FlatFile的RAR文件导入WID中,你会在connectModule目录下发现CWYBS_AdapterFoundation.jar,这就是Adapter Foundation Classes。





回页首


Mock EIS

为了简化,本文不使用任何现实的EIS,而是用一个Mock EIS 类来模拟一个EIS,这样的好处是你无需了解任何EIS API的调用,通常那是很复杂的。Mock EIS是一个二元计算服务,可以计算加减乘除。

使用Mock EIS的程序,首先要用setOperation()设置运算符,然后调用calculate()计算得出结果。


代码清单 1.MockEIS.java
                
package com.ibm.eis.mock; 

public class MockEIS {

  String operation = "+";
    
  public MockEIS(){
       
  }
  /**
   * @param operation The operation to set.
   */
  public void setOperation(String operation) {
    this.operation = operation;
  }
  
  /**
   * Calculate the result.
   * @param x
   * @param y
   * @return
   */
  public float calculate(float x, float y){
    float result = Float.NaN;
    if(operation.equals("+")){
      result = x + y;
    }else if(operation.equals("-")){
      result = x - y;
    }else if(operation.equals("*")){
      result = x * y;
    }else if(operation.equals("/")){
      result = x / y;
    }
    return result;
  }
}
      





回页首


先期准备:创建Business Object定义

由于SDO是一种需要预先定义数据格式的规范,并且使用XML Schema文件来描述数据格式,在WPS/WID中称为Business Object 定义。我们首先要确定EIS所需要处理的数据格式,并将它映射到一个适当的Business Object 定义。在Mock EIS中需要处理的数据包括运算数和结果,可以作为属性封装在一个BO中。

我们是用WID的BO编辑器来创建BO。首先创建一个新Business Object,命名为MockBO,为它添加X,Y,Result三个属性,然后为它生成一个Business Graph(BG),BG是SDO规范中规定的BO的包装器,用来纪录BO的变化和某些附加信息,可以看作是一种特殊的BO。在WebSphere Adapter中,接受和发送的数据对象都是以BG包装的BO。

创建完成的BO如下图所示:


图 2. MockBO 定义
MockBO 定义

BO的定义会保存为XML Schema文件,切换到资源透视图,可以在模块工程目录下找到MockBO.xsd和MockBOBG.xsd两个文件。





回页首


第一步:创建Connector Project

在WID中切换到J2EE perspective,创建一个Connector Project。注意要选择WebSphere Process Server 6.0作为该Project的server,然后,把Foundation Classes的Jar文件CWYBS_AdatperFoundation.jar导入到该project的connectorModule 目录下,并添加到build path中。接下来,将刚才创建的BO定义文件,即MockBO.xsd和MockBOBG.xsd复制到connectorModule,以便将来BO定义随Adapter一同部署。





回页首


第二步:创建Resource Adapter主类

用文本方式打开ra.xml文件,目前只有对MockAdapter的简单描述,将各项描述添全。

      <display-name>IBM Mock Adapter for QA</display-name>
      <vendor-name>IBM CSDL AIA</vendor-name>
      <eis-type>Mock EIS</eis-type>
      <resourceadapter-version>1.0.0</resourceadapter-version>

接着创建Mock Adapter的ResourceAdapter类,类名为com.ibm.j2ca.mock.MockAdapter,将此添加到ra.xml中。

       <resourceadapter>
          <resourceadapter-class>com.ibm.j2ca.mock.MockAdapter</resourceadapter-class>
          ......
       </resourceadapter>

通过继承WBIResourceAdapter类创建MockAdapter类。WBIResourceAdapter类在com.ibm.j2ca.base包中(大部分Adapter需要继承的基类都在这个包中,如不特别指出,以下文中提到的需要继承的类都属于这个包)。唯一必须实现的方法是getResourceAdapterMetadata,返回描述该Adapter的WBIResourceAdapterMetadata实例。注意,该类需要符合Java Bean规范,即必须有public无参数的缺省构造函数。


代码清单 2.MockAdapter.java
                
package com.ibm.j2ca.mock;

import javax.resource.ResourceException;
import com.ibm.j2ca.base.WBIResourceAdapter;
import com.ibm.j2ca.base.WBIResourceAdapterMetadata;

public class MockAdapter extends WBIResourceAdapter {
  public MockAdapter() 
    super();
  }
  public WBIResourceAdapterMetadata getResourceAdapterMetadata()
      throws ResourceException {
    return new WBIResourceAdapterMetadata(
            "IBM Mock Adapter", "IBM CSDL ", "1.0.0", false);
  }
}





回页首


第三步:实现对EIS的连接管理逻辑

WebSphere Adapter要连接EIS,必须实现JCA规范中的Connection管理逻辑。包括四个主要接口:Connection,ManagedConnection,ManagedConnectionFactory,ConnectionFactory

首先要确定的是连接特定的EIS需要的属性值,必需的属性要加在实现ManagedConnectionFactory接口的类里,如hostname,port,username,password之类。Mock EIS唯一需要设置的就是操作符Operation。因此Mock Adapter只需要一个ManagedConnectionFactory属性:Operation

各个接口的实现类以及ManagedConnectionFactory的属性需要在ra.xml里加以描述。在ra.xml <resourceadapter>标签下加上如下信息,来描述Adapter的outbound功能,指明各个接口的实现类名。

<outbound-resourceadapter>
    <connection-definition>
        <managedconnectionfactory-class>
             com.ibm.j2ca.mock.MockManagedConnectionFactory
        </managedconnectionfactory-class>
        <config-property>
            <config-property-name>Operation</config-property-name>
            <config-property-type>java.lang.String</config-property-type>
            <config-property-value></config-property-value>
        </config-property>
        <connectionfactory-interface>
            javax.resource.cci.ConnectionFactory
        </connectionfactory-interface>
        <connectionfactory-impl-class>
            com.ibm.j2ca.mock.MockConnectionFactory
        </connectionfactory-impl-class>
        <connection-interface>javax.resource.cci.Connection</connection-interface>
        <connection-impl-class>com.ibm.j2ca.mock.MockConnection</connection-impl-class>
    </connection-definition>
    <transaction-support>NoTransaction</transaction-support>
    <reauthentication-support>false</reauthentication-support>
</outbound-resourceadapter>

接着分别实现这四个接口:

Connection:Foudation Classes提供了Connection接口的抽象实现WBIConnection,MockConnection继承并该类。唯一必须实现的方法是createInteraction,提供outbound操作需要的Interaction接口的实现MockInteraction(将在下一步中描述)。


代码清单 3.MockConnection.java
                
package com.ibm.j2ca.mock; 

import javax.resource.ResourceException;
import javax.resource.cci.Interaction;
import com.ibm.j2ca.base.WBIConnection;
import com.ibm.j2ca.base.WBIManagedConnection;

public class MockConnection extends WBIConnection {
  public MockConnection(WBIManagedConnection mc) throws ResourceException {
    super(mc);
  }

  public Interaction createInteraction() throws ResourceException {
    return new MockInteraction(this);
  }
}

ManagedConnection:对EIS真正的连接通过实现ManagedConnection接口完成。Foundation Classe提供了抽象实现WBIManagedConnection。Mock Adapter要继承WBIManagedConnection并完成对EIS连接的操作,如创建和关闭连接。MockManagedConnection所要做的是创建一个MockEIS对象来代表一个连接。需要实现的方法有:

  • getMetaData方法返回关于EIS的一些信息。
  • getWBIConnection方法,进行认证并返回一个对应的JCA Connection对象,这里将是MockConnection。
  • destory方法,释放对EIS的连接。
  • getMockEIS方法,使得Adapter其他部分可以访问EIS。

代码清单 4.MockManagedConnection.java
                
package com.ibm.j2ca.mock;

import javax.resource.ResourceException;
import javax.resource.spi.ManagedConnectionMetaData;
import javax.resource.spi.security.PasswordCredential;
import javax.security.auth.Subject;

import com.ibm.eis.mock.MockEIS;
import com.ibm.j2ca.base.WBIConnectionRequestInfo;
import com.ibm.j2ca.base.WBIManagedConnection;
import com.ibm.j2ca.base.WBIManagedConnectionFactory;
import com.ibm.j2ca.base.WBIManagedConnectionMetaData;

/**
 * @author Donny
 *
 */
public class MockManagedConnection extends WBIManagedConnection {
  
  private MockEIS mockEIS ;

  public MockManagedConnection(WBIManagedConnectionFactory factory,
        Subject sub, WBIConnectionRequestInfo request,MockEIS eis)
        throws ResourceException {
    super(factory, sub, request);
    mockEIS = eis;
  }

  public ManagedConnectionMetaData getMetaData() throws ResourceException {
    return new WBIManagedConnectionMetaData("Mock EIS",
          "1.0.0",10,super.getPasswordCredential().getUserName());
  }

  public Object getWBIConnection(PasswordCredential arg0, boolean arg1)
        throws ResourceException {
    return new MockConnection(this);
  }

  public void destroy() throws ResourceException {

  }
  public MockEIS getMockEIS() {
    return mockEIS;
  }  
}

ManagedConnectionFactory:J2EE容器通过ManagedConnectionFactory来创建ManagedConnection。AFC提供了ManagedConnectionFactory的抽象实现WBIManangedConnectionFactory。MockManagedConnectionFactory只需要继承这个类,实现特定的属性,在这里就是Operation。同时要实现方法createConnectionFactory供J2EE服务器取得ConnectionFactory的实例,这里将是MockConnectionFactory对象;最重要的是要实现createManagedConnection返回MangedConnection对象。还必须实现在前面确定并在ra.xml文件里制定的属性所对应的get和set方法,这里即getOperation和setOperation。MockManagedConnectionFactory根据Operation属性值构造一个MockEIS实例,并由此实例构造出MockMangedConnection的一个实例。

MockManagedConnectionFactory实现如下,注意必须提供缺省构造函数使其满足Java Bean规范要求:


代码清单 5.MockManagedConnectionFactory.java
                 
package com.ibm.j2ca.mock;

import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnection;
import javax.security.auth.Subject;

import com.ibm.j2ca.base.WBIConnectionRequestInfo;
import com.ibm.j2ca.base.WBIManagedConnectionFactory;

public class MockManagedConnectionFactory extends WBIManagedConnectionFactory {
    private String operation = "+";
  public MockManagedConnectionFactory() {
    super();
  }

  public ManagedConnection createManagedConnection(Subject sub,
      ConnectionRequestInfo info) throws ResourceException {
    //“连接” Mock EIS,创建对MockManagedConnection 
    MockEIS eis = new MockEIS();
    eis.setOperation(this.operation);
    return new MockManagedConnection(this, sub, (WBIConnectionRequestInfo) info,eis);
  }
  
  public Object createConnectionFactory(ConnectionManager arg0)
      throws ResourceException {
    return new MockConnectionFactory(arg0,this);
  }
  public String getOperation(){
      return operation;
  }
  public void setOperation(String operation){
    this.operation = operation;
  }
}

MockConnectionFactory:MockConnectionFactory需继承WBIConnectionFactory,该类已经实现了基本逻辑,子类只要实现构造函数即可。


代码清单 6.MockConnectionFactory.java
                
package com.ibm.j2ca.mock;

import javax.resource.spi.ConnectionManager;
import com.ibm.j2ca.base.WBIConnectionFactory;
import com.ibm.j2ca.base.WBIManagedConnectionFactory;

public class MockConnectionFactory extends WBIConnectionFactory {
  public MockConnectionFactory(ConnectionManager cm,
       WBIManagedConnectionFactory factory){
    super(cm, factory);
  }
}

到这里,连接管理的逻辑已经全部实现。





回页首


第四步:实现Interaction接口以支持outbound操作

为支持outbound操作,必须实现Interaction接口,如上一步所示,Interaction对象由MockConnection创建。Foundation Classes提供了抽象实现WBIInteraction。继承该类需要实现的唯一方法是execute,在其中根据传入的参数实现对EIS的操作。

为符合Websphere Adapter的标准,Record execute(InteractionSpec ixSpec,Record in) 函数的传入参数有相应的限制,ixSpec应当是 WBIInteractionSpec的实例,in应该是DataObjectRecord的实例。DataObjectRecord包含了一个SDO规范所定义的DataObject,即BO。

MockAdatper非常简单的实现了execute方法,分析输入的BO,取出操作数,交给MockEIS进行计算后返回一份BO副本。

如何操作BO

WPS提供了BO操作的各种服务,比如创建,复制等等。Foundation Classes将这些服务封装在com.ibm.j2ca.base.AdapterBOUtil工具类中以方便调用。


代码清单 7.MockInteraction.java
                
package com.ibm.j2ca.mock;

import javax.resource.ResourceException;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;

import com.ibm.eis.mock.MockEIS;
import com.ibm.j2ca.base.AdapterBOUtil;
import com.ibm.j2ca.base.DataObjectRecord;
import com.ibm.j2ca.base.WBIConnection;
import com.ibm.j2ca.base.WBIInteraction;
import com.ibm.j2ca.base.WBIInteractionSpec;
import commonj.sdo.DataObject;

public class MockInteraction extends WBIInteraction {

  public MockInteraction(WBIConnection arg0) {
    super(arg0);
  }

  public Record execute(InteractionSpec ixSpec, Record record)
      throws ResourceException {
    if(!(ixSpec instanceof WBIInteractionSpec)){
      throw new ResourceException("Unknown InteractionSpec type!");
    }
    if(!(record instanceof DataObjectRecord)){
      throw new ResourceException("Invalid Record type!");
    }
    //1. 分析输入的BO,得到运算数
    DataObject bg = ((DataObjectRecord)record).getDataObject();
    DataObject mockBO = bg.getDataObject("MockBO");
    float x = mockBO.getFloat("X");
    float y = mockBO.getFloat("Y");
    //2. 通过相应的连接,得到Mock EIS服务,并计算结果
    MockManagedConnection mcon = (MockManagedConnection)(
        (WBIConnection)this.getConnection()).getManagedConnection();
    MockEIS eis = mcon.getMockEIS();
    float result = eis.calculate(x,y);
    
    //3. 创建输出Record
    DataObject outputBG = AdapterBOUtil.copyBusinessObject(bg);
    outputBG.getDataObject("MockBO").setFloat("Result",result);
    DataObjectRecord outputRecord = new DataObjectRecord();
    outputRecord.setDataObject(outputBG);
    outputRecord.setRecordName(record.getRecordName());
    return outputRecord;
  }
}

到这里,Adapter对Outbound的支持已经完全实现,可以部署运行了。





回页首


测试:CCI 方式调用Adapter

为了在WPS上部署运行Adapter,需要将Adapter打包。首先,用wid的export功能,将Adapter所有类文件打包成为一个jar文件,比如MockAdapter.jar,并将该文件保存在工程的connectorModule目录下,这样可以在WID的集成测试环境中成功部署。

必须要有应用程序来调用Adapter,可以是jsp,ejb等。这里我们创建一个动态Web工程,使用jsp来做测试。根据J2EE的规范,还需要创建EAR工程,将Adapter工程和Web工程都包括进去。

调用Adapter很简单,首先通过JNDI查找获取ConnectionFactory实例以创建连接;然后调用Interaction的execute方法执行操作;最后关闭连接即可。


代码清单 8.MockTest.jsp
                
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ page import="com.ibm.j2ca.base.*"%> 
<%@ page import="commonj.sdo.*"%> 
<%@ page import="javax.resource.cci.*"%>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META name="GENERATOR" content="IBM Software Development Platform">
<TITLE>MockTest.jsp</TITLE>
</HEAD>
<BODY>
<%  
  try{
    //Step 1: 获取连接
    //  1.1: 通过JNDI查找ConnetionFactory
    javax.naming.InitialContext initCx = new javax.naming.InitialContext();
    String jndi = "Mock/Mock_Multi";
    ConnectionFactory cxf = (ConnectionFactory) initCx.lookup(jndi);
    
    //  1.2: 创建连接
    Connection connection = null ;
    connection = cxf.getConnection();

    //Step 2: 执行操作
    //  2.1: 创建Interaction
    Interaction interaction = null;
    interaction = connection.createInteraction();
    
    //  2.2: 准备InteractionSpec
    WBIInteractionSpec interactionSpec = new WBIInteractionSpec();
    //  2.3: 准备BO,必须以BG为包装器
    DataObject inputObject = null;
    inputObject = AdapterBOUtil
        .createDataObject(
            "http://MockTest",
            "MockBOBG");
    DataObject bo = inputObject.createDataObject("MockBO");
    bo.set("X", "1.01");
    bo.set("Y", "3.21");

    //  2.4: 准备Record
    DataObjectRecord inputRecord = new DataObjectRecord();
    inputRecord.setDataObject(inputObject);
    //  2.5: 调用执行方法
    Record outputRecord = interaction.execute(interactionSpec,
        inputRecord);
    //  2.6: 获取返回值并输出
    DataObject outputObject = ((DataObjectRecord) outputRecord)
        .getDataObject();
    out.println(AdapterBOUtil.serializeDataObject(outputObject));
    //Step 3: 关闭连接
    connection.close();
  } catch (Exception e) {
    e.printStackTrace();
  }
%></BODY>
</HTML>

以上代码中,第一步引用了JNDI名字Mock/Mock_Multi,需要在ear部署后手工创建。首先启动WID的集成测试服务器,将ear工程添加到服务器上。接着通过WPS的管理控制台,找到相应的企业应用程序,为其建立J2C连接工厂,将其JNDI设为Mock/Mock_Multi,并且定制其属性opertaion为“*”(即乘法)。


图 3. 定义J2C连接工厂
定义J2C连接工厂

然后可以通过浏览器来执行index.jsp。如果完全按照如上设置,将得到以下输出:


图 4. 输出结果
输出结果




回页首


总结及展望

以上我们实现了MockAdapter的连接管理和Outbound操作功能。WebSphere JCA Adapter还有很多其它需要考虑的特性,比如事务的管理,Inbound通讯等。Foundation Classes也有很多其他功能,如Command管理框架,统一的日志功能等。这些本文都没有触及。实际可用的Adapter无疑要复杂的多,但是基本的实现步骤是大体相同的。



参考资料

学习

获得产品和技术


关于作者

刘冬清是中国软件实验室(CSDL BJ)的工程师,加入IBM以来一直从事Websphere Business Integration相关软件的开发和测试工作。可以通过电子邮件:liudongq@cn.ibm.com来联系他。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款