spring-framework/spring-framework-reference/src/cci.xml

1156 lines
50 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<chapter id="cci">
<title>JCA CCI</title>
<section id="cci-introduction">
<title>Introduction</title>
<para>J2EE provides a specification to standardize access to enterprise information systems (EIS):
the JCA (Java Connector Architecture). This specification is divided into several different parts:</para>
<itemizedlist>
<listitem>
<para>SPI (Service provider interfaces) that the connector provider
must implement. These interfaces constitute a resource adapter which
can be deployed on a J2EE application server. In such a scenario, the
server manages connection pooling, transaction and security (managed
mode). The application server is also responsible for managing the
configuration, which is held outside the client application. A connector
can be used without an application server as well; in this case, the
application must configure it directly (non-managed mode).</para>
</listitem>
<listitem>
<para>CCI (Common Client Interface) that an application can use to
interact with the connector and thus communicate with an EIS. An API
for local transaction demarcation is provided as well.</para>
</listitem>
</itemizedlist>
<para>The aim of the Spring CCI support is to provide classes to access
a CCI connector in typical Spring style, leveraging the Spring Framework's general
resource and transaction management facilities.</para>
<note>
<para>The client side of connectors doesn't alway use CCI. Some
connectors expose their own APIs, only providing JCA resource adapter to
use the system contracts of a J2EE container (connection pooling, global
transactions, security). Spring does not offer special support for such
connector-specific APIs.</para>
</note>
</section>
<section id="cci-config">
<title>Configuring CCI</title>
<section id="cci-config-connector">
<title>Connector configuration</title>
<para>The base resource to use JCA CCI is the
<interfacename>ConnectionFactory</interfacename> interface. The connector used
must provide an implementation of this interface.</para>
<para>To use your connector, you can deploy it on your application
server and fetch the <interfacename>ConnectionFactory</interfacename> from the
server's JNDI environment (managed mode). The connector must be
packaged as a RAR file (resource adapter archive) and contain a
<filename>ra.xml</filename> file to describe its deployment
characteristics. The actual name of the resource is specified when
you deploy it. To access it within Spring, simply use Spring's
<classname>JndiObjectFactoryBean</classname> to fetch the factory
by its JNDI name.</para>
<para>Another way to use a connector is to embed it in your application
(non-managed mode), not using an application server to deploy and
configure it. Spring offers the possibility to configure a connector
as a bean, through a provided <literal>FactoryBean</literal>
(<classname>LocalConnectionFactoryBean</classname>). In this manner,
you only need the connector library in the classpath (no RAR file and
no <filename>ra.xml</filename> descriptor needed). The library must
be extracted from the connector's RAR file, if necessary.</para>
<para>Once you have got access to your <interfacename>ConnectionFactory</interfacename>
instance, you can inject it into your components. These components can
either be coded against the plain CCI API or leverage Spring's support
classes for CCI access (e.g. <classname>CciTemplate</classname>).</para>
<note>
<para>When you use a connector in
non-managed mode, you can't use global transactions because the resource
is never enlisted / delisted in the current global transaction of the
current thread. The resource is simply not aware of any global J2EE
transactions that might be running.</para>
</note>
</section>
<section id="cci-config-connectionfactory">
<title><interfacename>ConnectionFactory</interfacename> configuration in Spring</title>
<para>In order to make connections to the EIS, you need to obtain a
<interfacename>ConnectionFactory</interfacename> from the application server if
you are in a managed mode, or directly from Spring if you are in a
non-managed mode.</para>
<para>In a managed mode, you access a <interfacename>ConnectionFactory</interfacename>
from JNDI; its properties will be configured in the application server.</para>
<programlisting><![CDATA[<bean id="eciConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="eis/cicseci"/>
</bean>]]></programlisting>
<para>In non-managed mode, you must configure the <interfacename>ConnectionFactory</interfacename>
you want to use in the configuration of Spring as a JavaBean. The
<classname>LocalConnectionFactoryBean</classname> class offers this
setup style, passing in the <classname>ManagedConnectionFactory</classname>
implementation of your connector, exposing the application-level
CCI <interfacename>ConnectionFactory</interfacename>.</para>
<programlisting><![CDATA[<bean id="eciManagedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
<property name="serverName" value="TXSERIES"/>
<property name="connectionURL" value="tcp://localhost/"/>
<property name="portNumber" value="2006"/>
</bean>
<bean id="eciConnectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="eciManagedConnectionFactory"/>
</bean>]]></programlisting>
<note>
<para>You can't directly instantiate a specific
<interfacename>ConnectionFactory</interfacename>. You need to go through
the corresponding implementation of the
<classname>ManagedConnectionFactory</classname> interface for your
connector. This interface is part of the JCA SPI specification.</para>
</note>
</section>
<section id="cci-config-cci-connections">
<title>Configuring CCI connections</title>
<para>JCA CCI allow the developer to configure the connections to the
EIS using the <interfacename>ConnectionSpec</interfacename> implementation of your
connector. In order to configure its properties, you need to wrap the
target connection factory with a dedicated adapter,
<classname>ConnectionSpecConnectionFactoryAdapter</classname>. So, the
dedicated <interfacename>ConnectionSpec</interfacename> can be configured with the
property <literal>connectionSpec</literal> (as an inner bean).</para>
<para>This property is not mandatory because the CCI
<interfacename>ConnectionFactory</interfacename> interface defines two different
methods to obtain a CCI connection. Some of the
<interfacename>ConnectionSpec</interfacename> properties can often be configured
in the application server (in managed mode) or on the corresponding local
<classname>ManagedConnectionFactory</classname> implementation.</para>
<programlisting><![CDATA[public interface ConnectionFactory implements Serializable, Referenceable {
...
Connection getConnection() throws ResourceException;
Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException;
...
}]]></programlisting>
<para>Spring provides a <classname>ConnectionSpecConnectionFactoryAdapter</classname>
that allows for specifying a <interfacename>ConnectionSpec</interfacename> instance
to use for all operations on a given factory. If the adapter's
<literal>connectionSpec</literal> property is specified, the adapter
uses the <literal>getConnection</literal> variant without argument,
else the one with the <interfacename>ConnectionSpec</interfacename> argument.</para>
<programlisting><![CDATA[<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>]]></programlisting>
</section>
<section id="cci-config-single-connection">
<title>Using a single CCI connection</title>
<para>If you want to use a single CCI connection, Spring provides a further
<interfacename>ConnectionFactory</interfacename> adapter to manage this. The
<classname>SingleConnectionFactory</classname> adapter class will open a single
connection lazily and close it when this bean is destroyed at application
shutdown. This class will expose special <interfacename>Connection</interfacename>
proxies that behave accordingly, all sharing the same underlying physical
connection.</para>
<programlisting><![CDATA[<bean id="eciManagedConnectionFactory"
class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
<property name="serverName" value="TEST"/>
<property name="connectionURL" value="tcp://localhost/"/>
<property name="portNumber" value="2006"/>
</bean>
<bean id="targetEciConnectionFactory"
class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="eciManagedConnectionFactory"/>
</bean>
<bean id="eciConnectionFactory"
class="org.springframework.jca.cci.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="targetEciConnectionFactory"/>
</bean>]]></programlisting>
<note>
<para>This <interfacename>ConnectionFactory</interfacename> adapter cannot directly be
configured with a <interfacename>ConnectionSpec</interfacename>. Use an
intermediary <classname>ConnectionSpecConnectionFactoryAdapter</classname>
that the <classname>SingleConnectionFactory</classname> talks to
if you require a single connection for a specific
<interfacename>ConnectionSpec</interfacename>.</para>
</note>
</section>
</section>
<section id="cci-using">
<title>Using Spring's CCI access support</title>
<section id="cci-record-creator">
<title>Record conversion</title>
<para>One of the aims of the JCA CCI support is to provide convenient
facilities for manipulating CCI records. The developer can specify the
strategy to create records and extract datas from records, for use
with Spring's <classname>CciTemplate</classname>. The following interfaces will configure the
strategy to use input and output records if you don't want to work
with records directly in your application.</para>
<para>In order to create an input <interfacename>Record</interfacename>, the
developer can use a dedicated implementation of the
<interfacename>RecordCreator</interfacename> interface.</para>
<programlisting><![CDATA[public interface RecordCreator {
Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException;
}]]></programlisting>
<para>As you can see, the <literal>createRecord(..)</literal> method
receives a <interfacename>RecordFactory</interfacename> instance as parameter,
which corresponds to the <interfacename>RecordFactory</interfacename> of the
<interfacename>ConnectionFactory</interfacename> used. This reference can be
used to create <interfacename>IndexedRecord</interfacename> or
<interfacename>MappedRecord</interfacename> instances. The following sample
shows how to use the <interfacename>RecordCreator</interfacename> interface
and indexed/mapped records.</para>
<programlisting><![CDATA[public class MyRecordCreator implements RecordCreator {
public Record createRecord(RecordFactory recordFactory) throws ResourceException {
IndexedRecord input = recordFactory.createIndexedRecord("input");
input.add(new Integer(id));
return input;
}
}]]></programlisting>
<para>An output <interfacename>Record</interfacename> can be used to receive
data back from the EIS. Hence, a specific implementation of the
<interfacename>RecordExtractor</interfacename> interface can be passed to
Spring's <classname>CciTemplate</classname> for extracting data from the output
<interfacename>Record</interfacename>.</para>
<programlisting><![CDATA[public interface RecordExtractor {
Object extractData(Record record) throws ResourceException, SQLException, DataAccessException;
}]]></programlisting>
<para>The following sample shows how to use the <interfacename>RecordExtractor</interfacename> interface.</para>
<programlisting><![CDATA[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);
}
}]]></programlisting>
</section>
<section id="cci-using-template">
<title>The <classname>CciTemplate</classname></title>
<para>The <classname>CciTemplate</classname> is the central class of the core CCI support package
(<literal>org.springframework.jca.cci.core</literal>). It simplifies
the use of CCI since it handles the creation and release of resources.
This helps to avoid common errors like forgetting to always close the
connection. It cares for the lifecycle of connection and interaction
objects, letting application code focus on generating input records
from application data and extracting application data from output
records.</para>
<para>The JCA CCI specification defines two distinct methods to call
operations on an EIS. The CCI <interfacename>Interaction</interfacename>
interface provides two execute method signatures:</para>
<programlisting><![CDATA[public interface javax.resource.cci.Interaction {
...
boolean execute(InteractionSpec spec, Record input, Record output) throws ResourceException;
Record execute(InteractionSpec spec, Record input) throws ResourceException;
...
}]]></programlisting>
<para>Depending on the template method called, <classname>CciTemplate</classname>
will know which <literal>execute</literal> method to call on the interaction.
In any case, a correctly initialized <interfacename>InteractionSpec</interfacename>
instance is mandatory.</para>
<para><literal>CciTemplate.execute(..)</literal> can be used in two ways:</para>
<itemizedlist>
<listitem>
<para>With direct <interfacename>Record</interfacename> arguments. In this case,
you simply need to pass the CCI input record in, and the returned object
be the corresponding CCI output record.</para>
</listitem>
<listitem>
<para>With application objects, using record mapping. In this case,
you need to provide corresponding <interfacename>RecordCreator</interfacename>
and <interfacename>RecordExtractor</interfacename> instances.
</para>
</listitem>
</itemizedlist>
<para>With the first approach, the following methods of the template
will be used. These methods directly correspond to those on the
<interfacename>Interaction</interfacename> interface.</para>
<programlisting><![CDATA[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 { ... }
}]]></programlisting>
<para>With the second approach, we need to specify the record creation
and record extraction strategies as arguments. The interfaces used
are those describe in the previous section on record conversion.
The corresponding <classname>CciTemplate</classname> methods are the
following:</para>
<programlisting><![CDATA[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 { ... }
}]]></programlisting>
<para>Unless the <literal>outputRecordCreator</literal> property is
set on the template (see the following section), every method will call
the corresponding <literal>execute</literal> method of the CCI
<interfacename>Interaction</interfacename> with two parameters:
<interfacename>InteractionSpec</interfacename> and input <interfacename>Record</interfacename>,
receiving an output <interfacename>Record</interfacename> as return value.
</para>
<para><classname>CciTemplate</classname> also provides methods to create
<literal>IndexRecord</literal> and <literal>MappedRecord</literal>
outside a <interfacename>RecordCreator</interfacename> implementation, through
its <literal>createIndexRecord(..)</literal> and
<literal>createMappedRecord(..)</literal> methods. This can be used
within DAO implementations to create <interfacename>Record</interfacename>
instances to pass into corresponding
<literal>CciTemplate.execute(..)</literal> methods.</para>
<programlisting><![CDATA[public class CciTemplate implements CciOperations {
public IndexedRecord createIndexedRecord(String name) throws DataAccessException { ... }
public MappedRecord createMappedRecord(String name) throws DataAccessException { ... }
}]]></programlisting>
</section>
<section id="cci-using-dao">
<title>DAO support</title>
<para>Spring's CCI support provides a abstract class for DAOs,
supporting injection of a <interfacename>ConnectionFactory</interfacename>
or a <classname>CciTemplate</classname> instances. The name of the
class is <classname>CciDaoSupport</classname>: It provides simple
<literal>setConnectionFactory</literal> and
<literal>setCciTemplate</literal> methods. Internally, this
class will create a <classname>CciTemplate</classname> instance
for a passed-in <interfacename>ConnectionFactory</interfacename>, exposing
it to concrete data access implementations in subclasses.</para>
<programlisting><![CDATA[public abstract class CciDaoSupport {
public void setConnectionFactory(ConnectionFactory connectionFactory) { ... }
public ConnectionFactory getConnectionFactory() { ... }
public void setCciTemplate(CciTemplate cciTemplate) { ... }
public CciTemplate getCciTemplate() { ... }
}]]></programlisting>
</section>
<section id="automatic-output-generation">
<title>Automatic output record generation</title>
<para>If the connector used only supports the
<methodname>Interaction.execute(..)</methodname> method with input and output
records as parameters (that is, it requires the desired output record
to be passed in instead of returning an appropriate output record),
you can set the <literal>outputRecordCreator</literal> property of the
<classname>CciTemplate</classname> to automatically generate an output
record to be filled by the JCA connector when the response is received.
This record will be then returned to the caller of the template.</para>
<para>This property simply holds an implementation of the
<interfacename>RecordCreator</interfacename> interface, used for that purpose.
The <interfacename>RecordCreator</interfacename> interface has already been
discussed in the section entitled <xref linkend="cci-record-creator"/>.
The <literal>outputRecordCreator</literal>
property must be directly specified on the <classname>CciTemplate</classname>.
This could be done in the application code like so:</para>
<programlisting><![CDATA[cciTemplate.setOutputRecordCreator(new EciOutputRecordCreator());]]></programlisting>
<para>Or (recommended) in the Spring configuration, if the <classname>CciTemplate</classname>
is configured as a dedicated bean instance:</para>
<programlisting><![CDATA[<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>]]></programlisting>
<note>
<para>As the <classname>CciTemplate</classname> class is thread-safe, it will
usually be configured as a shared instance.</para>
</note>
</section>
<section id="template-summary">
<title>Summary</title>
<para>The following table summarizes the mechanisms of the
<classname>CciTemplate</classname> class and the corresponding methods
called on the CCI <interfacename>Interaction</interfacename> interface:<table
frame="all" id="cci-interaction-execute-methods">
<title>Usage of <interfacename>Interaction</interfacename> execute methods</title>
<tgroup cols="3">
<thead>
<row>
<entry align="center">CciTemplate method signature</entry>
<entry align="center">CciTemplate outputRecordCreator
property</entry>
<entry align="center">execute method called on the CCI
Interaction</entry>
</row>
</thead>
<tbody>
<row>
<entry align="center">Record execute(InteractionSpec,
Record)</entry>
<entry align="center">not set</entry>
<entry align="center">Record execute(InteractionSpec,
Record)</entry>
</row>
<row>
<entry align="center">Record execute(InteractionSpec,
Record)</entry>
<entry align="center">set</entry>
<entry align="center">boolean execute(InteractionSpec, Record,
Record)</entry>
</row>
<row>
<entry align="center">void execute(InteractionSpec, Record,
Record)</entry>
<entry align="center">not set</entry>
<entry align="center">void execute(InteractionSpec, Record,
Record)</entry>
</row>
<row>
<entry align="center">void execute(InteractionSpec, Record,
Record)</entry>
<entry align="center">set</entry>
<entry align="center">void execute(InteractionSpec, Record,
Record)</entry>
</row>
<row>
<entry align="center">Record execute(InteractionSpec,
RecordCreator)</entry>
<entry align="center">not set</entry>
<entry align="center">Record execute(InteractionSpec,
Record)</entry>
</row>
<row>
<entry align="center">Record execute(InteractionSpec,
RecordCreator)</entry>
<entry align="center">set</entry>
<entry align="center">void execute(InteractionSpec, Record,
Record)</entry>
</row>
<row>
<entry align="center">Record execute(InteractionSpec, Record,
RecordExtractor)</entry>
<entry align="center">not set</entry>
<entry align="center">Record execute(InteractionSpec,
Record)</entry>
</row>
<row>
<entry align="center">Record execute(InteractionSpec, Record,
RecordExtractor)</entry>
<entry align="center">set</entry>
<entry align="center">void execute(InteractionSpec, Record,
Record)</entry>
</row>
<row>
<entry align="center">Record execute(InteractionSpec,
RecordCreator, RecordExtractor)</entry>
<entry align="center">not set</entry>
<entry align="center">Record execute(InteractionSpec,
Record)</entry>
</row>
<row>
<entry align="center">Record execute(InteractionSpec,
RecordCreator, RecordExtractor)</entry>
<entry align="center">set</entry>
<entry align="center">void execute(InteractionSpec, Record,
Record)</entry>
</row>
</tbody>
</tgroup>
</table></para>
</section>
<section id="cci-straight">
<title>Using a CCI <interfacename>Connection</interfacename> and <interfacename>Interaction</interfacename> directly</title>
<para><classname>CciTemplate</classname> also offers the possibility to
work directly with CCI connections and interactions, in the same manner
as <classname>JdbcTemplate</classname> and <classname>JmsTemplate</classname>.
This is useful when you want to perform multiple operations on a CCI
connection or interaction, for example.</para>
<para>The interface <interfacename>ConnectionCallback</interfacename> provides a
CCI <interfacename>Connection</interfacename> as argument, in order to perform
custom operations on it, plus the CCI <interfacename>ConnectionFactory</interfacename>
which the <interfacename>Connection</interfacename> was created with. The latter
can be useful for example to get an associated <interfacename>RecordFactory</interfacename>
instance and create indexed/mapped records, for example.</para>
<programlisting><![CDATA[public interface ConnectionCallback {
Object doInConnection(Connection connection, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException;
}]]></programlisting>
<para>The interface <interfacename>InteractionCallback</interfacename> provides
the CCI <interfacename>Interaction</interfacename>, in order to perform custom
operations on it, plus the corresponding CCI <interfacename>ConnectionFactory</interfacename>.
</para>
<programlisting><![CDATA[public interface InteractionCallback {
Object doInInteraction(Interaction interaction, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException;
}]]></programlisting>
<note>
<para><interfacename>InteractionSpec</interfacename> objects
can either be shared across multiple template calls or newly created
inside every callback method. This is completely up to the DAO implementation.</para>
</note>
</section>
<section id="cci-template-example">
<title>Example for <classname>CciTemplate</classname> usage</title>
<para>In this section, the usage of the <classname>CciTemplate</classname>
will be shown to acces to a CICS with ECI mode, with the IBM CICS ECI
connector.</para>
<para>Firstly, some initializations on the CCI
<interfacename>InteractionSpec</interfacename> must be done to specify which CICS
program to access and how to interact with it.</para>
<programlisting><![CDATA[ECIInteractionSpec interactionSpec = new ECIInteractionSpec();
interactionSpec.setFunctionName("MYPROG");
interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);]]></programlisting>
<para>Then the program can use CCI via Spring's template and specify
mappings between custom objects and CCI <literal>Records</literal>.</para>
<programlisting><![CDATA[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;
}
}]]></programlisting>
<para>As discussed previously, callbacks can be used to work
directly on CCI connections or interactions.</para>
<programlisting><![CDATA[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 {
]]><lineannotation>// do something...</lineannotation><![CDATA[
}
});
}
return output;
}
}]]></programlisting>
<note>
<para>With a <interfacename>ConnectionCallback</interfacename>,
the <interfacename>Connection</interfacename> used will be managed and closed by
the <classname>CciTemplate</classname>, but any interactions created
on the connection must be managed by the callback implementation.</para>
</note>
<para>For a more specific callback, you can implement an
<interfacename>InteractionCallback</interfacename>. The passed-in
<interfacename>Interaction</interfacename> will be managed and closed by the
<classname>CciTemplate</classname> in this case.</para>
<programlisting><![CDATA[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;
}
}]]></programlisting>
<para>For the examples above, the corresponding configuration of the
involved Spring beans could look like this in non-managed mode:</para>
<programlisting><![CDATA[<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>]]></programlisting>
<para>In managed mode (that is, in a J2EE environment), the configuration
could look as follows:</para>
<programlisting><![CDATA[<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>]]></programlisting>
</section>
</section>
<section id="cci-object">
<title>Modeling CCI access as operation objects</title>
<para>The <literal>org.springframework.jca.cci.object</literal> package
contains support classes that allow you to access the EIS in a different
style: through reusable operation objects, analogous to Spring's JDBC
operation objects (see JDBC chapter). This will usually encapsulate the
CCI API: an application-level input object will be 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.</para>
<para><emphasis>Note</emphasis>: This approach is internally based on the
<classname>CciTemplate</classname> class and the <interfacename>RecordCreator</interfacename>
/ <interfacename>RecordExtractor</interfacename> interfaces, reusing the machinery of
Spring's core CCI support.</para>
<section id="cci-object-mapping-record">
<title><classname>MappingRecordOperation</classname></title>
<para><classname>MappingRecordOperation</classname> essentially performs the
same work as <classname>CciTemplate</classname>, but represents a specific,
pre-configured operation as an object. It provides two template methods
to specify how to convert an input object to a input record, and how to
convert an output record to an output object (record mapping):</para>
<itemizedlist>
<listitem>
<para><literal>createInputRecord(..)</literal> to specify how to
convert an input object to an input <interfacename>Record</interfacename></para>
</listitem>
<listitem>
<para><literal>extractOutputData(..)</literal> to specify how to
extract an output object from an output <interfacename>Record</interfacename></para>
</listitem>
</itemizedlist>
<para>Here are the signatures of these methods:</para>
<programlisting><![CDATA[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 { ... }
...
}]]></programlisting>
<para>Thereafter, in order to 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 result:</para>
<programlisting><![CDATA[public abstract class MappingRecordOperation extends EisOperation {
...
public Object execute(Object inputObject) throws DataAccessException {
...
}]]></programlisting>
<para>As you can see, contrary to the <classname>CciTemplate</classname> class,
this <methodname>execute(..)</methodname> method does not have an
<interfacename>InteractionSpec</interfacename> as argument. Instead, the
<interfacename>InteractionSpec</interfacename> is global to the operation.
The following constructor must be used to instantiate an operation
object with a specific <interfacename>InteractionSpec</interfacename>:</para>
<programlisting><![CDATA[InteractionSpec spec = ...;
MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnectionFactory(), spec);
...]]></programlisting>
</section>
<section id="cci-object-mapping-comm-area">
<title><classname>MappingCommAreaOperation</classname></title>
<para>Some connectors use records based on a COMMAREA which represents
an array of bytes containing parameters to send to the EIS and data
returned by it. Spring provides a special operation class for working
directly on COMMAREA rather than on records. The
<classname>MappingCommAreaOperation</classname> class extends the
<classname>MappingRecordOperation</classname> class to provide such special
COMMAREA support. It implicitly uses the <classname>CommAreaRecord</classname>
class as input and output record type, and provides two new methods to
convert an input object into an input COMMAREA and the output COMMAREA
into an output object.</para>
<programlisting><![CDATA[public abstract class MappingCommAreaOperation extends MappingRecordOperation {
...
protected abstract byte[] objectToBytes(Object inObject)
throws IOException, DataAccessException;
protected abstract Object bytesToObject(byte[] bytes)
throws IOException, DataAccessException;
...
}]]></programlisting>
</section>
<section id="cci-automatic-record-gen">
<title>Automatic output record generation</title>
<para>As every <classname>MappingRecordOperation</classname> subclass is
based on CciTemplate internally, the same way to automatically generate
output records as with <classname>CciTemplate</classname> is available.
Every operation object provides a corresponding
<literal>setOutputRecordCreator(..)</literal> method. For further information,
see the section entitled <xref linkend="automatic-output-generation"/>.</para>
</section>
<section id="cci-object-summary">
<title>Summary</title>
<para>The operation object approach uses records in the same manner
as the <classname>CciTemplate</classname> class.</para>
<table frame="all" id="cci-interaction-methods">
<title>Usage of Interaction execute methods</title>
<tgroup cols="3">
<thead>
<row>
<entry align="center"><classname>MappingRecordOperation</classname> method
signature</entry>
<entry align="center"><classname>MappingRecordOperation</classname>
<literal>outputRecordCreator</literal> property</entry>
<entry align="center">execute method called on the CCI
<interfacename>Interaction</interfacename></entry>
</row>
</thead>
<tbody>
<row>
<entry align="center">Object execute(Object)</entry>
<entry align="center">not set</entry>
<entry align="center">Record execute(InteractionSpec,
Record)</entry>
</row>
<row>
<entry align="center">Object execute(Object)</entry>
<entry align="center">set</entry>
<entry align="center">boolean execute(InteractionSpec, Record,
Record)</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section id="cci-objects-mappring-record-example">
<title>Example for <classname>MappingRecordOperation</classname> usage</title>
<para>In this section, the usage of the
<classname>MappingRecordOperation</classname> will be shown to access a
database with the Blackbox CCI connector.</para>
<note>
<para>The original version of this connector is provided by the J2EE SDK
(version 1.3), available from Sun.</para>
</note>
<para>Firstly, some initializations on the CCI
<interfacename>InteractionSpec</interfacename> must be done to specify which SQL
request to execute. In this sample, 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
<classname>Person</classname> class.</para>
<programlisting><![CDATA[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;
}
}]]></programlisting>
<para>Then the application can execute the operation object, with the
person identifier as argument. Note that operation object could be
set up as shared instance, as it is thread-safe.</para>
<programlisting><![CDATA[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;
}
}]]></programlisting>
<para>The corresponding configuration of Spring beans could look
as follows in non-managed mode:</para>
<programlisting><![CDATA[<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>]]></programlisting>
<para>In managed mode (that is, in a J2EE environment), the configuration
could look as follows:</para>
<programlisting><![CDATA[<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>]]></programlisting>
</section>
<section id="cci-objects-mapping-comm-area-example">
<title>Example for <classname>MappingCommAreaOperation</classname> usage</title>
<para>In this section, the usage of the
<classname>MappingCommAreaOperation</classname> will be shown: accessing
a CICS with ECI mode with the IBM CICS ECI connector.</para>
<para>Firstly, the CCI <interfacename>InteractionSpec</interfacename> needs to be
initialized to specify which CICS program to access and how to interact
with it.</para>
<programlisting><![CDATA[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();
}
}
}]]></programlisting>
<para>The abstract <classname>EciMappingOperation</classname> class can
then be subclassed to specify mappings between custom objects and
<literal>Records</literal>.</para>
<programlisting><![CDATA[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));
}
}]]></programlisting>
<para>The corresponding configuration of Spring beans could look
as follows in non-managed mode:</para>
<programlisting><![CDATA[<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>]]></programlisting>
<para>In managed mode (that is, in a J2EE environment), the configuration
could look as follows:</para>
<programlisting><![CDATA[<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>]]></programlisting>
</section>
</section>
<section id="cci-tx">
<title>Transactions</title>
<para>JCA specifies several levels of transaction support for resource adapters.
The kind of transactions that your resource adapter supports is specified
in its <filename>ra.xml</filename> file. There are essentially three options:
none (for example with CICS EPI connector), local transactions (for
example with a CICS ECI connector), global transactions (for example with an
IMS connector).</para>
<programlisting><![CDATA[<connector>
<resourceadapter>
]]><lineannotation>&lt;!-- &lt;transaction-support&gt;NoTransaction&lt;/transaction-support&gt; --&gt;</lineannotation><![CDATA[
]]><lineannotation>&lt;!-- &lt;transaction-support&gt;LocalTransaction&lt;/transaction-support&gt; --&gt;</lineannotation><![CDATA[
<transaction-support>XATransaction</transaction-support>
<resourceadapter>
<connector>]]></programlisting>
<para>For global transactions, you can use Spring's generic transaction
infrastructure to demarcate transactions, with <classname>JtaTransactionManager</classname> as
backend (delegating to the J2EE server's distributed transaction coordinator
underneath).</para>
<para>For local transactions on a single CCI <interfacename>ConnectionFactory</interfacename>,
Spring provides a specific transaction management strategy for CCI, analogous
to the <classname>DataSourceTransactionManager</classname> for JDBC. The CCI API
defines a local transaction object and corresponding local transaction
demarcation methods. Spring's <classname>CciLocalTransactionManager</classname>
executes such local CCI transactions, fully compliant with Spring's generic
<interfacename>PlatformTransactionManager</interfacename> abstraction.</para>
<programlisting><![CDATA[<bean id="eciConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="eis/cicseci"/>
</bean>
<bean id="eciTransactionManager"
class="org.springframework.jca.cci.connection.CciLocalTransactionManager">
<property name="connectionFactory" ref="eciConnectionFactory"/>
</bean>]]></programlisting>
<para>Both transaction strategies can be used with any of Spring's
transaction demarcation facilities, be it declarative or programmatic.
This is a consequence of Spring's generic
<interfacename>PlatformTransactionManager</interfacename> abstraction, which
decouples transaction demarcation from the actual execution strategy.
Simply switch between <classname>JtaTransactionManager</classname> and
<classname>CciLocalTransactionManager</classname> as needed, keeping
your transaction demarcation as-is.</para>
<para>For more information on Spring's transaction facilities, see the
chapter entitled <xref linkend="transaction"/>.</para>
</section>
</chapter>