22.4.建模CCI访问为操作对象
22.4. 建模CCI访问为操作对象
org.springframework.jca.cci.object
包中包含的支持类允许你以另一种风格访问EIS: 通过可重用的操作对象,类似于Spring的JDBC操作对象(参见JDBC一章)。 它通常都封装了 CCI 的API:将应用级的输入对象传入到操作对象, 从而它能创建输入record然后转换接收到的record数据到一个应用级输出对象并返回它。
注意: 这种方法内在地基于 CciTemplate
类和 RecordCreator
/RecordExtractor
接口,重用了Spring核心CCI支持的机制。
22.4.1. MappingRecordOperation
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); ...
22.4.2. MappingCommAreaOperation
一些连接器使用了基于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; ... }
22.4.3. 自动输出记录生成
由于每个 MappingRecordOperation
子类的内部都是基于 CciTemplate
的,所以 用 CciTemplate
以相同的方式自动生成输出record都是有效的。 每个操作对象提供一个相应的 setOutputRecordCreator(..)
方法。 更多的信息,请参见前面的第 22.3.4 节 “自动输出记录生成 ”一节。
22.4.4. 总结
操作对象使用了跟 CciTemplate
相同的方法来使用记录。
表 22.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) |
22.4.5. MappingRecordOperation
使用示例
在本节中,将通过展示使用 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" > <property name="connectionURL" value="jdbc:hsqldb:hsql://localhost:9001"/> <property name="driverName" value="org.hsqldb.jdbcDriver"/> </bean> <bean id="targetConnectionFactory" > <property name="managedConnectionFactory" ref="managedConnectionFactory"/> </bean> <bean id="connectionFactory" > <property name="targetConnectionFactory" ref="targetConnectionFactory"/> <property name="connectionSpec"> <bean> <property name="user" value="sa"/> <property name="password" value=""/> </bean> </property> </bean> <bean id="component"> <property name="connectionFactory" ref="connectionFactory"/> </bean>
在托管模式(managed mode)(也就是说,在一个J2EE环境中),配置可能看起来像这样:
<bean id="targetConnectionFactory"> <property name="jndiName" value="eis/blackbox"/> </bean> <bean id="connectionFactory" > <property name="targetConnectionFactory" ref="targetConnectionFactory"/> <property name="connectionSpec"> <bean> <property name="user" value="sa"/> <property name="password" value=""/> </bean> </property> </bean> <bean id="component"> <property name="connectionFactory" ref="connectionFactory"/> </bean>
22.4.6. MappingCommAreaOperation
使用示例
在本节中,将展示 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(); } } }
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"> <property name="serverName" value="TXSERIES"/> <property name="connectionURL" value="local:"/> <property name="userName" value="CICSUSER"/> <property name="password" value="CICS"/> </bean> <bean id="connectionFactory"> <property name="managedConnectionFactory" ref="managedConnectionFactory"/> </bean> <bean id="component"> <property name="connectionFactory" ref="connectionFactory"/> </bean>
在托管模式(managed mode)(也就是说,在一个J2EE环境中),配置可能看起来像这样:
<bean id="connectionFactory"> <property name="jndiName" value="eis/cicseci"/> </bean> <bean id="component"> <property name="connectionFactory" ref="connectionFactory"/> </bean>