对JCA CCI支持的一个目标是提供方便的机制来操作CCI记录。
开发人员可以通过使用Spring CciTemplate
来指定创建记录并从记录中提取数据的策略。
如果你不想在你的应用程序中直接操作记录,你可以使用下面的接口来配置用于输入输出记录的策略。
为创建一个输入Record
,开发人员可以使用 RecordCreator
接口的一个特定实现。
public interface RecordCreator { Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException; }
正如你所看到的一样, createRecord(..)
方法接收一个 RecordFactory
实例作为参数,该参数对应于所使用的 ConnectionFactory
的RecordFactory
接口。
它能被用于创建 IndexedRecord
或者 MappedRecord
的实例。
下面的例子展示了如何使用 RecordFactory
接口和索引(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
接口的特定实现可以被传给Spring的 CciTemplate
,
用来从输出Record
接口中提取数据。
public interface RecordExtractor { Object extractData(Record record) throws ResourceException, SQLException, DataAccessException; }
下面的例子展示了如何使用 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); } }
CciTemplate
类是 CCI 核心支持包(org.springframework.jca.cci.core
)中的中心类。
它简化了CCI的使用,因为它会处理资源的创建和释放。这有助于避免常见的错误,比如总是忘记关闭连接。
它关注连接和交互对象的生命周期,从而使应用程序的代码可以专注于处理从应用数据中生成输入记录和从输出记录中提取应用数据。
JCA CCI规范定义了两个不同的方法来在EIS上调用操作。CCI Interaction
接口提供两个 execute
方法的签名:
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
类可以知道 interaction上的哪个 execute
方法被调用。
在任何情况下,都必须有一个正确初始化过的 InteractionSpec
接口实例。
CciTemplate.execute(..)
可以在以下两种方式下使用:
在提供直接的Record
参数的情况下,你仅仅需要简单的传递输入记录给 CCI ,
而返回的对象就是对应的 CCI 输出记录。
在提供使用记录映射的应用对象的情况下,你需要提供相应的 RecordCreator
和 RecordExtractor
实例。
第一种方法将使用下面的模板方法。这些模板方法将直接对应到 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 { ... } ... }
第二种方法需要我们以参数的方式指定创建记录和记录提取的策略。
使用前面记录转化一节中描述的接口。对应的 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
属性(参见下一部分),
不然每个方法将调用CCI Interaction
中相应的含有两个参数: InteractionSpec
和输入 Record
的 execute
方法,
并接收一个输出 Record
作为返回值。
通过 createIndexRecord(..)
和 createMappedRecord(..)
方法,CciTemplate
在RecordCreator
实现类外部也提供了创建 IndexRecord
和 MappedRecord
。
还可以用来在DAO实现内创建记录实例并传入到相应的 CciTemplate.execute(..)
方法。
public class CciTemplate implements CciOperations { ... public IndexedRecord createIndexedRecord(String name) throws DataAccessException { ... } public MappedRecord createMappedRecord(String name) throws DataAccessException { ... } ... }
Spring的 CCI 支持为 DAO 提供了一个抽象类,支持 ConnectionFactory
或 CciTemplate
实例的注入。
这个类的名字是 CciDaoSupport
:它提供了简单的 setConnectionFactory
和 setCciTemplate
方法。
在内部,该类将为传入的 ConnectionFactory
创建一个 CciTemplate
实例,
并把它暴露给子类中具体的数据访问实现使用。
public abstract class CciDaoSupport { ... public void setConnectionFactory(ConnectionFactory connectionFactory) { ... } public ConnectionFactory getConnectionFactory() { ... } public void setCciTemplate(CciTemplate cciTemplate) { ... } public CciTemplate getCciTemplate() { ... } ... }
如果所用的连接器只支持以输入输出记录作为参数的 Interaction.execute(..)
方法
(就是说,它要求传入期望的输出记录而不是返回适当的输出记录),
你可以设定 CciTemplate
类的 outputRecordCreator
属性来自动生成一个输出记录,
当接收到响应时JCA连接器(JCA connector)将填充该记录并返回给模板的调用者。
因为这个目的,这个属性只持有 RecordCreator
接口的一个实现。RecordCreator
接口已经在第 21.3.1 节 “记录转换”进行了讨论。
outputRecordCreator
属性必须直接在 CciTemplate
中指定,可以在应用代码中做到这一点。
cciTemplate.setOutputRecordCreator(new EciOutputRecordCreator());
或者如果CciTemplate
被配置为一个专门的bean实例,那么outputRecordCreator还可以在Spring文件中配置(推荐的做法):
<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
类是线程安全的,所以它通常被配置为一个共享实例。
下表总结了 CciTemplate
类和在 CCI Interaction
接口上调用相应方法的机制:
表 21.1. Usage of Interaction
execute methods
CciTemplate method signature | CciTemplate outputRecordCreator property | execute method called on the CCI Interaction |
---|---|---|
Record execute(InteractionSpec, Record) | not set | Record execute(InteractionSpec, Record) |
Record execute(InteractionSpec, Record) | set | boolean execute(InteractionSpec, Record, Record) |
void execute(InteractionSpec, Record, Record) | not set | void execute(InteractionSpec, Record, Record) |
void execute(InteractionSpec, Record, Record) | set | void execute(InteractionSpec, Record, Record) |
Record execute(InteractionSpec, RecordCreator) | not set | Record execute(InteractionSpec, Record) |
Record execute(InteractionSpec, RecordCreator) | set | void execute(InteractionSpec, Record, Record) |
Record execute(InteractionSpec, Record, RecordExtractor) | not set | Record execute(InteractionSpec, Record) |
Record execute(InteractionSpec, Record, RecordExtractor) | set | void execute(InteractionSpec, Record, Record) |
Record execute(InteractionSpec, RecordCreator, RecordExtractor) | not set | Record execute(InteractionSpec, Record) |
Record execute(InteractionSpec, RecordCreator, RecordExtractor) | set | void execute(InteractionSpec, Record, Record) |
类似于JdbcTemplate
类和 JmsTemplate
类的操作方式,CciTemplate
类同样提供直接操作CCI 连接和交互的可能性。
比如说如果你想对一个CCI连接执行多种操作,这就会很有用。
ConnectionCallback
接口提供以CCI Connection
作为参数,为了在它上面执行自定义动作,添加了创建Connection
的CCI ConnectionFactory
。
后者在获取相关 RecordFactory
实例和创建indexed/mapped records时很有用。例如:
public interface ConnectionCallback { Object doInConnection(Connection connection, ConnectionFactory connectionFactory) throws ResourceException, SQLException, DataAccessException; }
InteractionCallback
接口提供 CCI Interaction
接口,为了在它上面执行自定义动作,请添加相应的CCI ConnectionFactory
。
public interface InteractionCallback { Object doInInteraction(Interaction interaction, ConnectionFactory connectionFactory) throws ResourceException, SQLException, DataAccessException; }
InteractionSpec
对象还可以在多个template调用之间被共享或者在每个回调方法内重新创建,这完全取决于 DAO 的实现。
在这章节中,我们将展示如何使用 CciTemplate
和IBM CICS ECI连接器在ECI模式下访问一个CICS.
首先,在CCI InteractionSpec
进行一些初始化以指定访问哪个CICS程序并且指定如何进行交互。
ECIInteractionSpec interactionSpec = new ECIInteractionSpec(); interactionSpec.setFunctionName("MYPROG"); interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);
然后,程序通过Spring的模板使用 CCI 并在自定义对象和 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; } }
正如之前讨论的那样,callbacks 可以被用来直接在 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 { ... } }); } return output; } }
当getCciTemplate().execute参数是ConnectionCallback
时,
所用的 Connection
将被 CciTemplate
管理和关闭,
但是任何在连接上建立的交互必须被callback实现类所管理。
对于一个更特殊的callback,你可以实现一个 InteractionCallback
。
这样传入的 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; } }
上面的例子中,在非托管模式(non-managed)下对应的spring beans的配置会是下面这样:
<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>
在托管模式(managed mode)(也就是说,在一个J2EE环境)下,配置可能如下所示:
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="eis/cicseci"/> </bean> <bean id="component" class="MyDaoImpl"> <property name="connectionFactory" ref="connectionFactory"/> </bean>