32. JCA CCI

32.1 简介

Java EE 提供了一个规范来标准化对企业信息系统(EIS)的访问:JCA(Java EE Connector Architecture)。该规范分为几个不同的部分:

  • 连接器提供程序必须实现的 SPI(服务提供程序接口)。这些接口构成可以部署在 Java EE application 服务器上的资源适配器。在这种情况下,服务器管理连接池,transaction 和安全性(托管模式)。 application 服务器还负责管理 configuration,它位于 client application 之外。连接器也可以在没有 application 服务器的情况下使用;在这种情况下,application 必须直接配置它(non-managed 模式)。

  • CCI(Common Client Interface), application 可以用来与连接器交互,从而与 EIS 通信。还提供了用于本地 transaction 划分的 API。

Spring CCI 支持的目的是提供 classes 以典型的 Spring 风格访问 CCI 连接器,利用 Spring Framework 的一般资源和 transaction management 工具。

连接器的 client 端并不总是使用 CCI。某些连接器公开自己的 API,仅提供 JCA 资源适配器以使用 Java EE 容器的系统 contracts(连接池,global transactions,security)。 Spring 不为此类 connector-specific API 提供特殊支持。

32.2 配置 CCI

32.2.1 连接器配置

使用 JCA CCI 的基本资源是ConnectionFactory接口。使用的连接器必须提供此接口的 implementation。

要使用连接器,可以将其部署在 application 服务器上,并从服务器的 JNDI 环境(托管模式)获取ConnectionFactory。必须将连接器打包为 RAR 文件(资源适配器归档文件),并包含ra.xml文件以描述其部署特征。部署资源时指定资源的实际 name。要在 Spring 中访问它,只需使用 Spring 的JndiObjectFactoryBean/<jee:jndi-lookup>通过其 JNDI name 获取工厂。

使用连接器的另一种方法是将其嵌入到 application(non-managed 模式)中,而不是使用 application 服务器来部署和配置它。 Spring 提供了通过提供的FactoryBean(LocalConnectionFactoryBean)将连接器配置为 bean 的可能性。通过这种方式,您只需要 classpath 中的连接器 library(不需要 RAR 文件,也不需要ra.xml描述符)。如有必要,必须从连接器的 RAR 文件中提取 library。

一旦您有权访问ConnectionFactory实例,就可以将其注入组件中。这些组件可以针对普通 CCI API 进行编码,也可以利用 Spring 的支持 classes 进行 CCI 访问(e.g. CciTemplate)。

在 non-managed 模式下使用连接器时,不能使用 global transactions,因为在当前线程的当前 global transaction 中,资源永远不会被列入/退出。资源根本不知道可能正在运行的任何 global Java EE transactions。

_Sp中的 32.2.2 ConnectionFactory configuration

在 order 中建立与 EIS 的连接,如果您处于托管模式,则需要从 application 服务器获取ConnectionFactory,如果您处于 non-managed 模式,则需要直接从 Spring 获取ConnectionFactory

在托管模式下,您可以从 JNDI 访问ConnectionFactory;它的 properties 将在 application 服务器中配置。

<jee:jndi-lookup id="eciConnectionFactory" jndi-name="eis/cicseci"/>

在 non-managed 模式下,必须将要在 Spring 的 configuration 中使用的ConnectionFactory配置为 JavaBean。 LocalConnectionFactoryBean class 提供此设置样式,传递连接器的ManagedConnectionFactory implementation,显示 application-level CCI ConnectionFactory

<bean id="eciManagedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
    <property name="serverName" value="TXSERIES"/>
    <property name="connectionURL" value="tcp://localhost/"/>
    <property name="portNumber" value="2006"/>
</bean>

<bean id="eciConnectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
    <property name="managedConnectionFactory" ref="eciManagedConnectionFactory"/>
</bean>

您不能直接实例化特定的ConnectionFactory。您需要为连接器完成ManagedConnectionFactory接口的相应 implementation。该接口是 JCA SPI 规范的一部分。

32.2.3 配置 CCI 连接

