org.springframework.jca.cci.object
包中包含的支持类允许你以另一种风格访问EIS:
通过可重用的操作对象,类似于Spring的JDBC操作对象(参见JDBC一章)。
它通常都封装了 CCI 的API:将应用级的输入对象传入到操作对象,
从而它能创建输入record然后转换接收到的record数据到一个应用级输出对象并返回它。
注意: 这种方法内在地基于 CciTemplate
类和
RecordCreator
/ RecordExtractor
接口,重用了Spring核心CCI支持的机制。
MappingRecordOperation
本质上与 CciTemplate
做的事情是一样的,
但是它表达了一个明确的、预配置(pre-configured)的操作作为对象。它提供了两个模板方法来指明如何将一个输入对象转换为输入记录,
以及如何将一个输出记录转换为输出对象(记录映射):
createInputRecord(..)
指定了如何将一个输入对象转换为输入Record
extractOutputData(..)
指定了如何从输出 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 { ... } ... }
此后,为了执行一个 EIS 操作,你需要使用一个单独的execute方法,传递一个应用级(application-level) 输入对象,并接收一个应用级输出对象作为结果:
public abstract class MappingRecordOperation extends EisOperation { ... public Object execute(Object inputObject) throws DataAccessException { ... }
正如你所看到的,与 CciTemplate
类相反,
这个execute
方法并没有 InteractionSpec
参数,
然而,InteractionSpec
对操作是全局的。
下面的构造方法必须使用指定的 InteractionSpec
来初始化一个操作对象:
InteractionSpec spec = ...; MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnectionFactory(), spec); ...
一些连接器使用了基于COMMAREA的记录,该记录包含了发送给EIS的参数和返回数据的字节数组。
Spring提供了一个专门的操作类用于直接操作COMMAREA而不是操作记录。
MappingCommAreaOperation
类扩展了 MappingRecordOperation
类以提供这种专门的COMMAREA支持。
它隐含地使用了 CommAreaRecord
类作为输入和输出record类型,
并提供了两个新的方法来转换输入对象到输入COMMAREA,以及转换输出COMMAREA到输出对象。
public abstract class MappingCommAreaOperation extends MappingRecordOperation { ... protected abstract byte[] objectToBytes(Object inObject) throws IOException, DataAccessException; protected abstract Object bytesToObject(byte[] bytes) throws IOException, DataAccessException; ... }
由于每个 MappingRecordOperation
子类的内部都是基于 CciTemplate
的,所以
用 CciTemplate
以相同的方式自动生成输出record都是有效的。
每个操作对象提供一个相应的 setOutputRecordCreator(..)
方法。
更多的信息,请参见前面的第 21.3.4 节 “自动输出记录生成”一节。
操作对象方法使用了跟 CciTemplate
相同的方式来使用记录。
表 21.2. Usage of Interaction execute methods
MappingRecordOperation method
signature |
MappingRecordOperation
outputRecordCreator property |
execute method called on the CCI
Interaction
|
---|---|---|
Object execute(Object) | not set | Record execute(InteractionSpec, Record) |
Object execute(Object) | set | boolean execute(InteractionSpec, Record, Record) |
在本节中,将通过展示使用 Blackbox CCI 连接器访问一个数据库来说明 MappingRecordOperation
的用法。
该连接器的最初版本是由SUN提供的J2EE SDK(1.3版本)。
首先,必须在 CCI InteractionSpec
中进行一些初始化动作来指定执行哪些SQL请求。
在这个例子中,我们直接定义了将请求参数转换为CCI record以及将CCI结果记录转换为一个 Person
类的实例的方法。
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; } }
然后应用程序会以person标识符作为参数来得到操作对象。注意:操作对象可以被设为共享实例,因为它是线程安全的。
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; } }
对应的Spring beans的配置看起来类似于下面非托管模式(non-managed mode)的配置:
<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>
在托管模式(managed mode)(也就是说,在一个J2EE环境中)),配置可能看起来像这样:
<bean id="targetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="eis/blackbox"/> </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>
在本节中,将展示 MappingCommAreaOperation
类的用法:通过IBM 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(); } } }
The abstract EciMappingOperation
class can
then be subclassed to specify mappings between custom objects and
Records
.
EciMappingOperation
抽象类可以被子类化以指定自定义对象和 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)); } }
对应的Spring beans的配置看起来类似于下面非托管模式(non-managed mode)的配置:
<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>
在托管模式(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>