Modeling CCI Access as Operation Objects
The org.springframework.jca.cci.object
package contains support classes that let you
access the EIS in a different style: through reusable operation objects, analogous to
Spring’s JDBC operation objects (see the JDBC section of the
Data Access chapter). This usually encapsulates the CCI API. An application-level
input object is passed to the operation object, so it can construct the input record and
then convert the received record data to an application-level output object and return it.
This approach is internally based on the CciTemplate class and the RecordCreator
or RecordExtractor interfaces, reusing the machinery of Spring’s core CCI support.
|
Using MappingRecordOperation
MappingRecordOperation
essentially performs the same work as CciTemplate
but
represents a specific, pre-configured operation as an object. It provides two template
methods to specify how to convert an input object to an input record and how to convert
an output record to an output object (record mapping):
-
createInputRecord(..)
: to specify how to convert an input object to an inputRecord
-
extractOutputData(..)
: to specify how to extract an output object from an outputRecord
The following listing shows the signatures of these methods:
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 {
// ...
}
...
}
Thereafter, ito execute an EIS operation, you need to use a single execute
method, passing in an application-level input object and receiving an application-level
output object as the result. The following example shows how to do so:
public abstract class MappingRecordOperation extends EisOperation {
...
public Object execute(Object inputObject) throws DataAccessException {
}
...
}
Contrary to the CciTemplate
class, this execute(..)
method does not
have an InteractionSpec
as an argument. Instead, the InteractionSpec
is global to the
operation. You must use the following constructor to instantiate an operation object
with a specific InteractionSpec
. The following example shows how to do so:
InteractionSpec spec = ...;
MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnectionFactory(), spec);
...
Using MappingCommAreaOperation
Some connectors use records based on a COMMAREA, which represents an array of bytes
that contain parameters to send to the EIS and the data returned by it. Spring provides a
special operation class for working directly on COMMAREA rather than on records. The
MappingCommAreaOperation
class extends the MappingRecordOperation
class to provide
this special COMMAREA support. It implicitly uses the CommAreaRecord
class as the input
and output record type and provides two new methods to convert an input object into an
input COMMAREA and convert the output COMMAREA into an output object. The following
listing shows the relevant method signatures:
public abstract class MappingCommAreaOperation extends MappingRecordOperation {
...
protected abstract byte[] objectToBytes(Object inObject)
throws IOException, DataAccessException;
protected abstract Object bytesToObject(byte[] bytes)
throws IOException, DataAccessException;
...
}
Automatic Output Record Generation
As every MappingRecordOperation
subclass is based on CciTemplate internally, the same
way to automatically generate output records as with CciTemplate
is available.
Every operation object provides a corresponding setOutputRecordCreator(..)
method.
For further information, see automatic-output-generation.
Summary
The operation object approach uses records in the same manner as the CciTemplate
class.
MappingRecordOperation method signature |
MappingRecordOperation outputRecordCreator property |
execute method called on the CCI Interaction |
---|---|---|
|
Not set |
|
|
Set |
|
Example of MappingRecordOperation
Usage
In this section, we show how to use MappingRecordOperation
to access a
database with the Blackbox CCI connector.
The original version of this connector is provided by the Java EE SDK (version 1.3), which is available from Oracle. |
First, you must do some initializations on the CCI InteractionSpec
to specify which
SQL request to execute. In the following example, we directly define the way to convert the
parameters of the request to a CCI record and the way to convert the CCI result record
to an instance of the 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;
}
}
Then the application can execute the operation object, with the person identifier as an argument. Note that you could set up the operation object as a shared instance, as it is thread-safe. The following executes the operation object with the person identifier as an argument:
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;
}
}
The corresponding configuration of Spring beans could be as follows in 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>
In managed mode (that is, in a Java EE environment), the configuration could be as follows:
<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>
Example of MappingCommAreaOperation
Usage
In this section, we show how to use the usage of the MappingCommAreaOperation
to access a
CICS with ECI mode with the IBM CICS ECI connector.
First, we need to initialize the CCI InteractionSpec
to specify which CICS program
to access and how to interact with it, as the following example shows:
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();
}
}
}
We can then subclass the abstract EciMappingOperation
class to specify mappings
between custom objects and Records
, as the following example shows:
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));
}
}
The corresponding configuration of Spring beans could be as follows in 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>
In managed mode (that is, in a Java EE environment), the configuration could be as follows:
<jee:jndi-lookup id="connectionFactory" jndi-name="eis/cicseci"/>
<bean id="component" class="MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>