JCA CCI 允许开发人员使用连接器的ConnectionSpec implementation 配置与 EIS 的连接。在 order 中配置其 properties,您需要使用专用适配器ConnectionSpecConnectionFactoryAdapter包装目标连接工厂。因此,可以使用 property connectionSpec(作为内部 bean)配置专用ConnectionSpec

此 property 不是必需的,因为 CCI ConnectionFactory接口定义了两种不同的方法来获取 CCI 连接。某些ConnectionSpec properties 通常可以在 application 服务器(在托管模式下)或相应的本地ManagedConnectionFactory implementation 中配置。

public interface ConnectionFactory implements Serializable, Referenceable {
    ...
    Connection getConnection() throws ResourceException;
    Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException;
    ...
}

Spring 提供ConnectionSpecConnectionFactoryAdapter,允许指定ConnectionSpec实例以用于给定工厂的所有操作。如果指定了适配器的connectionSpec property,则适配器将getConnection变量与ConnectionSpec参数一起使用,否则变量不带参数。

<bean id="managedConnectionFactory"
        class="com.sun.connector.cciblackbox.CciLocalTxManagedConnectionFactory">
    <property name="connectionURL" value="jdbc:hsqldb:hsql://localhost:9001"/>
    <property name="driverName" value="org.hsqldb.jdbcDriver"/>
</bean>

<bean id="targetConnectionFactory"
        class="org.springframework.jca.support.LocalConnectionFactoryBean">
    <property name="managedConnectionFactory" ref="managedConnectionFactory"/>
</bean>

<bean id="connectionFactory"
        class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter">
    <property name="targetConnectionFactory" ref="targetConnectionFactory"/>
    <property name="connectionSpec">
        <bean class="com.sun.connector.cciblackbox.CciConnectionSpec">
            <property name="user" value="sa"/>
            <property name="password" value=""/>
        </bean>
    </property>
</bean>

32.2.4 使用单个 CCI 连接

如果要使用单个 CCI 连接,Spring 会提供另一个ConnectionFactory适配器来管理它。 adapter class 将懒惰地打开一个连接,并在 application shutdown 时销毁 bean 时将其关闭。这个 class 将公开相应行为的特殊Connection代理,它们共享相同的底层物理连接。

<bean id="eciManagedConnectionFactory"
        class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
    <property name="serverName" value="TEST"/>
    <property name="connectionURL" value="tcp://localhost/"/>
    <property name="portNumber" value="2006"/>
</bean>

<bean id="targetEciConnectionFactory"
        class="org.springframework.jca.support.LocalConnectionFactoryBean">
    <property name="managedConnectionFactory" ref="eciManagedConnectionFactory"/>
</bean>

<bean id="eciConnectionFactory"
        class="org.springframework.jca.cci.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory" ref="targetEciConnectionFactory"/>
</bean>

ConnectionFactory适配器无法直接配置ConnectionSpec。如果您需要针对特定ConnectionSpec的单个连接,请使用SingleConnectionFactory与之对话的中介ConnectionSpecConnectionFactoryAdapter

32.3 使用 Spring 的 CCI 访问支持

32.3.1 记录转换

JCA CCI 支持的目标之一是为操作 CCI 记录提供便利的设施。开发人员可以指定策略来创建记录并从记录中提取数据,以便与 Spring 的CciTemplate一起使用。如果您不想直接在 application 中使用记录,以下接口将配置策略以使用输入和输出记录。

在 order 中创建输入Record,开发人员可以使用RecordCreator接口的专用 implementation。

public interface RecordCreator {

    Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException;

}

如您所见,createRecord(..)方法接收RecordFactory实例作为参数,该参数对应于ConnectionFactoryRecordFactory。此 reference 可用于创建IndexedRecordMappedRecord实例。以下 sample 显示了如何使用RecordCreator接口和 indexed/mapped 记录。

public class MyRecordCreator implements RecordCreator {

