![]() |
![]() |
|
|
Developing a Service Adapter
Service adapters receive an XML request document from a client and invoke the associated function in the underlying EIS. They are consumers of messages and may or may not provide a response. Service adapters perform the following four functions:
This section contains information on the following subjects:
J2EE-Compliant Adapters Not Specific to WebLogic Integration
The steps outlined in this chapter are directed primarily at developing adapters for use with WebLogic Integration. You can also use the ADK to develop adapters that can be used outside of the WebLogic Integration environment by following the steps herein, but modifying them as described in Creating an Adapter Not Specific to WebLogic Integration.
Service Adapters in the Run-Time Environment
Figure 6-1 and Figure 6-2 show the processes executed when a service adapter is used in the run-time environment. Figure 6-1 shows an asynchronous service adapter while Figure 6-2 shows a synchronous adapter.
Figure 6-1 An Asynchronous Service Adapter in the Run-Time Environment
Figure 6-2 Synchronous Service Adapter in the Run-Time Environment
The Flow of Events
Figure 6-3 outlines the steps required to develop a Service Adapter.
Figure 6-3 Service Adapter Flow of Events
Step 1: Development Considerations
You will need to consider the items listed below before commencing with service adapter development. The Adapter Setup Worksheet will provide much of this information. See Adapter Setup Worksheet.
You need to identify the EIS and the type of service required for this adapter; that is, based upon your knowledge of the EIS, you must identify the interface to the back-end functionality.
You need to determine the "expensive" connection object required to invoke a function within the EIS. The expensive connection object is a resource required to communicate with the EIS and requires the allocation of system resources; for example, a socket connection or DBMS connection. A valuable asset of J2EE Connector Architecture is that the application server provides pooling of these objects. Therefore, you must determine this object for your adapter, as it will need to be pooled by the application server.
You need to consider and understand how to pass connection authentication across the connection request path. To do this, your adapter will need to implement a connectionRequestInfo class. The ADK provides the class ConnectionRequestInfoMap to map authorization information, such as username and password, to the connection to facilitate ConnectionRequestInfo implementation.
The ADK conforms to the J2EE Connector Architecture Specification 1.0. For more information on connection architecture security, please refer to "Security" in that document. Go to http://java.sun.com/j2ee/
to download the specification.The J2EE Connector Architecture Specification 1.0 will download as a .pdf file.
You need to identify which type of transaction demarcation support to implement with the adapter:
Note: For more information on transaction demarcation support, please see Transaction Demarcation or:
http://java.sun.com/j2ee/blueprints/transaction_
management/platform/index.html
Step 2: Configuring the Development Environment
This step describes the processes you must complete to prepare your computer for adapter development.
Note: The steps described below can be completed simply be running the GenerateAdapterTemplate utility. For more information on using this utility, see Creating a Custom Development Environment.
Step 2a: Set Up the File Structure
Installing WebLogic Integration creates the file structure necessary not only to run an adapter, but also to use the ADK. The ADK files appear under WLI_HOME/adapters/, where WLI_HOME is the directory where you installed WebLogic Integration. You need to verify that, upon installation, the necessary directories and files appear in your WLI_HOME directory. The file structure that follows under WLI_HOME is described in Table 6-1:
Modifying the Directory Structure
When you clone a development tree by using GenerateAdapterTemplate, the file paths and files under adapters/sample are automatically cloned and updated to reflect the new development environment. The changes are reflected in the file WLI_HOME/adapters/ADAPTER/docs/api/index.html (where ADAPTER is the name of the new development directory). This file also contains code that you can copy and paste into the config.xml file for the new adapter that will set up WebLogic Integration to host the adapter.
Step 2b: Assign the Adapter Logical Name
Next, you need to assign the adapter's logical name. By convention, this name is comprised of the vendor name, the type of EIS connected to the adapter, and the version number of the EIS and is expressed as vendor_EIS-type_EIS version. For example:
BEA_WLS_SAMPLE_ADK
For more information on the adapter logical name, see Adapter Logical Name.
Step 2c: Setting Up the Build Process
The ADK employs a build process based upon Ant, a 100% pure Java-based build tool. For more information on Ant, please see Ant-Based Build Process. For more information on using Ant, see:
http://jakarta.apache.org/ant/index.html
.The sample adapter shipped with the ADK (located in WLI_HOME/adapters/sample/project) contains the file build.xml. This is the Ant build file for the sample adapter. It contains the tasks needed to build a J2EE-compliant adapter. Running the GenerateAdapterTemplate utility to clone a development tree for your adapter creates a build.xml file specifically for that adapter. This will free you from having to customize the sample build.xml and will ensure that the code is correct. For information on using the GenerateAdapterTemplate utility, see Creating a Custom Development Environment.
The Manifest File
Among the files created by GenerateAdapterTemplate is MANIFEST.MF, the manifest file. This file contains classloading instructions for each component that uses the file. A manifest file is created for each /META-INF directory except ear/META-INF.
Listing 6-1 shows an example of the manifest file included with the sample adapter.
Listing 6-1 Manifest File Example
Manifest-Version: 1.0
Created-By: BEA Systems, Inc.
Class-Path: BEA_WLS_SAMPLE_ADK.jar adk.jar bea.jar log4j.jar logtoolkit.jar xmltoolkit.jar wlai-common.jar wlai-ejb-client.jar xcci.jar
The first line of the file contains version information and the second line shows vendor information. The third line contains the relevant classpath or classloading instructions. The Class-Path property contains references to resources required by the component. It identifies the shared .jar files, which are separated by spaces. You must ensure that these .jar files are included in the shared area of the .ear file (see Enterprise Archive (.ear) Files).
Note: When the filename MANIFEST.MF appears in a .war file, it must appear in uppercase letters. If it does not, Unix will not recognize it and an error will occur.
build.xml Components
If you open build.xml and review its components, you will better understand how this file works. This section describes the prominent elements of build.xml.
Note: The following examples are taken from the sample adapter, not a cloned version thereof.
<project name='BEA_WLS_SAMPLE_ADK' default='all' basedir='.'>
sets the name attribute of the root project element.
Listing 6-2 Setting Archive File Names
<property name='JAR_FILE' value='BEA_WLS_SAMPLE_ADK.jar'/>
<property name='RAR_FILE' value='BEA_WLS_SAMPLE_ADK.rar'/>
<property name='WAR_FILE' value='BEA_WLS_SAMPLE_ADK_Web.war'/>
<property name='EVENTROUTER_JAR_FILE' value='BEA_WLS_ SAMPLE_ADK_EventRouter.jar'/>
<property name='EVENTROUTER_WAR_FILE' value='BEA_WLS_ SAMPLE_ADK_EventRouter.war'/>
<property name='EAR_FILE' value='BEA_WLS_SAMPLE_ADK.ear'/>
Listing 6-3 Standard ADK Properties
<property name='ADK' value='${WLI_LIB_DIR}/adk.jar'/>
<property name='ADK_WEB' value='${WLI_LIB_DIR}/adk-web.jar'/>
<property name='ADK_TEST' value='${WLI_LIB_DIR}/adk-test.jar'/>
<property name='ADK_EVENTGENERATOR' value='${WLI_LIB_DIR}/ adk-eventgenerator.jar'/>
<property name='BEA' value='${WLI_LIB_DIR}/bea.jar'/>
<property name='LOGTOOLKIT' value='${WLI_LIB_DIR}/ logtoolkit.jar'/>
<property name='WEBTOOLKIT' value='${WLI_LIB_DIR}/ webtoolkit.jar'/>
<property name='WLAI_COMMON' value='${WLI_LIB_DIR}/ wlai-common.jar'/>
<property name='WLAI_EJB_CLIENT'value='${WLI_LIB_DIR}/ wlai-ejb-client.jar'/>
<property name='WLAI_EVENTROUTER' value='${WLI_LIB_DIR}/ wlai-eventrouter.jar'/>
<property name='WLAI_EVENTROUTER_CLIENT' value='${WLI_LIB_DIR}/ wlai-eventrouter-client.jar'/>
<property name='WLAI_SERVLET_CLIENT' value='${WLI_LIB_DIR}/ wlai-servlet-client.jar'/>
<property name='XMLTOOLKIT' value='${WLI_LIB_DIR}/ xmltoolkit.jar'/>
<property name='XCCI' value='${WLI_LIB_DIR}/xcci.jar'/>
To the list in Listing 6-3, you can add any additional .jar files and/or classes that are specific to your adapter.
Listing 6-4 Sample for Setting the Classpath
<path id='CLASSPATH'>
<pathelement location='${SRC_DIR}'/>
<pathelement path='${ADK}:${ADK_EVENTGENERATOR}: ${ADK_WEB}:${ADK_TEST}:${BEA}:${LOGTOOLKIT}:${WEBTOOLKIT}
:${WLAI_EJB_CLIENT}:${WLAI_COMMON}:${WLAI_EVENTROUTER}:
${XCCI}: ${XMLTOOLKIT}'/>
<pathelement path='${XMLX_JAR}'/>
<pathelement path='${LOG4J_JAR}:${JUNIT}'/>
<pathelement path='${WEBLOGIC_JAR}:${env.BEA_HOME}'/>
</path>
To this information, you can add code that will produce the following:
Listing 6-5 Sample of Calling All Binaries and Archives
<target name='release' depends='all, apidoc'/>
<!-- This target produces all the binaries and archives
or the adapter -->
<target name='all' depends='ear'/>
<target name='release' depends='all,apidoc'/>
Listing 6-6 Sample version_info File
<!-- This target produces a version_info file for inclusion into archives -->
<target name='version_info'>
<java classname='GenerateVersionInfo'>
<arg line='-d${basedir}'/>
<classpath>
<pathelement path='${WLI_HOME}/adapters/utils: ${WEBLOGIC_JAR}:${XMLX_JAR}'/>
</classpath>
</java>
</target>
Listing 6-7 Sample Code Setting .jar File Contents
<target name='jar' depends='packages,version_info'>
<delete file='${LIB_DIR}/${JAR_FILE}'/>
<mkdir dir='${LIB_DIR}'/>
<jar jarfile='${LIB_DIR}/${JAR_FILE}'>
Listing 6-8 Sample Code for Including the "Includes" List
<fileset dir='${SRC_DIR}'
includes='sample/cci/*.class,sample/spi/*.class,
sample/eis/*. class,*.xml,*.properties'/>
Listing 6-9 Setting .jar File Version Information
<!-- Include version information about the JAR file -->
<fileset dir='${basedir}'
includes='version_info.xml'/>
</jar>
Listing 6-10 Sample Code for Creating the Connection Architecture .rar File
<target name='rar' depends='jar'>
<delete file='${LIB_DIR}/${RAR_FILE}'/>
<mkdir dir='${LIB_DIR}'/>
<jar jarfile='${LIB_DIR}/${RAR_FILE}' manifest='${SRC_DIR}/rar/ META-INF/MANIFEST.MF'>
<fileset dir='${SRC_DIR}/rar'includes='META-INF/ra.xml, META-INF/weblogic-ra.xml' excludes=
'META-INF/MANIFEST.MF'/>
</jar>
</target>
Listing 6-11 Sample Code Producing the .war File
<target name='war' depends='jar'>
<!-- Clean-up existing environment -->
<delete file='${LIB_DIR}/${WAR_FILE}'/>
<copy file='${WLI_HOME}/adapters/src/war/WEB-INF/taglibs/ adk.tld' todir='${SRC_DIR}/war/WEB-INF/taglibs'/>
<java classname='weblogic.jspc' fork='yes'>
<arg line='-d ${SRC_DIR}/war -webapp ${SRC_DIR}/
war -compileAll -depend'/>
<classpath refid='CLASSPATH'/>
</java>
<!-- The first adapter should compile the common ADK JSPs -->
<java classname='weblogic.jspc' fork='yes'>
<arg line='-d ${WLI_HOME}/adapters/src/war -webapp ${WLI_HOME}/adapters/src/war -compileAll
-depend'/>
<classpath refid='CLASSPATH'/>
</java>
<war warfile='${LIB_DIR}/${WAR_FILE}' webxml='${SRC_DIR}/war/ WEB-INF/web.xml' manifest='${SRC_DIR}/war/META-INF/ MANIFEST.MF'>
<!--
IMPORTANT! Exclude the WEB-INF/web.xml file from
the WAR as it already gets included via the webxml attribute above
-->
<fileset dir="${SRC_DIR}/war" >
<patternset >
<include name="WEB-INF/weblogic.xml"/>
<include name="**/*.html"/>
<include name="**/*.gif"/>
</patternset>
</fileset>
<!--
IMPORTANT! Include the ADK design time framework into the adapter's design time Web application.
-->
<fileset dir="${WLI_HOME}/adapters/src/war" >
<patternset >
<include name="**/*.css"/>
<include name="**/*.html"/>
<include name="**/*.gif"/>
<include name="**/*.js"/>
</patternset>
</fileset>
<!-- Include classes from the adapter that support the design time UI -->
<classes dir='${SRC_DIR}' includes='sample/web/*.class'/>
<classes dir='${SRC_DIR}/war'includes='**/*.class'/>
<classes dir='${WLI_HOME}/adapters/src/war' includes= '**/*.class'/>
<!--
Include all JARs required by the Web application under the WEB-INF/lib directory of the WAR file that are not shared in the EAR
-->
<lib dir='${WLI_LIB_DIR}' includes='adk-web.jar, webtoolkit.jar'/>
</war>
</target>
Listing 6-12 Sample Code to Include .jar Files Required by Web Application
<lib dir='${WLI_LIB_DIR}' includes='adk-web.jar, webtoolkit.jar'/>
Listing 6-13 Sample Code to Include .ear File
<target name='ear' depends='rar,eventrouter_jar,war'>
<delete file='${LIB_DIR}/${EAR_FILE}'/>
<!-- include an eventrouter that shares the jars
rather than includes them-->
<delete file='${LIB_DIR}/${EVENTROUTER_WAR_FILE}'/>
<delete dir='${SRC_DIR}/eventrouter/WEB-INF/lib'/>
<war warfile='${LIB_DIR}/${EVENTROUTER_WAR_FILE} 'webxml='${SRC_DIR}/eventrouter/WEB-INF/web.xml
'manifest='${SRC_DIR}/eventrouter/META-INF/
MANIFEST.MF'>
<fileset dir='${basedir}' includes='version_info.xml'/>
<fileset dir="${SRC_DIR}/eventrouter" >
<patternset >
<exclude name="WEB-INF/web.xml"/>
<exclude name="META-INF/*.mf"/>
</patternset>
</fileset>
<lib dir='${LIB_DIR}' includes='${EVENTROUTER_JAR_
FILE}'/>
<lib dir='${WLI_LIB_DIR}'includes= 'adk-eventgenerator.jar,wlai-eventrouter.jar,
wlai-servlet-client.jar'/>
</war>
<jar jarfile='${LIB_DIR}/${EAR_FILE}'>
<fileset dir='${basedir}' includes='version_info.xml'/>
<fileset dir='${SRC_DIR}/ear' includes= 'application.xml'/>
<fileset dir='${LIB_DIR}'includes='${JAR_FILE},
${RAR_FILE}, ${WAR_FILE},${EVENTROUTER_WAR_FILE}'/>
<fileset dir='${WLI_LIB_DIR}'includes='adk.jar,bea.jar, logtoolkit.jar,xcci.jar,xmltoolkit.jar'/>
<fileset dir='${WLI_LIB_DIR}'includes='log4j.jar,
wlai-common.jar,wlai-ejb-client.jar'/>
</jar>
<delete file='${LIB_DIR}/${EVENTROUTER_WAR_FILE}'/>
<delete file='${LIB_DIR}/${EVENTROUTER_JAR_FILE}'/>
<delete file='${LIB_DIR}/${WAR_FILE}'/>
<delete file='${LIB_DIR}/${RAR_FILE}'/>
</target>
Within the .ear target, in Listing 6-14, is the EventRouter specific to the .ear deployment. This event router cannot be deployed by itself. Listing 6-14 shows how to include the event router.
Listing 6-14 Sample Code for Including .ear-specific EventRouter
<delete file='${LIB_DIR}/${EVENTROUTER_WAR_FILE}'/>
<delete dir='${SRC_DIR}/eventrouter/WEB-INF/lib'/>
<war warfile='${LIB_DIR}/${EVENTROUTER_WAR_FILE} 'webxml='${SRC_DIR}/eventrouter/WEB-INF/web.xml
'manifest='${SRC_DIR}/eventrouter/META-INF/
MANIFEST.MF'>
<fileset dir='${basedir}' includes='version_info.xml'/>
<fileset dir="${SRC_DIR}/eventrouter" >
<patternset >
<exclude name="WEB-INF/web.xml"/>
<exclude name="META-INF/*.mf"/>
</patternset>
</fileset>
<lib dir='${LIB_DIR}' includes='${EVENTROUTER_
JAR_FILE}'/>
<lib dir='${WLI_LIB_DIR}'includes='adk-eventgenerator. jar,wlai-eventrouter.jar,wlai-servlet-client.jar'/>
</war>
Within the .ear target, in Listing 6-14, you will also find all common or shared jars, as shown in Listing 6-15.
Listing 6-15 Sample Code Showing Inclusion of Common or Shared .jar Files
<jar jarfile='${LIB_DIR}/${EAR_FILE}'>
<fileset dir='${basedir}' includes='version_info.xml'/>
<fileset dir='${SRC_DIR}/ear' includes='application.xml'/>
<fileset dir='${LIB_DIR}'includes='${JAR_FILE},${RAR_FILE},
${WAR_FILE},${EVENTROUTER_WAR_FILE}'/>
<fileset dir='${WLI_LIB_DIR}'includes='adk.jar,bea.jar,
logtoolkit.jar,xcci.jar,xmltoolkit.jar'/>
<fileset dir='${WLI_LIB_DIR}'includes='log4j.jar,
wlai-common.jar,wlai-ejb-client.jar'/>
</jar>
Listing 6-16 Sample Code for Compiling Java Source
<target name='packages'>
<echo message='Building ${ant.project.name}...'/>
<javac srcdir='${SRC_DIR}'>
<classpath refid='CLASSPATH'/>
</javac>
</target>
Listing 6-17 Sample Code Constructing the EventRouter .jar File
<target name='eventrouter_jar' depends='packages,version_info'>
<delete file='${LIB_DIR}/${EVENTROUTER_JAR_FILE}'/>
<jar jarfile='${LIB_DIR}/${EVENTROUTER_JAR_FILE}'>
<fileset dir='${SRC_DIR}'
includes='sample/event/*.class'/>
<fileset dir='${basedir}'
includes='version_info.xml'/>
</jar>
</target>
Listing 6-18 Sample Code Producing the EventRouter Target for Stand-Alone Deployment
<target name='eventrouter_war' depends='jar,eventrouter_jar'>
<delete file='${LIB_DIR}/${EVENTROUTER_WAR_FILE}'/>
<delete dir='${SRC_DIR}/eventrouter/WEB-INF/lib'/>
<war warfile='${LIB_DIR}/${EVENTROUTER_WAR_FILE}'webxml=
'${SRC_DIR}/eventrouter/WEB-INF/web.xml'>
<fileset dir='${basedir}' includes='version_info.xml'/>
<fileset dir='${SRC_DIR}/eventrouter' excludes=
'WEB-INF/web.xml'/>
<lib dir='${LIB_DIR}' includes='${JAR_FILE},
${EVENTROUTER_JAR_FILE}'/>
<lib dir='${WLI_LIB_DIR}'includes='adk.jar,
adk-eventgenerator.jar,bea.jar,logtoolkit.jar,
wlai-common.jar,wlai-ejb-client.jar,wlai-
eventrouter.jar,wlai-servlet-client.jar,
xmltoolkit.jar'/>
<lib dir='${WLI_LIB_DIR}' includes='log4j.jar'/>
</war>
</target>
Listing 6-19 Sample Code for Generating Javadocs
<target name='apidoc'>
<mkdir dir='${DOC_DIR}'/>
<javadoc sourcepath='${SRC_DIR}'
destdir='${DOC_DIR}'
packagenames='sample.*'
author='true'
version='true'
use='true'
overview='${SRC_DIR}/overview.html'
windowtitle='WebLogic BEA_WLS_SAMPLE_ADK Adapter
API Documentation'
doctitle='WebLogic BEA_WLS_SAMPLE_ADK Adapter
API Documentation'
header='WebLogic BEA_WLS_SAMPLE_ADK Adapter'
bottom='Built using the WebLogic Adapter
Development Kit (ADK)'>
<classpath refid='CLASSPATH'/>
</javadoc>
</target>
Listing 6-20 Sample Code for Including Clean-Up Code
<target name='clean' depends='clean_release'/>
<target name='clean_release' depends='clean_all,clean_apidoc'/>
<target name='clean_all'depends='clean_ear,clean_rar,clean_war,
clean_eventrouter_war,clean_test'/>
<target name='clean_test'>
<delete file='${basedir}/BEA_WLS_SAMPLE_ADK.log'/>
<delete file='${basedir}/mcf.ser'/>
</target>
<target name='clean_ear' depends='clean_jar'>
<delete file='${LIB_DIR}/${EAR_FILE}'/>
</target>
<target name='clean_rar' depends='clean_jar'>
<delete file='${LIB_DIR}/${RAR_FILE}'/>
</target>
<target name='clean_war' depends='clean_jar'>
<delete file='${LIB_DIR}/${WAR_FILE}'/>
<delete dir='${WLI_HOME}/adapters/src/war/jsp_servlet'/>
</target>
<target name='clean_jar' depends='clean_packages,clean_version_
info'>
<delete file='${LIB_DIR}/${JAR_FILE}'/>
</target>
<target name='clean_eventrouter_jar'>
<delete file='${LIB_DIR}/${EVENTROUTER_JAR_FILE}'/>
</target>
<target name='clean_eventrouter_war' depends='clean_
eventrouter_jar'>
<delete file='${LIB_DIR}/${EVENTROUTER_WAR_FILE}'/>
</target>
<target name='clean_version_info'>
<delete file='${basedir}/version_info.xml'/>
</target>
<target name='clean_packages'>
<delete>
<fileset dir='${SRC_DIR}' includes='**/*.class'/>
</delete>
</target>
<target name='clean_apidoc'>
<delete dir='${DOC_DIR}'/>
</target>
</project>
Step 2d: Create the Message Bundle
Any message destined for the end-user should be placed in a message bundle. The message bundle is simply a .properties text file that contains key=value pairs that allow you to internationalize messages. When a locale and national language are specified at run time, the contents of the message is interpreted, based upon the key=value pair, and the message is presented to the user in the correct language for his or her locale.
For instructions on creating a message bundle, please refer to the JavaSoft tutorial on internationalization at:
http://java.sun.com/docs/books/tutorial/i18n/index.html
Step 3: Implementing the SPI
The Service Provider Interface (SPI) contains the objects that provide and manage connectivity to the EIS, establish transaction demarcation, and provide a framework for service invocation. All J2EE-compliant adapters must provide an implementation for these interfaces in the javax.resource.spi package.
How to Use this Section
This section (Step 3: Implementing the SPI) contains descriptions of the interfaces you can use to implement the SPI. A minimum of three interfaces are necessary to complete the task (see Basic SPI Implementation). Each of these are described in detail, followed by a discussion of how they were extended in the sample adapter included with the ADK.
Following the three required interfaces, the additional interfaces are described in detail, including information regarding why you might use them and how they benefit an adapter.
Basic SPI Implementation
To implement the SPI for your adapter, you need to extend at least these three interfaces:
Ideally, you will implement these interfaces in the order specified above.
In addition to these three interfaces, you can implement any of the other interfaces described in this step, as your adapter needs dictate.
ManagedConnectionFactory
javax.resource.spi.ManagedConnectionFactory
ManagedConnectionFactory instance is a factory of both ManagedConnection and EIS-specific connection factory instances. This interface supports connection pooling by providing methods for matching and creating a ManagedConnection instance.
Transaction Demarcation
A critical component of the ManagedConnectionFactory is transaction demarcation. You will need to determine which statements in your program are included in a single transaction. J2EE defines a transaction management contract between an application server and an adapter (and its underlying resource manager). The transaction management contract has two parts, depending of the type of transaction:
XA-compliant Transaction
A javax.transaction.xa.XAResource-based contract occurs between a transaction manager and a resource manager in a distributed transaction processing (DTP) environment. A JDBC driver or a JMS provider implements this interface to support association between a global transaction and a database or message service connection.
The XAResource interface can be supported by any transactional resource that is intended for use by application programs in an environment where transactions are controlled by an external transaction manager; for example a database management system where an application accesses data through multiple database connections. Each database connection is enlisted with the transaction manager as a transactional resource. The transaction manager obtains an XAResource for each connection participating in a global transaction. The transaction manager uses the start() method to associate the global transaction with the resource; it uses the end() method to disassociate the transaction from the resource. The resource manager associates the global transaction to all work performed on its data between the start() and end() method invocation.
At transaction commit time, the resource managers are informed by the transaction manager to prepare, commit, or rollback a transaction according to the two-phase commit protocol.
Local Transaction
A local transaction management contract occurs when an adapter implements the javax.resource.spi.LocalTransaction interface to provide support for local transactions that are performed on the underlying resource manager. These contracts enable an application server to provide the infrastructure and run-time environment for transaction management. Application components rely on this transaction infrastructure to support their component-level transaction model.
For more information on transaction demarcation support, please refer to:
http://java.sun.com/j2ee/blueprints/transaction_management/platform/index.html
ADK Implementations
The ADK provides an abstract foundation for an adapter, the AbstractManagedConnectionFactory. This foundation provides the following feature:
There are several key methods that you must supply implementations for. The following paragraphs describe these methods.
createConnectionFactory()
createConnectionFactory(), shown in Listing 6-21, is responsible for constructing the factory for application-level connection handles for the adapter. In other words, clients of your adapter will use the object returned by this method to obtain a connection handle to the EIS.
If the adapter supports a CCI interface, it is recommended that you return an instance of com.bea.adapter.cci.ConnectionFactoryImpl or an extension of this class. The key to implementing this method correctly is to propagate the ConnectionManager, LogContext, and ResourceAdapterMetaData into the client API.
Listing 6-21 createConnectionFactory() Example
protected Object
createConnectionFactory(ConnectionManager connectionManager,
String strAdapterName,
String strAdapterDescription,
String strAdapterVersion,
String strVendorName)
throws ResourceException
createManagedConnection()
createManagedConnection(), shown in Listing 6-22, is responsible for constructing a ManagedConnection instance for your adapter. The ManagedConnection instance encapsulates the expensive resources needed to communicate with the EIS. This method is called by the ConnectionManager when it determines a new ManagedConnection is required to satisfy a client's request. A common design pattern with adapters is to open the resources needed to communicate with the EIS in this method and then pass the resources into a new ManagedConnection instance.
Listing 6-22 createManagedConnection() Example
public ManagedConnection
createManagedConnection(Subject subject, ConnectionRequestInfo
info)
throws ResourceException
checkState()
checkState() gets called by the AbstractManagedConnectionFactory before it attempts to perform any of its factory responsibilities. Use this method to verify that all members that need to be initialized before the ManagedConnectionFactory can perform its SPI responsibilities have been initialized correctly. Implement this method as shown here:
protected boolean checkState()
equals()
equals() tests the object argument for equality. It is important to implement this method correctly as it is used by the ConnectionManager for managing the connection pools. This method should include all important members in its equality comparison. Implement this method as shown here:
public boolean equals(Object obj)
hashCode()
hashCode() provides a hash code for the factory. It is also used by the ConnectionManager for managing the connection pools. Consequently, this method should generate a hashCode based upon properties that determine the uniqueness of the object. Implement this method as shown here:
public int hashCode()
matchManagedConnections()
Lastly, the ManagedConnectionFactory must supply an implementation of the matchManagedConnections() method. The AbstractManagedConnectionFactory provides an implementation of the matchManagedConnections() method that relies upon the compareCredentials() method on AbstractManagedConnection.
In order to provide logic that will match managed connections, you will need to override AbstractManagedConnection's compareCredentials() method. This method is invoked when the ManagedConnectionFactory attempts to match a connection with a connection request for the ConnectionManager.
Currently, AbstractManagedConnectionFactory's implementation extracts a PasswordCredential from the supplied Subject/ConnectionRequestInfo parameters. If both parameters are null, this method returns true because it has already been established that the ManagedConnectionFactory for this instance is correct. Listing 6-23 shows this implementation:
Listing 6-23 compareCredentials() Implementation
public boolean compareCredentials(Subject subject,
ConnectionRequestInfo info)
throws ResourceException
{
ILogger logger = getLogger();
Next, you need to extract a PasswordCredential from either the JAAS Subject or the SPI ConnectionRequestInfo using the ADK's ManagedConnectionFactory. An example is shown in Listing 6-24:
Listing 6-24 Extracting a PasswordCredential
PasswordCredential pc = getFactory().
getPasswordCredential(subject, info);
if (pc == null)
{
logger.debug(this.toString() + ": compareCredentials
In the example shown in Listing 6-24, JAAS Subject and ConnectionRequestInfo are null, which assumes a match. This method will not get invoked unless it has already been established that the factory for this instance is correct. Consequently, if the Subject and ConnectionRequestInfo are both null, then the credentials match by default; therefore, the result of pinging this connection determines the outcome of the comparison. Listing 6-25 shows how to programmatically ping the connection.
Listing 6-25 Pinging a Connection
return ping();
}
boolean bUserNameMatch = true;
String strPcUserName = pc.getUserName();
if (m_strUserName != null)
{
logger.debug(this.toString() + ": compareCredentials >>> comparing
my username ["+m_strUserName+"] with client username
["+strPcUserName+"]");
Next, you need to see if the user supplied in either the Subject or the ConnectionRequestInfo is the same as our user. We do not support re-authentication in this adapter, so if they do not match, this instance cannot satisfy the request. The following line of code does that:
bUserNameMatch = m_strUserName.equals(strPcUserName);
If usernames match, ping the connection to determine if this is still a good connection. Otherwise, there is no match and no reason to ping. The following line of code does that:
return bUserNameMatch ? ping() : false;
Explanation of the Implementation
Under a managed scenario, the application server invokes the matchManagedConnections() method on the ManagedConnectionFactory for an adapter. The specification does not indicate how the application server determines which ManagedConnectionFactory to use to satisfy a connection request. The ADKs AbstractManagedConnectionFactory implements matchManagedConnections(). The first step in this implementation is to compare "this" (that is, the ManagedConnectionFactory instance on which the ConnectionManager invoked matchManagedConnections) to the ManagedConnectionFactory on each ManagedConnection in the set supplied by the application server. For each ManagedConnection in the set that has the same ManagedConnectionFactory, the implementation invokes the compareCredentials() method. This method allows each ManagedConnection object to determine if it can satisfy the request.
matchManagedConnections() gets called by the ConnectionManager (as shown in Listing 6-26) to try to find a valid connection in the pool it is managing. If this method returns null, then the ConnectionManager will allocate a new connection to the EIS via a call to createManagedConnection().
Listing 6-26 matchManagedConnections() Method Implementation
public ManagedConnection
matchManagedConnections(Set connectionSet,
Subject subject,
ConnectionRequestInfo info)
throws ResourceException
This class uses the following approach to matching a connection:
AbstractManagedConnectionFactory Properties Required at Deployment
To use the base implementation of AbstractManagedConnectionFactory, you need to provide the following properties at deployment time:
Table 6-2 AbstractManagedConnectionFactory Properties
Other Key ManagedConnectionFactory Features in the ADK
In the ADK sample adapter, the class sample.spi.ManagedConnectionFactoryImpl is provided. This class extends AbstractManagedConnectionFactory. Use this class as an example of how to extend the ADK's base class.
For the complete sample adapter ManagedConnectionFactory implementation code listing, see:
WLI_HOME/adapters/sample/src/sample/spi/
ManagedConnectionFactoryImpl.java
ManagedConnection
javax.resource.spi.ManagedConnection
The ManagedConnection object is responsible for encapsulating all expensive resources needed to establish connectivity to the EIS. A ManagedConnection instance represents a physical connection to the underlying EIS. ManagedConnection objects are pooled by the application server in a managed environment.
ADK Implementation
The ADK provides an abstract implementation of ManagedConnection. The base class provides logic for managing connection event listeners and multiple application-level connection handles per ManagedConnection instance.
When implementing the ManagedConnection interface, you need to determine the transaction demarcation support provided by the underlying EIS. For more information on transaction demarcation, see Transaction Demarcation.
The ADK provides AbstractManagedConnection, an abstract implementation for the javax.resource.spi.ManagedConnection interface that:
The sample adapter that comes with the ADK includes ManagedConnectionImpl, which extends AbstractManagedConnection. For the complete sample adapter ManagedConnection implementation code listing, see:
WLI_HOME/adapters/sample/src/sample/spi/
ManagedConnectionFactoryImpl.java
ManagedConnectionMetaData
javax.resource.spi.ManagedConnectionMetaData
The ManagedConnectionMetaData interface provides information about the underlying EIS instance associated with a ManagedConnection instance. An application server uses this information to get run-time information about a connected EIS instance.
ADK Implementation
The ADK provides AbstractManagedConnectionMetaData, an abstract implementation of the javax.resource.spi.ManagedConnectionMetaData and javax.resource.cci.ConnectionMetaData interfaces that:
The sample adapter that comes with the ADK includes ConnectionMetaDataImpl, which extends AbstractManagedConnectionMetaData. For the complete code listing, see:
WLI_HOME/adapters/sample/src/sample/spi/
ConnectionMetaDataImpl.java
ConnectionEventListener
javax.resource.spi.ConnectionEventListener
The ConnectionEventListener interface provides an event callback mechanism that enables an application server to receive notifications from a ManagedConnection instance.
ADK Implementation
The ADK provides two concrete implementations of ConnectionEventListener:
In most cases, the implementations provided by the ADK are sufficient; you should not need to provide your own implementation of this interface.
ConnectionManager
javax.resource.spi.ConnectionManager
The ConnectionManager interface provides a hook for the adapter to pass a connection request to the application server.
ADK Implementation
The ADK provides a concrete implementation of this interface, com.bea.adapter.spi.NonManagedConnectionManager. This implementation provides a basic connection manager for adapters running in a non-managed environment. In a managed environment, this interface is provided by the application server. In most cases, you can use the implementation provided by the ADK.
NonManagedConnectionManager is a concrete implementation of the javax.resource.spi.ConnectionManager interface. It serves as the ConnectionManager in the non-managed scenario for an adapter; it does not provide any connection pooling or any other quality of service.
ConnectionRequestInfo
javax.resource.spi.ConnectionRequestInfo
The ConnectionRequestInfo interface enables an adapter to pass its own request specific data structure across the connection request flow. An adapter extends the empty interface to support its own data structures for a connection request.
ADK Implementation
The ADK provides a concrete implementation of this interface called ConnectionRequestInfoMap. This is a concrete implementation of the javax.resource.spi.ConnectionRequestInfo interface and provides a java.util.Map interface to such connection request information as username and password.
LocalTransaction
javax.resource.spi.LocalTransaction
The LocalTransaction interface provides support for transactions that are managed internal to an EIS resource manager, and do not require an external transaction manager.
ADK Implementation
The ADK provides an abstract implementation of this interface called AbstractLocalTransaction. This implementation allows you to focus on implementing the EIS-specific aspects of a LocalTransaction. This implementation:
Step 4: Implementing the CCI
The client interface allows a J2EE-compliant application to connect to and access back-end systems. The client interface manages the flow of data between the client application and the back-end system and does not have any visibility into what either the container or the application server are doing with the adapter. The client interface specifies the format of the request and response records for a given interaction with the EIS.
First, you must determine if your adapter must support the J2EE-compliant Common Client Interface (CCI). Although not a requirement in the current J2EE specification, it is likely to be a requirement in a later version. Consequently, the ADK focuses on helping you implement a CCI interface for your adapter.
How to Use this Section
This section (Step 4: Implementing the CCI) describes some of the interfaces you can use to implement the CCI. A minimum of two interfaces are necessary to complete the task (see Basic CCI Implementation). Each of these is described in detail, followed by a discussion of how they were extended in the sample adapter included with the ADK.
Following the two required interfaces, the additional interfaces are described in detail, including information regarding why you might use them and what benefit they provide to an adapter.
Basic CCI Implementation
To implement the CCI for your adapter, you need to extend at least these two interfaces:
Ideally, you will implement these interfaces in the order specified above.
In addition to these interfaces, you can implement any of the other interfaces described in this step, as your adapter needs dictate. These interfaces are:
Connection
javax.resource.cci.Connection
A Connection represents an application-level handle that is used by a client to access the underlying physical connection. The actual physical connection associated with a Connection instance is represented by a ManagedConnection instance.
A client gets a Connection instance by using the getConnection() method on a ConnectionFactory instance. A Connection can be associated with zero or more Interaction instances.
ADK Implementation
The ADK provides an abstract implementation of this interface called AbstractConnection. This interface provides the following functionality:
You will need to extend this class by providing an implementation for:
public Interaction createInteraction()
throws ResourceException
This method creates an interaction associated with this connection. An interaction enables an application to execute EIS functions. This method:
Interaction
javax.resource.cci.Interaction
The javax.resource.cci.Interaction enables a component to execute EIS functions. An Interaction instance supports the following ways of interacting with an EIS instance:
An Interaction instance is created from a connection and is required to maintain its association with the Connection instance. The close() method releases all resources maintained by the adapter for the interaction. The close of an Interaction instance should not close the associated Connection instance.
ADK Implementation
The ADK provides an implementation of this interface called AbstractInteraction. This interface:
You must supply a concrete extension to AbstractInteraction that implements execute(). Use at least one of the following versions of execute():
execute() Version 1
The execute() method declared in Listing 6-27 shows an interaction represented by the InteractionSpec. This form of invocation takes an input record and updates the output record.
This method:
Listing 6-27 execute() Version 1 Code Example
public boolean execute(InteractionSpec ispec,
Record input,
Record output)
throws ResourceException
The parameters for execute() version 1 are:
Table 6-3 execute() Version 1 Parameters
Parameters |
Description |
---|---|
ispec |
InteractionSpec representing a target EIS data/function module |
input |
Input Record |
output |
Output Record |
execute() Version 2
The execute() method declared in Listing 6-28 also executes an Interaction represented by the InteractionSpec. This form of invocation takes an input Record and returns an output Record if the execution of the Interaction has been successful.
This method:
If an exception occurs, this method will notify its Connection, which will take the appropriate action, including closing itself.
Listing 6-28 execute() Version 2 Code Example
public Record execute(InteractionSpec ispec,
Record input)
throws ResourceException
The parameters for execute() version 2 are:
Table 6-4 execute() Version 2 Parameters
Parameter |
Description |
---|---|
ispec |
InteractionSpec representing a target EIS data/function module |
input |
Input Record |
Using XCCI to Implement the CCI
XCCI (XML-CCI) It is a dialect of CCI that uses XML-based record formats to represent data. It provides the tools and framework for supporting this record format. There are two primary components of XCCI: Services and DocumentRecords.
A service represents functionality available in an EIS and is comprised of four components:
Every service has a unique business name that indicates its role in an integration solution. For example, in an integration solution involving a Customer Relationship Management (CRM) system, you may have a service named "CreateNewCustomer". It is important to understand that the service name should reflect the business purpose of the service; it is an abstraction from the name of the function(s) your service invokes in the EIS
The request document definition describes the input requirements for a service. The com.bea.document.IDocumentDefinition interface embodies all the metadata about a document type. It includes the document schema (structure and usage), and the root element name for all documents of this type. The root element name is needed because an XML schema can define more than one possible root element.
The response document definition describes the output for a service.
A service is a higher-order component in an integration solution that hides most of the complexity involved in executing functionality in an EIS. In other words, a service does not expose many of the details required to interact with the EIS in its public interface. This implies that some of the information required to invoke a function in an EIS is not provided by the client in the request. Consequently, most services need to store additional metadata. In WebLogic Integration, this additional metadata is encapsulated by an adapter's javax.resource.cci.InteractionSpec implementation class.
DocumentRecord
com.bea.connector.DocumentRecord
At run time, the XCCI layer expects DocumentRecord objects as input to a service and returns DocumentRecord objects as output from a service. DocumentRecord implements the javax.resource.cci.Record and the com.bea.document.IDocument interfaces. See Record for a description of that interface. IDocument, which facilitates XML input and output from the CCI layer in an adapter, is described in the following section.
IDocument
com.bea.document.IDocument
An IDocument is a higher-order wrapper around the W3C Document Object Model (DOM). The primary value-add of the IDocument interface is that it provides an XPath interface to elements in an XML document. In other words, IDocument objects are queryable and updatable using XPath strings. For example, The XML document shown in Listing 6-29 describes a person named "Bob" and some of the details about "Bob."
Listing 6-29 XML Example
<Person name="Bob">
<Home squareFeet="2000"/>
<Family>
<Child name="Jimmy">
<Stats sex="male" hair="brown" eyes="blue"/>
</Child>
<Child name="Susie">
<Stats sex="female" hair="blonde" eyes="brown"/>
</Child>
</Family>
</Person>
By using IDocument, you can retrieve Jimmy's hair color using the code shown in Listing 6-30:
Listing 6-30 IDocument Data Retrieval Code Sample
System.out.println("Jimmy's hair color: " +
person.getStringFrom("//Person[@name=\"Bob\"]/Family/Child
[@name=\"Jimmy\"]/Stats/@hair");
On the other hand, if you used DOM, you would need to enter the code shown in Listing 6-31:
Listing 6-31 DOM Data Retrieval Code Sample
String strJimmysHairColor = null;
org.w3c.dom.Element root = doc.getDocumentElement();
if (root.getTagName().equals("Person") &&
root.getAttribute("name").equals("Bob") {
org.w3c.dom.NodeList list = root.
getElementsByTagName("Family");
if (list.getLength() > 0) {
org.w3c.dom.Element family = (org.w3c.dom.
Element)list.item(0);
org.w3c.dom.NodeList childList = family.getElementsByTagName("Child");
for (int i=0; i < childList.getLength(); i++) {
org.w3c.dom.Element child = childList.item(i);
if (child.getAttribute("name").equals("Jimmy")) {
org.w3c.dom.NodeList statsList =
child.getElementsByTagName("Stats");
if (statsList.getLength() > 0) {
org.w3c.dom.Element stats = statsList.item(0);
strJimmysHairColor = stats.getAttribute("hair");
}
}
}
}
}
As you can see, by using IDocument, you can simplify your code.
ADK-Supplied XCCI Classes
The ADK provides several classes that will help you implement XCCI for your adapters. This section describes those classes.
AbstractDocumentRecordInteraction
com.bea.adapter.cci.AbstractDocumentRecordInteraction
This class extends the ADK's abstract base Interaction, com.bea.adapter.cci.AbstractInteraction. The purpose of this class is to provide convenience methods for manipulating DocumentRecords and to reduce the amount of error handling the you need to implement. Specifically, this class declares:
protected abstract boolean execute(InteractionSpec ixSpec, DocumentRecord inputDoc, DocumentRecord outputDoc) throws ResourceException
and
protected abstract DocumentRecord execute(InteractionSpec ixSpec, DocumentRecord inputDoc) throws ResourceException
These methods will not be invoked on the concrete implementation until the parameters have been verified that they are DocumentRecord objects.
DocumentDefinitionRecord
com.bea.adapter.cci.DocumentDefinitionRecord
This class allows the adapter to return an IDocumentDefinition from its DocumentRecordInteraction implementation. This class is useful for satisfying design-time requests to create the request and/or response document definitions for a service.
DocumentInteractionSpecImpl
com.bea.adapter.cci.DocumentInteractionSpecImpl
This class allows you to save the request document definition and response document definition for a service into the InteractionSpec provided to the execute method at run time. This is useful when the Interaction for an adapter needs access to the XML schemas for a service at run time.
XCCI Design Pattern
A common design pattern that emerges when using the XCCI approach is to support the definition of services in the Interaction implementation. In other words, the javax.resource.cci.Interaction implementation for an adapter allows a client program to retrieve metadata from the underlying EIS in order to define a WebLogic Integration service. Specifically, this means that the interaction must be able to generate the request and response XML schemas and additional metadata for a service. Additionally, the Interaction could also allow a client program to browse a catalog of functions provided by the EIS. This approach facilitates a thin client architecture for your adapter.
The ADK provides the com.bea.adapter.cci.DesignTimeInteraction- SpecImpl class to help you implement this design pattern. The sample.cci.InteractionImpl class demonstrates how to implement this design pattern using the DesignTimeInteractionSpecImpl class.
Using Non-XML J2EE-Compliant Adapters
The ADK provides a plug-in mechanism for using non-XML adapters with WebLogic Integration. Not all pre-built adapters use XML as their javax.resource.cci.Record data type; for example:
To facilitate implementation of these types of adapters, the ADK provides the com.bea.connector.IRecordTranslator interface. At run time, the application view engine uses an adapter's IRecordTranslator implementation to translate request and response records before executing the adapter's service.
Since the application integration engine only supports javax.resource.cci.Record of type com.bea.connector.DocumentRecord, you must translate this proprietary format to a document record for request and response records. You do not need to rewrite the adapter's CCI interaction layer. By inserting a class into the WebLogic Integration engine classpath that implements IRecordTranslator, the application view engine will execute the translate methods in your translator class on each record for request and response.
The requirements and restrictions for implementing this translator class are that there is a one to one correlation between adapter and the translator. The plug-in architecture loads the translator class by name, using the full class name of the adapter's InteractionSpec plus the phrase "RecordTranslator"; for example, if the adapter's InteractionSpec class name was com.bea.adapter.dbms.cci. InteractionSpecImpl, then the engine would load the class com.bea.adapter. dbms.cci.InteractionSpecImplRecordTranslator if it was available.
See the Javadoc for com.bea.connector.IRecordTranslator at WLI_HOME/docs/apidocs/com/bea/connector/IRecordTranslator.html for a description of the methods that must be implemented.
ConnectionFactory
javax.resource.cci.ConnectionFactory
ConnectionFactory provides an interface for getting connection to an EIS instance. An implementation of the ConnectionFactory interface is provided by an adapter.
The application code looks up a ConnectionFactory instance from JNDI namespace and uses it to get EIS connections.
An implementation class for ConnectionFactory is required to implement java.io.Serializable and javax.resource.Referenceableinterfaces to support JNDI registration.
ADK Implementation
The ADK provides ConnectionFactoryImpl, a concrete implementation of the javax.resource.cci.ConnectionFactory interface that provides the following functionality:
Typically, you will not need to extend this class and can use it outright.
ConnectionMetaData
javax.resource.cci.ConnectionMetaData
ConnectionMetaData provides information about an EIS instance connected through a Connection instance. A component calls the method Connection.getMetaData to get a ConnectionMetaData instance.
ADK Implementation
By default, the ADK provides an implementation of this class via the com.bea.adapter.spi.AbstractConnectionMetaData class. You will need to extend this abstract class and implement its four abstract methods for your adapter.
ConnectionSpec
javax.resource.cci.ConnectionSpec
ConnectionSpec is used by an application component to pass connection request-specific properties to the ConnectionFactory.getConnection() method.
It is recommended that you implement the ConnectionSpec interface as a JavaBean so that it can support tools. The properties on the ConnectionSpec implementation class must be defined through the getter and setter methods pattern.
The CCI specification defines a set of standard properties for an ConnectionSpec. The properties are defined either on a derived interface or an implementation class of an empty ConnectionSpec interface. In addition, an adapter may define additional properties specific to its underlying EIS.
ADK Implementation
Since the ConnectionSpec implementation must be a JavaBean, the ADK does not supply an implementation for this class.
InteractionSpec
javax.resource.cci.InteractionSpec
An InteractionSpec holds properties for driving an interaction with an EIS instance. It is used by an interaction to execute the specified function on an underlying EIS.
The CCI specification defines a set of standard properties for an InteractionSpec. An InteractionSpec implementation is not required to support a standard property if that property does not apply to its underlying EIS.
The InteractionSpec implementation class must provide getter and setter methods for each of its supported properties. The getter and setter methods convention should be based on the JavaBeans design pattern.
The InteractionSpec interface must be implemented as a JavaBean in order to support tools. An implementation class for InteractionSpec interface is required to implement the java.io.Serializable interface.
The InteractionSpec contains information that is not in Record but helps determine what EIS function to invoke.
The standard properties are described in Table 6-5:
Table 6-5 Standard InteractionSpec Properties
The following standard properties are used to give hints to an interaction instance about the ResultSet requirements:
A CCI implementation can provide additional properties beyond that described in the InteractionSpec interface.
Note: The format and type of the additional properties is specific to an EIS and is outside the scope of the CCI specification.
ADK Implementation
The ADK contains a concrete implementation of javax.resource.cci.InteractionSpec called InteractionSpecImpl. This interface provides a base implementation for you to extend by using getter and setter methods for the standard interaction properties described in Table 6-5.
LocalTransaction
javax.resource.cci.LocalTransaction
The LocalTransaction interface is used for application-level local transaction demarcation. It defines a transaction demarcation interface for resource manager local transactions. The system contract level LocalTransaction interface (as defined in the javax.resource.spi package) is used by the container for local transaction management.
A local transaction is managed internal to a resource manager. There is no external transaction manager involved in the coordination of such transactions.
A CCI implementation can (but is not required to) implement the LocalTransaction interface. If the LocalTransaction interface is supported by a CCI implementation, then the method Connection.getLocalTransaction() should return a LocalTransaction instance. A component can then use the returned LocalTransaction to demarcate a resource manager local transaction (associated with the Connection instance) on the underlying EIS instance.
The com.bea.adapter.spi.AbstractLocalTransaction class also implements this interface.
For more information on local transactions, see Transaction Demarcation.
Record
javax.resource.cci.Record
The javax.resource.cci.Record interface is the base interface for representing an input or output to the execute() methods defined on an Interaction. For more information on the execute() methods, see execute() Version 1 and execute() Version 2
A MappedRecord or IndexedRecord can contain another Record. This means that you can use MappedRecord and IndexedRecord to create a hierarchical structure of any arbitrary depth. A basic Java type is used as the leaf element of a hierarchical structure represented by a MappedRecord or IndexedRecord.
The Record interface can be extended to form one of the representations shown in Table 6-6:
Table 6-6 Record Interface Representations
Assuming the adapter implements a CCI interface, the next consideration is the record format for a service. A service has a request record format and a response record format. The request record provides input to the service and the response record provides the EIS response.
ADK Implementation
The ADK focuses on helping you implement an XML-based record format in the CCI layer. To this end, the ADK provides the DocumentRecord class. In addition, you can use BEA's schema toolkit to develop schemas to describe the request and response documents for a service.
The ADK provides RecordImpl, a concrete implementation of the javax.resource.cci.Record interface that provides getter and setter methods for record name and description.
If an adapter provider wants to use an XML-based record format (which is highly recommended), the ADK also provides the com.bea.adapter.cci.Abstract DocumentRecordInteraction class. This class ensures that the client passes DocumentRecord objects. In addition, this class provides convenience methods for accessing content in a DocumentRecord.
ResourceAdapterMetaData
javax.resource.cci.ResourceAdapterMetaData
The interface javax.resource.cci.ResourceAdapterMetaData provides information about capabilities of an adapter implementation. A CCI client uses a ConnectionFactory.getMetaData to get metadata information about the adapter. The getMetaData() method does not require establishment of an active connection to an EIS instance. The ResourceAdapterMetaData interface can be extended to provide more information specific to an adapter implementation.
Note: This interface does not provide information about an EIS instance that is connected through the adapter.
ADK Implementation
The ADK provides ResourceAdapterMetaDataImpl that encapsulates adapter metadata and provides getters and setters for all properties.
Step 5: Testing the Adapter
The ADK provides a test harness that leverages JUnit, an open-source tool for unit testing. You can find more information on JUnit at:
com.bea.adapter.test.TestHarness does the following:
Using the Test Harness
To use the test harness in the ADK, complete the following steps:
Listing 6-32 Ant Target Specified in the Sample Adapter
<target name='test' depends='packages'>
<java classname='com.bea.adapter.test.TestHarness'>
<arg value='-DCONFIG_FILE=test.properties'/<classpath
refid='CLASSPATH'/>
</java>
This target invokes the JVM with main class com.bea.adapter.test.TestHarness using the classpath established for the sample adapter and passes the command-line argument:
-DCONFIG_FILE=test.properties
Test Case Extensions Provided by the ADK
The sample adapter ships with two basic TestCase extensions:
sample.spi.NonManagedScenarioTestCase
NonManagedScenarioTestCase allows you to test your SPI and CCI classes in a non-managed scenario. Specifically, this class tests the following:
sample.event.OfflineEventGeneratorTestCase
sample.event.OfflineEventGeneratorTestCase allows you to test the inner workings of your event generator outside of Weblogic Server. Specifically, this class tests the following for the event generator:
sample.client.ApplicationViewClient
sample.client.ApplicationViewClient offers an additional way of test your adapter. This class is a Java program that demonstrates how to invoke a service and listen for an event on an application view. The Ant build.xml provides the "client" target to allow you to use the ApplicationViewClient program. Executing ant client will provide the usage for the program. To see an example of sample.client.ApplicationViewClient.java, go to WLI_HOME/adapters/ sample/src/sample/client.
Note: sample.client.ApplicationViewClient is not integrated with the test harness.
Step 6: Deploying the Adapter
After implementing the SPI and CCI interfaces for an adapter, and then testing it, deploy it into WebLogic Integration. You can deploy an adapter either manually or from the WebLogic Server Console. See Deploying Adapters, for complete information.
![]() |
![]() |
![]() |
|
Copyright © 2001 BEA Systems, Inc. All rights reserved.
|