Spring建模CCI訪問為操作物件

ouhennb發表於2009-06-15
org.springframework.jca.cci.object 包中包含的支援類允許你以另一種風格訪問EIS: 通過可重用的操作物件,類似於Spring的JDBC操作物件。 它通常都封裝了 CCI 的API:將應用級的輸入物件傳入到操作物件, 從而它能建立輸入record然後轉換接收到的record資料到一個應用級輸出物件並返回它。

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);
...

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;
...
}

自動生成輸出記錄
由於每個 MappingRecordOperation 子類的內部都是基於 CciTemplate 的,所以 用 CciTemplate 以相同的方式自動生成輸出record都是有效的。 每個操作物件提供一個相應的 setOutputRecordCreator(..) 方法。

MappingRecordOperation 使用示例
在本節中,將通過展示使用 Blackbox CCI 聯結器訪問一個資料庫來說明 MappingRecordOperation 的用法。

首先,必須在 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)(也就是說,在一個JAVA EE環境中)),配置可能看起來像這樣:

<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 使用示例
在本節中,將展示 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)(也就是說,在一個JAVA EE環境中),配置可能看起來像這樣:

<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>

相關文章