    public Record createRecord(RecordFactory recordFactory) throws ResourceException {
        IndexedRecord input = recordFactory.createIndexedRecord("input");
        input.add(new Integer(id));
        return input;
    }

}

输出Record可用于从 EIS 接收数据。因此,可以将RecordExtractor接口的特定 implementation 传递给 Spring 的CciTemplate,以便从输出Record中提取数据。

public interface RecordExtractor {

    Object extractData(Record record) throws ResourceException, SQLException, DataAccessException;

}

以下 sample 显示了如何使用RecordExtractor接口。

public class MyRecordExtractor implements RecordExtractor {

    public Object extractData(Record record) throws ResourceException {
        CommAreaRecord commAreaRecord = (CommAreaRecord) record;
        String str = new String(commAreaRecord.toByteArray());
        String field1 = string.substring(0,6);
        String field2 = string.substring(6,1);
        return new OutputObject(Long.parseLong(field1), field2);
    }

}

32.3.2 CciTemplate

CciTemplate是核心 CCI 支持包(org.springframework.jca.cci.core)的核心 class。它简化了 CCI 的使用,因为它处理资源的创建和释放。这有助于避免 common 错误,例如忘记始终关闭连接。它关注连接和交互 objects 的生命周期,让 application code 专注于从 application 数据生成输入记录并从输出记录中提取 application 数据。

JCA CCI 规范定义了两种不同的方法来调用 EIS 上的操作。 CCI Interaction接口提供两个执行方法签名:

public interface javax.resource.cci.Interaction {

    ...

    boolean execute(InteractionSpec spec, Record input, Record output) throws ResourceException;

    Record execute(InteractionSpec spec, Record input) throws ResourceException;

    ...

}

根据调用的模板方法,CciTemplate将知道要在交互上调用哪个execute方法。无论如何,正确初始化的InteractionSpec实例是必需的。

CciTemplate.execute(..)可以通过两种方式使用:

  • 直接使用Record arguments。在这种情况下,您只需要传入 CCI 输入 record,返回的 object 就是相应的 CCI 输出 record。

  • 使用 application objects,使用 record 映射。在这种情况下,您需要提供相应的RecordCreatorRecordExtractor实例。

使用第一种方法,将使用模板的以下方法。这些方法直接对应于Interaction接口上的方法。

public class CciTemplate implements CciOperations {

    public Record execute(InteractionSpec spec, Record inputRecord)
            throws DataAccessException { ... }

    public void execute(InteractionSpec spec, Record inputRecord, Record outputRecord)
            throws DataAccessException { ... }

}

使用第二种方法,我们需要将 record 创建和 record 提取策略指定为 arguments。使用的接口是上一节中关于 record 转换的描述。相应的CciTemplate方法如下:

public class CciTemplate implements CciOperations {

    public Record execute(InteractionSpec spec,
            RecordCreator inputCreator) throws DataAccessException {
        // ...
    }

    public Object execute(InteractionSpec spec, Record inputRecord,
            RecordExtractor outputExtractor) throws DataAccessException {
        // ...
    }

    public Object execute(InteractionSpec spec, RecordCreator creator,
            RecordExtractor extractor) throws DataAccessException {
        // ...
    }

}

除非在模板上设置了outputRecordCreator property(参见下一节),否则每个方法都会使用两个参数调用 CCI Interaction的相应execute方法:InteractionSpec并输入Record,接收输出Record作为 return value。

CciTemplate还提供了通过createIndexRecord(..)createMappedRecord(..)方法在RecordCreator implementation 之外创建IndexRecordMappedRecord的方法。这可以在 DAO implementations 中使用,以创建Record实例以传递到相应的CciTemplate.execute(..)方法。

public class CciTemplate implements CciOperations {

    public IndexedRecord createIndexedRecord(String name) throws DataAccessException { ... }

    public MappedRecord createMappedRecord(String name) throws DataAccessException { ... }

}

32.3.3 DAO 支持

Spring 的 CCI 支持为 DAO 提供了一个抽象 class,支持注入ConnectionFactoryCciTemplate实例。 class 的 name 是CciDaoSupport:它提供简单的setConnectionFactorysetCciTemplate方法。在内部,这个 class 将为 passed-in ConnectionFactory创建一个CciTemplate实例,将其暴露给子类中的具体数据访问 implementations。

public abstract class CciDaoSupport {

    public void setConnectionFactory(ConnectionFactory connectionFactory) {
        // ...
    }

    public ConnectionFactory getConnectionFactory() {
        // ...
    }

    public void setCciTemplate(CciTemplate cciTemplate) {
        // ...
    }

    public CciTemplate getCciTemplate() {
        // ...
    }

}

32.3.4 自动输出记录生成

如果使用的连接器仅支持带有输入和输出记录作为参数的Interaction.execute(..)方法(也就是说,它需要传入所需的输出 record 而不是返回适当的输出 record),则可以将CciTemplateoutputRecordCreator property 设置为自动生成一个输出 record,在收到响应时由 JCA 连接器填充。然后,此 record 将返回给模板的调用者。

此 property 只保存RecordCreator接口的 implementation,用于此目的。 RecordCreator接口已在第 32.3.1 节,“记录转换”中讨论过。必须在CciTemplate上直接指定outputRecordCreator property。这可以在 application code 中完成,如下所示:

cciTemplate.setOutputRecordCreator(new EciOutputRecordCreator());

或者(推荐)在 Spring configuration 中,如果CciTemplate配置为专用的 bean 实例:

<bean id="eciOutputRecordCreator" class="eci.EciOutputRecordCreator"/>

<bean id="cciTemplate" class="org.springframework.jca.cci.core.CciTemplate">
    <property name="connectionFactory" ref="eciConnectionFactory"/>
    <property name="outputRecordCreator" ref="eciOutputRecordCreator"/>
</bean>

由于CciTemplate class 是 thread-safe,因此通常将其配置为共享实例。

32.3.5 摘要

以下 table 总结了CciTemplate class 的机制以及在 CCI Interaction接口上调用的相应方法:

表格 1_.使用交互执行方法

CciTemplate 方法签名CciTemplate outputRecordCreator property在 CCI Interaction 上调用的 execute 方法
Record execute(InteractionSpec,Record)没有设置Record execute(InteractionSpec,Record)
Record execute(InteractionSpec,Record)boolean execute(InteractionSpec, RECord,Record)
void execute(InteractionSpec,Record,Record)没有设置void execute(InteractionSpec,Record,Record)
void execute(InteractionSpec,Record,Record)void execute(InteractionSpec,Record,Record)
Record execute(InteractionSpec,RecordCreator)没有设置Record execute(InteractionSpec,Record)
Record execute(InteractionSpec,RecordCreator)void execute(InteractionSpec,Record,Record)
Record execute(InteractionSpec, RECord,RecordExtractor)没有设置Record execute(InteractionSpec,Record)
Record execute(InteractionSpec, RECord,RecordExtractor)void execute(InteractionSpec,Record,Record)
Record execute(InteractionSpec,RecordCreator,RecordExtractor)没有设置Record execute(InteractionSpec,Record)
Record execute(InteractionSpec,RecordCreator,RecordExtractor)void execute(InteractionSpec,Record,Record)

32.3.6 直接使用 CCI 连接和交互

CciTemplate还提供了直接使用 CCI 连接和交互的可能性,其方式与JdbcTemplateJmsTemplate相同。如果要对 CCI 连接或交互执行多个操作,这对于 example 非常有用。

接口ConnectionCallback提供 CCI Connection作为参数,在 order 中对其执行自定义操作,加上创建Connection的 CCI ConnectionFactory。对于 example,后者可用于 example 以获取关联的RecordFactory实例并创建 indexed/mapped 记录。

public interface ConnectionCallback {

    Object doInConnection(Connection connection, ConnectionFactory connectionFactory)
            throws ResourceException, SQLException, DataAccessException;

}

接口InteractionCallback在 order 中提供 CCI Interaction以对其执行自定义操作,以及相应的 CCI ConnectionFactory

public interface InteractionCallback {

    Object doInInteraction(Interaction interaction, ConnectionFactory connectionFactory)
        throws ResourceException, SQLException, DataAccessException;

}

InteractionSpec objects 可以在多个模板 calls 之间共享,也可以在每个回调方法中新创建。这完全取决于 DAO implementation。

32.3.7 _ CciTemplate 用法示例

在本节中,将显示CciTemplate的使用情况,以使用 IBM CICS ECI 连接器访问具有 ECI 模式的 CICS。

首先,必须对 CCI InteractionSpec进行一些初始化,以指定要访问的 CICS 程序以及如何与之交互。

ECIInteractionSpec interactionSpec = new ECIInteractionSpec();
interactionSpec.setFunctionName("MYPROG");
interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);

然后程序可以通过 Spring 的模板使用 CCI,并指定自定义 objects 和 CCI Records之间的映射。

public class MyDaoImpl extends CciDaoSupport implements MyDao {

    public OutputObject getData(InputObject input) {
        ECIInteractionSpec interactionSpec = ...;

    OutputObject output = (ObjectOutput) getCciTemplate().execute(interactionSpec,
        new RecordCreator() {
            public Record createRecord(RecordFactory recordFactory) throws ResourceException {
                return new CommAreaRecord(input.toString().getBytes());
            }
        },
        new RecordExtractor() {
            public Object extractData(Record record) throws ResourceException {
                CommAreaRecord commAreaRecord = (CommAreaRecord)record;
                String str = new String(commAreaRecord.toByteArray());
                String field1 = string.substring(0,6);
                String field2 = string.substring(6,1);
                return new OutputObject(Long.parseLong(field1), field2);
            }
        });

        return output;
    }
}

如前所述,回调可用于直接在 CCI 连接或交互上工作。

public class MyDaoImpl extends CciDaoSupport implements MyDao {

    public OutputObject getData(InputObject input) {
        ObjectOutput output = (ObjectOutput) getCciTemplate().execute(
            new ConnectionCallback() {
                public Object doInConnection(Connection connection,
                        ConnectionFactory factory) throws ResourceException {

                    // do something...

                }
            });
        }
        return output;
    }

}

使用ConnectionCallback时,Connection将使用Connection来管理和关闭,但是在连接上创建的任何交互都必须由回调 implementation 管理。

对于更具体的回调,您可以实现InteractionCallback。在这种情况下,passed-in Interaction将由CciTemplate管理和关闭。

public class MyDaoImpl extends CciDaoSupport implements MyDao {

    public String getData(String input) {
        ECIInteractionSpec interactionSpec = ...;
        String output = (String) getCciTemplate().execute(interactionSpec,
            new InteractionCallback() {
                public Object doInInteraction(Interaction interaction,
                        ConnectionFactory factory) throws ResourceException {
                    Record input = new CommAreaRecord(inputString.getBytes());
                    Record output = new CommAreaRecord();
                    interaction.execute(holder.getInteractionSpec(), input, output);
                    return new String(output.toByteArray());
                }
            });
        return output;
    }

}

对于上面的示例,所涉及的 Spring beans 的相应 configuration 在 non-managed 模式下可能如下所示:

<bean id="managedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
    <property name="serverName" value="TXSERIES"/>
    <property name="connectionURL" value="local:"/>
    <property name="userName" value="CICSUSER"/>
    <property name="password" value="CICS"/>
</bean>

<bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
    <property name="managedConnectionFactory" ref="managedConnectionFactory"/>
</bean>

<bean id="component" class="mypackage.MyDaoImpl">
    <property name="connectionFactory" ref="connectionFactory"/>
</bean>

在托管模式下(即在 Java EE 环境中),configuration 可能如下所示:

<jee:jndi-lookup id="connectionFactory" jndi-name="eis/cicseci"/>

<bean id="component" class="MyDaoImpl">
    <property name="connectionFactory" ref="connectionFactory"/>
</bean>

32.4 将 CCI 访问建模为操作 objects

org.springframework.jca.cci.object包中包含支持 classes,允许您以不同的方式访问 EIS:通过可重用的操作 objects,类似于 Spring 的 JDBC 操作 objects(参见 JDBC 章节)。这通常会封装 CCI API:application-level 输入 object 将传递给操作 object,因此它可以构造输入 record,然后将接收到的 record 数据转换为 application-level 输出 object 并 return 它。

这种方法在内部基于CciTemplate class 和RecordCreator/RecordExtractor接口,重用了 Spring 核心 CCI 支持的机制。

32.4.1 MappingRecordOperation

MappingRecordOperation基本上执行与CciTemplate相同的工作,但是将 pre-configured 操作表示为 object。它提供了两个模板方法来指定如何将输入 object 转换为输入 record,以及如何将输出 record 转换为输出 object(record mapping):

  • createInputRecord(..)指定如何将输入 object 转换为输入Record

  • extractOutputData(..)指定如何从输出中提取输出 object Record

以下是这些方法的签名:

public abstract class MappingRecordOperation extends EisOperation {

    ...

    protected abstract Record createInputRecord(RecordFactory recordFactory,
            Object inputObject) throws ResourceException, DataAccessException {
        // ...
    }

    protected abstract Object extractOutputData(Record outputRecord)
            throws ResourceException, SQLException, DataAccessException {
        // ...
    }

    ...

}

此后,在 order 中执行 EIS 操作,您需要使用单个 execute 方法,传入 application-level 输入 object 并接收 application-level 输出 object 作为结果:

public abstract class MappingRecordOperation extends EisOperation {

    ...

    public Object execute(Object inputObject) throws DataAccessException {
    }

    ...
}

如您所见,与CciTemplate class 相反,此execute(..)方法没有InteractionSpec作为参数。相反,InteractionSpec是 global 操作。必须使用以下构造函数来实例化具有特定InteractionSpec的操作 object:

InteractionSpec spec = ...;
MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnectionFactory(), spec);
...

32.4.2 MappingCommAreaOperation

某些连接器使用基于 COMMAREA 的记录,该记录表示包含要发送到 EIS 的参数和由其返回的数据的字节的 array。 Spring 提供了一个特殊的操作 class,用于直接在 COMMAREA 而不是记录上工作。 MappingCommAreaOperation class 扩展MappingRecordOperation class 以提供这种特殊的 COMMAREA 支持。它隐式使用CommAreaRecord class 作为输入和输出 record 类型,并提供两种新方法将输入 object 转换为输入 COMMAREA,将输出 COMMAREA 转换为输出 object。

public abstract class MappingCommAreaOperation extends MappingRecordOperation {

    ...

    protected abstract byte[] objectToBytes(Object inObject)
            throws IOException, DataAccessException;

    protected abstract Object bytesToObject(byte[] bytes)
        throws IOException, DataAccessException;

    ...

}

32.4.3 自动输出记录生成

由于每个MappingRecordOperation子类都在内部基于 CciTemplate,因此可以使用与CciTemplate一样自动生成输出记录的相同方法。每个操作 object 都提供相应的setOutputRecordCreator(..)方法。有关详细信息,请参阅第 32.3.4 节,“自动输出记录生成”

32.4.4 摘要

操作 object 方法以与CciTemplate class 相同的方式使用记录。

表格 1_.使用交互执行方法

MappingRecordOperation 方法签名MappingRecordOperation outputRecordCreator property在 CCI Interaction 上调用的 execute 方法
Object execute(Object)没有设置Record execute(InteractionSpec,Record)
Object execute(Object)boolean execute(InteractionSpec, RECord,Record)

32.4.5 MappingRecordOperation 用法示例

在本节中,将显示MappingRecordOperation的用法以使用 Blackbox CCI 连接器访问数据库。

此连接器的原始 version 由 Oracle 提供的 Java EE SDK(version 1.3)提供。

首先,必须对 CCI InteractionSpec进行一些初始化以指定要执行的 SQL 请求。在这个例子中,我们直接定义了将请求的参数转换为 CCI record 的方式以及将 CCI 结果 record 转换为Person class 实例的方法。

public class PersonMappingOperation extends MappingRecordOperation {

    public PersonMappingOperation(ConnectionFactory connectionFactory) {
        setConnectionFactory(connectionFactory);
        CciInteractionSpec interactionSpec = new CciConnectionSpec();
        interactionSpec.setSql("select * from person where person_id=?");
        setInteractionSpec(interactionSpec);
    }

    protected Record createInputRecord(RecordFactory recordFactory,
            Object inputObject) throws ResourceException {
        Integer id = (Integer) inputObject;
        IndexedRecord input = recordFactory.createIndexedRecord("input");
        input.add(new Integer(id));
        return input;
    }

    protected Object extractOutputData(Record outputRecord)
            throws ResourceException, SQLException {
        ResultSet rs = (ResultSet) outputRecord;
        Person person = null;
        if (rs.next()) {
            Person person = new Person();
            person.setId(rs.getInt("person_id"));
            person.setLastName(rs.getString("person_last_name"));
            person.setFirstName(rs.getString("person_first_name"));
        }
        return person;
    }
}

然后 application 可以执行操作 object,并将 person 标识符作为参数。请注意,操作 object 可以设置为共享实例,因为它是 thread-safe。

public class MyDaoImpl extends CciDaoSupport implements MyDao {

    public Person getPerson(int id) {
        PersonMappingOperation query = new PersonMappingOperation(getConnectionFactory());
        Person person = (Person) query.execute(new Integer(id));
        return person;
    }
}

在 non-managed 模式下,Spring beans 的相应 configuration 可能如下所示:

<bean id="managedConnectionFactory"
        class="com.sun.connector.cciblackbox.CciLocalTxManagedConnectionFactory">
    <property name="connectionURL" value="jdbc:hsqldb:hsql://localhost:9001"/>
    <property name="driverName" value="org.hsqldb.jdbcDriver"/>
</bean>

<bean id="targetConnectionFactory"
        class="org.springframework.jca.support.LocalConnectionFactoryBean">
    <property name="managedConnectionFactory" ref="managedConnectionFactory"/>
</bean>

<bean id="connectionFactory"
        class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter">
    <property name="targetConnectionFactory" ref="targetConnectionFactory"/>
    <property name="connectionSpec">
        <bean class="com.sun.connector.cciblackbox.CciConnectionSpec">
            <property name="user" value="sa"/>
            <property name="password" value=""/>
        </bean>
    </property>
</bean>

<bean id="component" class="MyDaoImpl">
    <property name="connectionFactory" ref="connectionFactory"/>
</bean>

在托管模式下(即在 Java EE 环境中),configuration 可能如下所示:

<jee:jndi-lookup id="targetConnectionFactory" jndi-name="eis/blackbox"/>

<bean id="connectionFactory"
        class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter">
    <property name="targetConnectionFactory" ref="targetConnectionFactory"/>
    <property name="connectionSpec">
        <bean class="com.sun.connector.cciblackbox.CciConnectionSpec">
            <property name="user" value="sa"/>
            <property name="password" value=""/>
        </bean>
    </property>
</bean>

<bean id="component" class="MyDaoImpl">
    <property name="connectionFactory" ref="connectionFactory"/>
</bean>

32.4.6 Example for MappingCommAreaOperation 用法

在本节中,将显示MappingCommAreaOperation的用法:使用 IBM CICS ECI 连接器以 ECI 模式访问 CICS。

首先,需要初始化 CCI InteractionSpec以指定要访问的 CICS 程序以及如何与之交互。

public abstract class EciMappingOperation extends MappingCommAreaOperation {

    public EciMappingOperation(ConnectionFactory connectionFactory, String programName) {
        setConnectionFactory(connectionFactory);
        ECIInteractionSpec interactionSpec = new ECIInteractionSpec(),
        interactionSpec.setFunctionName(programName);
        interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);
        interactionSpec.setCommareaLength(30);
        setInteractionSpec(interactionSpec);
        setOutputRecordCreator(new EciOutputRecordCreator());
    }

    private static class EciOutputRecordCreator implements RecordCreator {
        public Record createRecord(RecordFactory recordFactory) throws ResourceException {
            return new CommAreaRecord();
        }
    }

}

然后可以对 abstract EciMappingOperation class 进行子类化以指定 custom objects 和Records之间的映射。

public class MyDaoImpl extends CciDaoSupport implements MyDao {

    public OutputObject getData(Integer id) {
        EciMappingOperation query = new EciMappingOperation(getConnectionFactory(), "MYPROG") {

            protected abstract byte[] objectToBytes(Object inObject) throws IOException {
                Integer id = (Integer) inObject;
                return String.valueOf(id);
            }

            protected abstract Object bytesToObject(byte[] bytes) throws IOException;
                String str = new String(bytes);
                String field1 = str.substring(0,6);
                String field2 = str.substring(6,1);
                String field3 = str.substring(7,1);
                return new OutputObject(field1, field2, field3);
            }
        });

        return (OutputObject) query.execute(new Integer(id));
    }

}

在 non-managed 模式下,Spring beans 的相应 configuration 可能如下所示:

<bean id="managedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
    <property name="serverName" value="TXSERIES"/>
    <property name="connectionURL" value="local:"/>
    <property name="userName" value="CICSUSER"/>
    <property name="password" value="CICS"/>
</bean>

<bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
    <property name="managedConnectionFactory" ref="managedConnectionFactory"/>
</bean>

<bean id="component" class="MyDaoImpl">
    <property name="connectionFactory" ref="connectionFactory"/>
</bean>

在托管模式下(即在 Java EE 环境中),configuration 可能如下所示:

<jee:jndi-lookup id="connectionFactory" jndi-name="eis/cicseci"/>

<bean id="component" class="MyDaoImpl">
    <property name="connectionFactory" ref="connectionFactory"/>
</bean>

32.5 Transactions

JCA 为资源适配器指定了几个 transaction 支持级别。资源适配器支持的 transactions 类型在其ra.xml文件中指定。基本上有三个选项:none(对于带有 CICS EPI 连接器的 example),local transactions(对于带有 CICS ECI 连接器的 example), global transactions(对于带有 IMS 连接器的 example)。

<connector>
    <resourceadapter>
        <!-- <transaction-support>NoTransaction</transaction-support> -->
        <!-- <transaction-support>LocalTransaction</transaction-support> -->
        <transaction-support>XATransaction</transaction-support>
    <resourceadapter>
<connector>

对于 global transactions,您可以使用 Spring 的通用 transaction 基础结构来划分 transactions,将JtaTransactionManager作为后端(委托给下面的 Java EE 服务器的分布式 transaction 协调器)。

对于单个 CCI ConnectionFactory上的本地 transactions,Spring 为 CCI 提供了特定的 transaction management 策略,类似于 JDBC 的DataSourceTransactionManager。 CCI API 定义了本地 transaction object 和相应的本地 transaction 分界方法。 Spring 的CciLocalTransactionManager执行这样的本地 CCI transactions,完全符合 Spring 的通用PlatformTransactionManager抽象。

<jee:jndi-lookup id="eciConnectionFactory" jndi-name="eis/cicseci"/>

<bean id="eciTransactionManager"
        class="org.springframework.jca.cci.connection.CciLocalTransactionManager">
    <property name="connectionFactory" ref="eciConnectionFactory"/>
</bean>

两种 transaction 策略都可以与 Spring 的 transaction 分界设施一起使用,无论是声明性的还是程序性的。这是 Spring 的通用PlatformTransactionManager抽象的结果,它将 transaction 分界与实际执行策略分离。只需根据需要在JtaTransactionManagerCciLocalTransactionManager之间切换,保持 transaction 分界 as-is。

有关 Spring 的 transaction 工具的更多信息,请参阅标题为第 17 章,交易管理的章节。

Updated at: 9 months ago
31.8. 更多资源Table of content33. 电子邮件