![]() ![]() ![]() ![]() ![]() ![]() ![]() |
A service connection receives an XML request document from a client and invokes the associated function in the underlying EIS. Service connections are consumers of messages; they may or may not provide responses. They perform the following four functions:
This section contains information about the following subjects:
The steps outlined in this section are directed primarily at developing adapters for use with WebLogic Integration. You can also use the ADK to develop adapters for use outside the WebLogic Integration environment, however, by following the same steps with certain modifications. For instructions, see Creating an Adapter Not Specific to WebLogic Integration.
Figure 6-1 and Figure 6-2 show the processes that are executed when a service connection is used in a run-time environment. Figure 6-1 shows an asynchronous service connection; Figure 6-2, a synchronous adapter.
Figure 6-3 outlines the steps required to develop a service connection.
Before you start developing your service connection, you must identify the resources needed in your environment to support it. This section provides a high-level description of the prerequisites for a development environment. For a complete list of required resources, see Adapter Setup Worksheet.
Based on your knowledge of the EIS, identify the interface to the back-end functionality.
An expensive connection object is an object required to invoke a function within the EIS. This function, in turn, is required for communicating with the EIS.
An expensive connection object requires an allocation of system resources, such as a socket connection or DBMS connection. A valuable benefit of using the J2EE Connector Architecture is that the application server pools these objects. Because the object for your adapter will be pooled by the application server, you need to identify it.
To pass connection authentication across the connection request path, your adapter must implement a ConnectionRequestInfo
class. To facilitate such an implementation, the ADK provides the class ConnectionRequestInfoMap
. You can use this class to map authorization information, such as username and password, to the connection.
The ADK conforms to the J2EE Connector Architecture Specification 1.0. For more information about connection architecture security, see the "Security" section of that document. You can download the specification in PDF format (for easy printing) from the following URL:
Decide which of the following types of transaction demarcation support to implement with your adapter:
Note: | For more information about transaction demarcation support, see Transaction Demarcation, or see: |
Environment variables are used to isolate environment specific information in a way that allows system administrators and application deployers to modify it as necessary for the target environment. If your adapter defines service properties that include environment-specific identifiers or other information, you should implement environment variable support in your service adapter.
This section provides a four-step procedure (steps 2a-2d) for configuring your environment.
Note: | A simple way of completing this procedure is by running the GenerateAdapterTemplate utility. For more information, see Creating a Custom Development Environment. |
When you install WebLogic Integration, you also create the directory structure necessary not only to run an adapter, but also to use the ADK. The ADK files reside under WLI_HOME
/adapters/
, where WLI_HOME
is the directory in which you installed WebLogic Integration. Be sure to verify that your WLI_HOME
directory is populated with the necessary directories and files at installation time.
The following table describes the directory structure under WLI_HOME
.
Directory containing the Apache Jakarta Ant build file:
build.xml . This file contains build information for compiling the source code, generating the JAR and EAR files, and generating Javadoc information. For details about building the adapter, see Step 2c: Set Up the Build Process.
|
|
File containing messages used by the adapter for internationalization and localization. This file is merged with the ADK properties file (
WLI_HOME /adapters/src/ADK.properties ) to form the BEA_WLS_SAMPLE_ADK.properties file, the final properties file that will be used by the adapter. This merge happens in the build.xml file in the packages target.
|
|
Web application descriptor. See The web.xml and weblogic.xml Descriptor Files for details.
|
|
File containing WebLogic Server-specific attributes for a Web Application. See The web.xml and weblogic.xml Descriptor Files for details.
|
|
The web.xml
and weblogic.xml
descriptors for your adapter generally follow a very simple pattern. They list the names of all the JSP pages in your design-time web application and provide additional setup information. Because most adapters contain very similar web descriptors, the ADK provides a means to automatically generate them. This frees the adapter developer from maintaining a large descriptor that is mostly identical to other adapter's web descriptors.
The generation of the web application descriptors may be requested by including and calling a special Ant target in your Ant build.xml
file for your adapter. If you clone the ADK sample adapter using GenerateAdapterTemplate
, the resulting build.xml
already includes the necessary Ant target and a call to use that target. Look at the WLI_HOME
/adapters/sample/project/build.xml file
and find the generate_web_descriptors
target. This Ant target takes in a file called web-gen.properties
and generates the web.xml
and weblogic.xml
descriptors from the information contained in it. Notice that in the sample adapter build.xml
, this target is called near the top of the packages
target.
The sample adapter includes a web-gen.properties
file as a template that can be modified for your adapter. The following properties are listed in this file:
display-name
—This is the value used in the display-name
element of web.xml
. It should be the adapter logical name for your adapter (for example, BEA_WLS_SAMPLE_ADK
for the sample adapter). version
—The version of your design-time web application and the value that is used in the version element of web.xml
(for example, 8.1.0
for the sample adapter). Always use the same value you specified in GenerateAdapterTemplate
. request-handler-class
—This is the full class name of the design-time request handler implementation class for your adapter.This class that extends AbstractDesignTimeRequestHandler
and normally resides in adapter_package
.web.DesignTimeRequestHandler
. adapter-logical-name
—The adapter logical name for your adapter. It should be the same value you used in GenerateAdapterTemplate
for example, BEA_WLS_SAMPLE_ADK
for the sample adapter) debug-setting
—This setting enables or disables debug capabilities and is specified as on
or off
. Turning debug on
enables any debug statements you have placed in your source code (or that were there from cloning the sample adapter source) that use the ILogger.debug()
method. Turning debug off
disables these debug statements from being logged to the log file. extra-jsp-list
—a comma separated list of additional JSPs. The standard ones are:Fill in the information appropriate for your adapter in the copy of this file made for you by GenerateAdapterTemplate. Do no modify the original file.
At build time, the generate_web_descriptors
target substitutes the information in your web-gen.properties
file and generates the web.xml
and weblogic.xml
descriptors appropriate for your adapter's design-time web application. The descriptors are placed in the src/war/WEB-INF
directory for your adapter.
If you wish to tightly control your web.xml
and weblogic.xml
descriptors, you can comment out any call to generate_web_descriptors
in your build.xml
file, and maintain the web.xml
and weblogic.xml
descriptors manually.
When you clone a development tree by using GenerateAdapterTemplate, the contents of all the directories under WLI_HOME
/adapters/sample
are automatically cloned and updated to reflect the new development environment.
The changes are also reflected in the file WLI_HOME
/adapters/
ADAPTER
/src/overview.html
, where the value of 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 sets up WebLogic Integration to host the adapter.
Assign a logical name to the adapter. By convention, this name is made up of three items—the vendor name, the type of EIS connected to the adapter, and the version number of the EIS—separated by underscores, as follows:
For more information about the logical name of an adapter, see Adapter Logical Name.
The ADK employs a build process based on Ant, a 100% pure Java-based build tool. For more information about Ant, see Ant-Based Build Process. For more information about using Ant, see:
http://jakarta.apache.org/ant/index.html
The sample adapter provided with the ADK (in WLI_HOME
/adapters/sample/project
) contains build.xml
, the Ant build file for the sample adapter. It contains the tasks needed to build a J2EE-compliant adapter. When you run the GenerateAdapterTemplate
utility to clone a development tree for your adapter, a build.xml
file is created specifically for that adapter. This automatic file generation frees you from having to customize the sample build.xml
and ensures that the code is correct. For information about using the GenerateAdapterTemplate
utility, see Creating a Custom Development Environment.
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.
Manifest-Version: 1.0
Created-By: BEA Systems, Inc.
Class-Path: shared.jar
The first two lines of the file contain version and vendor information. The third line contains the relevant classpath or classloading instructions. The Class-Path
property contains references to resources required by the component and a list of shared JAR files. (Filenames in the list are separated by spaces.) Make sure the JAR files are included in the shared area of the EAR file. (For details, see Enterprise Archive (EAR) Files.)
The JAR tool imposes a 72-character limit on the length of the Class-Path:
line. Lines longer than 72 characters should carry over to the next line and begin with a preceding space, as in the following:
Class-Path: .....72 chars of classpath
<space>more classpath
In the sample ADK adapters, all shared JAR files are combined into a single JAR file (shared.jar
) using the following Ant commands:
<jar jarfile='${LIB_DIR}/shared.jar'>
<zipfileset src='${LIB_DIR}/${JAR_FILE}'>
<exclude name='META-INF/MANIFEST.MF'/>
</zipfileset>
<zipfileset src='${WLI_LIB_DIR}/adk.jar'>
<exclude name='META-INF/MANIFEST.MF'/>
</zipfileset>
<zipfileset src='${WLI_LIB_DIR}/adk-eventgenerator.jar'>
<exclude name='META-INF/MANIFEST.MF'/>
</zipfileset>
<zipfileset src='${WLI_LIB_DIR}/wlai-core.jar'>
<exclude name='META-INF/MANIFEST.MF'/>
</zipfileset>
<zipfileset src='${WLI_LIB_DIR}/wlai-client.jar'>
<exclude name='META-INF/MANIFEST.MF'/>
</zipfileset>
</jar>
Note: | When it is included in a WAR file, the filename MANIFEST.MF must be spelled in all uppercase letters. If it is spelled otherwise, it is not recognized on a UNIX system and an error occurs. |
To learn how build.xml
works, open it and review its components. This section provides descriptions of the main file elements. Refer to these descriptions as you review the contents of build.xml
.
Note: | The examples in this section are taken from the sample adapter itself, not from a cloned version of it. |
<project name='BEA_WLS_SAMPLE_ADK' default='all' basedir='.'>
WL_HOME
environment variable from your system.<property environment="env" />
<property name="WEBLOGIC_JAR" value="${env.WL_HOME}/lib/weblogic.jar" />
<property name="WLI_HOME" value="${basedir}/../../.." />
<property name="JAR_FILE" value="BEA_WLS_SAMPLE_ADK.jar" />
<property name="EIS_JAR_FILE" value="sample-eis.jar" />
<property name="EIS_JAR_PATH" value="APP-INF/lib/${EIS_JAR_FILE}" />
<property name="RAR_FILE" value="BEA_WLS_SAMPLE_ADK.rar" />
<property name="WAR_FILE" value="BEA_WLS_SAMPLE_ADK_Web.war" />
<property name="EAR_FILE" value="BEA_WLS_SAMPLE_ADK.ear" />
<property name="ADAPTER_DIR" value="${WLI_HOME}/adapters/sample" />
<property name="SRC_DIR" value="${ADAPTER_DIR}/src" />
<property name="LIB_DIR" value="${ADAPTER_DIR}/lib" />
<property name="DOC_DIR" value="${ADAPTER_DIR}/docs/api" />
<property name="WLI_LIB_DIR" value="${WLI_HOME}/lib" />
<property name="METAMATA_JAR" value="${WLI_LIB_DIR}/metamata.jar" />
<property name="LOG4J_JAR" value="${WLI_LIB_DIR}/log4j.jar" />
<property name="JUNIT" value="${WLI_LIB_DIR}/junit.jar" />
<property name="HTTPUNIT" value="${WLI_LIB_DIR}/httpunit.jar" />
<property name="TIDY" value="${WLI_LIB_DIR}/Tidy.jar" />
<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_CORE" value="${WLI_LIB_DIR}/wlai-core.jar" />
<property name="WLAI_CLIENT" value="${WLI_LIB_DIR}/wlai-client.jar" />
<property name="XMLTOOLKIT" value="${WLI_LIB_DIR}/xmltoolkit.jar" />
<property name="XCCI" value="${WLI_LIB_DIR}/xcci.jar" />
You should not need to alter these properties. After them, however, you can add any other JAR files and/or classes needed by your adapter.
<path id='CLASSPATH'>
<pathelement location='${SRC_DIR}'/>
<pathelement path='${ADK}:${ADK_EVENTGENERATOR}:
${ADK_WEB}:${ADK_TEST}:${WEBTOOLKIT}:${WLAI_CORE}:
${WLAI_CLIENT}'/>
<pathelement path='${WEBLOGIC_JAR}:${env.BEA_HOME}'/>
<pathelement path='${JUNIT}:${HTTPUNIT}:${TIDY}'/>
<pathelement path="${env.JAVA_HOME}/lib/tools.jar" />
</path>
After this information, you have the option of calling any of the following three combinations of files:
<target name='jar' depends='packages,version_info'>
<delete file='${LIB_DIR}/${JAR_FILE}'/>
<mkdir dir='${LIB_DIR}'/>
<jar jarfile='${LIB_DIR}/${JAR_FILE}'>
The includes
list from the adapter's source directory is specified. For the sample adapter described in this section, all the classes in the sample/cci
and sample/spi
packages are included, as well as the logging configuration file and message bundles.
<fileset dir='${SRC_DIR}'
includes='sample/cci/*.class,sample/spi/*.class,
*.xml,*.properties'/>
Version information about the JAR file is provided, as shown in the following listing.
<!-- Include version information about the JAR file -->
<fileset dir='${basedir}'
includes='version_info.xml'/>
</jar>
<target name="eis_jar" depends="packages,version_info">
<delete file="${LIB_DIR}/${EIS_JAR_PATH}" />
<mkdir dir="${LIB_DIR}" />
<mkdir dir="${LIB_DIR}/APP-INF" />
<mkdir dir="${LIB_DIR}/APP-INF/lib" />
<jar jarfile="${LIB_DIR}/${EIS_JAR_PATH}">
<fileset dir="${SRC_DIR}" includes="sample/eis/*.class" />
<fileset dir="${basedir}" includes="version_info.xml" />
</jar>
</target>
deployment
descriptor
for the adapterThe following listing shows how the RAR file for the sample adapter is created.
<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>
<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' failonerror="true">
<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/taglibs/adk.tld" />
<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
-->
All JAR files needed by the Web application are included in the <lib>
component of the build.xml
file.
<lib dir='${WLI_LIB_DIR}' includes='adk-web.jar,
webtoolkit.jar,wlai-client.jar'/>
<target name='ear' depends='eis_jar,rar,war'>
<delete file='${LIB_DIR}/${EAR_FILE}'/>
<jar jarfile="${LIB_DIR}/shared.jar">
<zipfileset src="${LIB_DIR}/${JAR_FILE}">
<exclude name="META-INF/MANIFEST.MF" />
</zipfileset>
<zipfileset src="${WLI_LIB_DIR}/adk.jar">
<exclude name="META-INF/MANIFEST.MF" />
</zipfileset>
<zipfileset src="${WLI_LIB_DIR}/adk-eventgenerator.jar">
<exclude name="META-INF/MANIFEST.MF" />
</zipfileset>
<zipfileset src="${WLI_LIB_DIR}/wlai-core.jar">
<exclude name="META-INF/MANIFEST.MF" />
</zipfileset>
<zipfileset src="${WLI_LIB_DIR}/wlai-client.jar">
<exclude name="META-INF/MANIFEST.MF" />
</zipfileset>
</jar>
<jar jarfile='${LIB_DIR}/${EAR_FILE}'>
<fileset dir='${basedir}' includes='version_info.xml'/>
<fileset dir='${SRC_DIR}/ear' includes=
'META-INF/application.xml'/>
<fileset dir='${LIB_DIR}'includes='shared.jar,
${RAR_FILE}, ${WAR_FILE}'/>
<fileset dir='${EIS_JAR_PATH}'/>
</jar>
<delete file='${LIB_DIR}/${WAR_FILE}'/>
<delete file='${LIB_DIR}/${RAR_FILE}'/>
<delete file='${LIB_DIR}/${JAR_FILE}'/>
<!--
Need to keep this out of the EAR and on the system classpath until we get
WLS Connector to fix the RAR ClassLoader so logical RAR's can see all
the classes/resources the base RAR can. Currently, the logical RAR can
only see things in the BASE RAR's archive or on its Manifest Class-Path
-->
<copy file="${LIB_DIR}/${EIS_JAR_PATH}" toFile="${LIB_DIR}/
${EIS_JAR_FILE}" />
<delete file="${LIB_DIR}/${EIS_JAR_PATH}" />
<delete dir="${LIB_DIR}/APP-INF/lib" />
<delete dir="${LIB_DIR}/APP-INF" />
<delete file="${LIB_DIR}/shared.jar" />
</target>
<jar jarfile='${LIB_DIR}/${EAR_FILE}'>
<fileset dir='${basedir}' includes='version_info.xml'/>
<fileset dir='${SRC_DIR}/ear' includes='META-INF/application.xml'/>
<fileset dir='${LIB_DIR}'includes='shared.jar,${RAR_FILE},
${WAR_FILE}'/>
<fileset dir='${EIS_JAR_PATH}'/>
</jar>
<target name="packages">
<echo message="Building ${ant.project.name}..." />
<!--
Generate web descriptors. NOTE: You can turn this off if you want to
tightly control your web.xml/weblogic.xml. In this case, simply maintain
these files in your src/war/WEB-INF instead of web-gen.properties
-->
<ant dir="${WLI_HOME}/adapters/utils/ant"
target="generate_web_descriptors" inheritAll="false">
<property name="web_gen_props_file"
value="${SRC_DIR}/war/WEB-INF/web-gen.properties" />
</ant>
<!--
Merge the ADK.properties file and your adapter-specific properties into
the final properties file that will be used by the adapter
-->
<ant dir="${WLI_HOME}/adapters/utils/ant" target="merge_properties"
inheritAll="false">
<property name="props_dir" value="${SRC_DIR}" />
<property name="adapter_props_file"
value="BEA_WLS_SAMPLE_ADK-base.properties" />
<property name="target_props_file"
value="BEA_WLS_SAMPLE_ADK.properties" />
</ant>
- <!--
Compile the java source files for the adapter
-->
<javac deprecation="true" debug="true">
<classpath refid="CLASSPATH" />
<src path="${SRC_DIR}" />
<include name="**/*.java" />
<exclude name="sample/event/OfflineEventGeneratorTestCase.java" />
<exclude name="war/jsp_servlet/**" />
</javac>
</target>
<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>
<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_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='${SRC_DIR}/war/jsp_servlet'/>
</target>
<target name='clean_jar' depends='clean_packages,clean_version_
info'>
<delete file='${LIB_DIR}/${JAR_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>
Any message destined for an end-user should be placed in a message bundle: a .properties
text file containing key
=
value
pairs that allow you to generate messages in more than one natural language. When a locale and a language are specified at run time, the contents of a message are interpreted in accordance with the relevant key
=
value
pairs, and the message is presented to the user in the language appropriate for his or her locale.
The message bundle is generally located at the root of the src
tree, WLI_HOME
/adapters/
adapter
/src/
bundle_name
-base.properties
, where bundle_name
is the adapter logical name. Remember that this base message bundle is merged with the ADK.properties
bundle (in WLI_HOME
/adapters/src/ADK.properties
) to form the final bundle_name
.properties
file that is loaded at runtime. This allows ADK defined properties to be placed in the final bundle without having to physically copy or maintain them in the adapter's message bundle file. This allows for updating or upgrading these properties as new WebLogic Integration releases are available and new locales are supported.
For instructions on creating a message bundle, see the JavaSoft tutorial on internationalization at:
http://java.sun.com/docs/books/tutorial/i18n/index.html
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.
This section 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 interface is described in detail, followed by a discussion of how it is extended in the sample adapter included with the ADK.
First, we describe the three required interfaces. Then we describe the additional interfaces in detail, and discuss why you might use them and how they can be beneficial when used in an adapter.
To implement the SPI for your adapter, you must extend at least the following three interfaces:
ManagedConnectionFactory
, which supports connection pooling by providing methods for matching and creating a ManagedConnection instance.ManagedConnection
, which represents a physical connection to the underlying EIS ManagedConnectionMetaData
, which provides information about the underlying EIS instance associated with a ManagedConnection
instance Ideally, these interfaces are implemented in the order specified here.
In addition to these three interfaces, you can implement any of the other interfaces described in this step, as your adapter needs dictate.
javax.resource.spi.ManagedConnectionFactory
The ManagedConnectionFactory
interface 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.
A critical component of the ManagedConnectionFactory
interface is transaction demarcation. You must be able 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. The contract differs, depending on the type of transaction for which it is used. There are two types of transactions:
In a distributed transaction processing (DTP) environment, a j
avax.transaction.xa.XAResource
-based contract is established between a transaction manager and a resource manager. A JDBC driver or a JMS provider implements this interface to support the 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 in which transactions are controlled by an external transaction manager.
An example of such a resource is a database management system set up in such a way that 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 with all work performed on its data between invocations of the start()
and end()
methods.
At transaction commit time, the resource managers are instructed, by the transaction manager, to prepare, commit, or roll back a transaction, according to the two-phase commit protocol.
When an adapter implements the javax.resource.spi.LocalTransaction
interface to support local transactions that are performed on the underlying resource manager, a local transaction management contract is established. This contract enables an application server to provide the infrastructure and run-time environment for transaction management. Application components rely on this transaction infrastructure to support the component-level transaction model that they use.
For more information about transaction demarcation support, enter the following URL:
The ADK provides an abstract foundation for an adapter called the AbstractManagedConnectionFactory. This foundation provides the following features:
java.util.ResourceBundle
for an adapterYou must provide your own implementations for the following key methods:
The following sections describe these methods.
createConnectionFactory()
is 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, we recommend 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.
protected Object
createConnectionFactory(ConnectionManager connectionManager,
String strAdapterName,
String strAdapterDescription,
String strAdapterVersion,
String strVendorName)
throws ResourceException
createManagedConnection()
is used to construct a ManagedConnection instance for your adapter. The following listing shows an example of this method.
public ManagedConnection
createManagedConnection(Subject subject, ConnectionRequestInfo
info)
throws ResourceException
The ManagedConnection instance encapsulates the expensive resources needed to communicate with the EIS. This method is called by the ConnectionManager when it determines that a new ManagedConnection is required to satisfy a client's request. A common design pattern used in 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.
The checkState()
method is called by the AbstractManagedConnectionFactory before it attempts to perform any 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 follows:
protected boolean checkState()
The equals()
method tests the object argument for equality. It is important to implement this method correctly because 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 follows:
public boolean equals(Object obj)
The hashCode()
method 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 on properties that determine the uniqueness of the object.
Implement this method as follows:
public int hashCode()
The ManagedConnectionFactory must supply an implementation of the matchManagedConnections()
method. The AbstractManagedConnectionFactory provides an implementation of the matchManagedConnections()
method that relies on the compareCredentials()
method of AbstractManagedConnection.
To provide logic that can match managed connections, you must override the compareCredentials()
method provided by the AbstractManagedConnection
class. This method is invoked when the ManagedConnectionFactory attempts to match a connection with a connection request for the ConnectionManager.
Currently, the AbstractManagedConnectionFactory
implementation extracts a PasswordCredential
from the Subject/ConnectionRequestInfo
parameters that are supplied. If both parameters are null, this method returns true because it has already been established that the ManagedConnectionFactory for this instance is correct. This implementation is shown in the following listing.
public boolean compareCredentials(Subject subject,
ConnectionRequestInfo info)
throws ResourceException
{
ILogger logger = getLogger();
Next, you must extract a PasswordCredential from either the JAAS Subject or the SPI ConnectionRequestInfo using the ADK's ManagedConnectionFactory
. An example is shown in the following listing.
PasswordCredential pc = getFactory().
getPasswordCredential(subject, info);
if (pc == null)
{
logger.debug(this.toString() + ": compareCredentials
In the previous listing, JAAS Subject and ConnectionRequestInfo are null, which means that a match is assumed. This method is not 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. The following listing shows how to ping the connection programmatically.
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 check whether the user specified in either the Subject or ConnectionRequestInfo
is the same as our user. We do not support reauthentication in this adapter, so if the usernames do not match, this instance cannot satisfy the request. The following code satisfies the request:
bUserNameMatch = m_strUserName.equals(strPcUserName);
If the usernames match, ping the connection to determine whether it is still good. If the names do not match, there is no reason to ping.
To ping the connection, use the following code:
return bUserNameMatch ? ping() : false;
In 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 ADK's 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 whether it can satisfy the request.
matchManagedConnections()
is called by the ConnectionManager
(as shown in Listing 6-22) to search for a valid connection in the pool it is managing. If this method returns null, then the ConnectionManager
allocates a new connection to the EIS via a call to createManagedConnection()
.
public ManagedConnection
matchManagedConnections(Set connectionSet,
Subject subject,
ConnectionRequestInfo info)
throws ResourceException
This class uses the following approach to match a connection:
connectionSet
until a match is found. Then it determines whether the object is an AbstractManagedConnection
class.ManagedConnectionFactory
for the AbstractManagedConnection
from the set. compareCredentials()
method is invoked on the AbstractManagedConnection
. compareCredentials()
method returns true, then the instance is returned.
To use the base implementation of AbstractManagedConnectionFactory
, you must, at deployment time, provide the properties described in the following table.
The ADK sample adapter provides a class called sample.spi.ManagedConnectionFactoryImpl
that extends AbstractManagedConnectionFactory
. Use this class as an example of how to extend the ADK's base class.
For a complete code listing of an implementation of the sample adapter called ManagedConnectionFactory, see:
WLI_HOME
/adapters/sample/src/sample/spi/
ManagedConnectionFactoryImpl.java
javax.resource.spi.ManagedConnection
The ManagedConnection
object is responsible for encapsulating all the 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.
The ADK provides an abstract implementation of ManagedConnection
. The base class provides logic for managing connection event listeners and multiple application-level connection handles for each instance of ManagedConnection
.
When implementing the ManagedConnection
interface, you need to determine the transaction demarcation support provided by the underlying EIS. For more information about transaction demarcation, see Transaction Demarcation.
The ADK provides AbstractManagedConnection
, an abstract implementation for the javax.resource.spi.ManagedConnection
interface that:
The sample adapter provided with the ADK includes ManagedConnectionImpl
, which extends AbstractManagedConnection
. For a complete code listing for a sample adapter called ManagedConnection
, see:
WLI_HOME
/adapters/sample/src/sample/spi/
ManagedConnectionFactoryImpl.java
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.
The ADK provides AbstractManagedConnectionMetaData
, an abstract implementation of the javax.resource.spi.ManagedConnectionMetaData
and javax.resource.cci.ConnectionMetaData
interfaces that:
The sample adapter provided with the ADK includes ConnectionMetaDataImpl
, which extends AbstractManagedConnectionMetaData
. For the complete code listing for the adapter, see:
WLI_HOME
/adapters/sample/src/sample/spi/ConnectionMetaDataImpl.java
javax.resource.spi.ConnectionEventListener
The ConnectionEventListener
interface provides an event callback mechanism that enables an application server to receive notifications from a ManagedConnection
instance.
The ADK provides two concrete implementations of ConnectionEventListener
:
com.bea.adapter.spi.ConnectionEventLogger
, which logs connection-related events to the adapter's log by using the ADK logging framework.com.bea.adapter.spi.NonManagedConnectionEventListener
, which destroys javax.resource.spi.ManagedConnection
instances when the adapter is running in an unmanaged environment. This implementation:In most cases, the implementations provided by the ADK are sufficient; you should not need to provide your own implementation of this interface.
javax.resource.spi.ConnectionManager
The ConnectionManager
interface provides a hook that can be used by the adapter to pass a connection request to the application server.
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 an unmanaged 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 unmanaged scenario for an adapter; it does not provide any connection pooling or any other quality of service.
javax.resource.spi.ConnectionRequestInfo
The ConnectionRequestInfo
interface enables an adapter to pass its own request-specific data structure across a connection request flow. An adapter extends the empty interface to support its own data structures for a connection request.
The ADK provides a concrete implementation of the javax.resource.spi.ConnectionRequestInfo
interface. This interface is called ConnectionRequestInfoMap
. It provides a java.util.Map
interface to information requested when a connection is being established, such as username and password.
javax.resource.spi.LocalTransaction
The LocalTransaction
interface provides support for transactions that are managed within an EIS resource manager, and do not require an external transaction manager.
The ADK provides an abstract implementation of this interface called AbstractLocalTransaction
, thus allowing you to focus on implementing the EIS-specific aspects of a LocalTransaction
. Specifically, it:
The client interface allows a J2EE-compliant application to access back-end systems. The client interface manages the flow of data between the client application and the back-end system; it 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 both the request records and the response records for a given interaction with the EIS.
First, you must determine whether your adapter must support the J2EE-compliant Common Client Interface (CCI). Although not required by the current J2EE specification, the CCI is likely to be required in a later version. Consequently, the ADK focuses on helping you implement a CCI interface for your adapter.
This section (Step 4: Implement the CCI) describes some of the interfaces you can use to implement the CCI. At a minimum, two interfaces are necessary to complete the task. (See Basic CCI Implementation.) Each interface is described in detail, followed by a discussion of how it is extended in the sample adapter included with the ADK.
Following the description of the two required interfaces, detailed descriptions of the additional interfaces are provided, along with a discussion of reasons why you might use these interfaces and the benefits they provide.
To implement the CCI for your adapter, you need to extend at least the following two interfaces:
Connection
, which represents an application-level handle that is used by a client to access the underlying physical connectionInteraction
, which enables a component to execute EIS functions If possible, implement these interfaces in the order specified here.
In addition, you can implement any of the following interfaces needed for your adapter:
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.
The ADK provides an abstract implementation of this interface called AbstractConnection
. This implementation provides the following functionality:
You must 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:
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:
execute(
) method may take an input Record
, an output Record
, and an InteractionSpec
. This method executes the EIS function represented by the InteractionSpec
and updates the output Record
.execute()
method may take an input Record
and an InteractionSpec
. This method implementation executes the EIS function represented by the InteractionSpec
and produces the output Record
as a return value.
An Interaction
instance is created from a connection and is required to maintain the association between the Interaction
and the Connection
instances. The close()
method releases all resources maintained by the adapter for the interaction. The close of an Interaction
instance should not trigger the close of the associated Connection
instance.
The ADK provides an implementation of this interface called AbstractInteraction
. This implementation:
You must supply a concrete extension to AbstractInteraction
that implements execute()
. Two versions of execute()
are available. They are described in the following sections.
The execute()
method declared in Listing 6-23 shows an interaction represented by InteractionSpec
.
public boolean execute(InteractionSpec ispec,
Record input,
Record output)
throws ResourceException
When invoked in this way, execute()
takes an input record and updates the output record. It returns the following:
The parameters fo
r execute()
version 1 are described in the following table.
The execute()
method declared in Listing 6-24 also executes an Interaction
represented by InteractionSpec
.
public Record execute(InteractionSpec ispec,
Record input)
throws ResourceException
When invoked in this way, execute()
takes an input Record
and, if the execution of Interaction is successful, it returns an output Record
.
If an exception occurs, this method notifies its Connection
, which takes the appropriate action, including closing itself.
The parameters for execute()
version 2 are listed in the following table.
XML-CCI is a dialect of the Client Connector Interface, in which XML-based record formats are used to represent data. These formats are supported by a framework and tools. XML-CCI is usually referred to by its abbreviation: XCCI.
XCCI is made up of two components: Services and DocumentRecords.
A service represents functionality available in an EIS. It includes 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 give a service a name that reflects the business purpose of the service; it is an abstraction of the name of the functions invoked by your service 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 root element.
A response document definition describes the output of 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. As a result, 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.
To indicate that a given service does not require request or response data, create an empty or null IDocumentDefinition
for the request or response in your DesignTimeRequestHandler
. You may also set the IDocumentDescriptor
for the request or response on the IServiceDescriptor
for the service with an empty or null IDocumentDescriptor
instance. Create empty or null IDocumentDefinition
instances using the static DocumentFactory.createNullDocumentDefinition()
method, and empty or null IDocumentDescriptor
instances by using the static DescriptorFactory.createNullDocumentDescriptor()
method.
If you choose to use empty or null document definitions or descriptors in the generated IServiceDescriptor
or IApplicationViewDescriptor
generated by the adapter at design-time, you must ensure that the null request or response documents for these services are handled at runtime. In other words, an adapter that uses empty or null document descriptors must not assume a request or response document is non-null at runtime.
The Application View runtime engine ensures that services requiring a request or response receive non-null request or response documents, and ensures that services not requiring a request or response receive null request or response documents.
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. For a description of the Record
interface, see Record.
IDocument
, which facilitates XML input and output from the CCI layer in an adapter, is described in the following section.
An IDocument
is a higher-order wrapper around the W3C Document Object Model (DOM). The most important value added by the IDocument
interface is an XPath interface to elements in an XML document. In other words, IDocument
objects can be queried and updated using XPath strings. For example, the XML document shown in Listing 6-25 shows how XML is used to record details about a person named Bob.
<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 XPath code shown in Listing 6-26.
System.out.println("Jimmy's hair color: " +
person.getStringFrom("//Person[@name=\"Bob\"]/Family/Child
[@name=\"Jimmy\"]/Stats/@hair");
On the other hand, if DOM is used, you must use the code shown in Listing 6-27 to submit a query.
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, IDocument
enables you to simplify your code.
If you pass in XML instance documents within an IDocument
instance, do not use any namespace or prefix within the instance document text, unless the adapter or consumer of the IDocument
instance explicitly uses qualified XPath statements to query the data.
Failure to observe this rule will cause runtime failures in code using IDocument
.
Also, because the sample adapters and most clients using IDocument
do not use namespace prefixes to qualify the steps in XPath expressions, use of XML namespace declarations on XML documents represented as IDocument
instances should be avoided.
For example, an XML namespace declaration is included on the XML instance document for an Application View service. The DBMS sample adapter uses the IDocument
interface to retrieve the request data fields. IDocument
, because of the underlying processor, cannot retrieve data fields in an XML instance document with a default XML namespace using XPaths with unqualified steps.
The result is that the DBMS Sample adapter (or any code using IDocument
or the Xalan XPath to get data fields from an XML instance) does not get the proper field data from the request document.
<Input>
<FirstName>Joe</FirstName>
</Input>
The call IDocument.getDocumentData("/Input/FirstName")
returns "Joe".
Using the following document with a default namespace:
<Input xmlns="my URI">
<FirstName>Joe</FirstName>
</Input>
The call IDocument.getDocumentData("/Input/FirstName")
returns "". The XPath processor does not detect any XPath step that selects data from the my URI
namespace, just the empty namespace.
To help you implement XCCI for your adapters, the ADK provides the following classes and interfaces:
This section describes those classes and interfaces.
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 that you need to implement. Specifically, this class declares:
protected abstract boolean execute(
InteractionSpec ixSpec,
DocumentRecord inputDoc,
DocumentRecord outputDoc
) throws ResourceException
protected abstract DocumentRecord execute(
InteractionSpec ixSpec,
DocumentRecord inputDoc
) throws ResourceException
These methods are not invoked on the concrete implementation until it has been verified that the output records are DocumentRecord
objects.
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.
com.bea.adapter.cci.DocumentInteractionSpecImpl
This class allows you to save a request document definition and response document definition for a service in the InteractionSpec
provided to the execute method at run time. This capability is useful when the Interaction
for an adapter needs access to the XML schemas for a service at run time.
Note: | DocumentInteractionSpecImpl also implements the com.bea.connector.ClientDataInteractionSpec interface. This allows it to receive IClientData instances containing environment variables and other client information at runtime. For more information, see Step 5: Enable Environment Variable Support (Optional). |
A design pattern that is frequently used with the XCCI is support for the definition of services in the Interaction
implementation. When this design pattern is used, 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. As a result, the interaction must be able to generate the request and response XML schemas and additional metadata for a service. The Interaction
may 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.
The ADK provides a plug-in mechanism for using nonXML adapters with WebLogic Integration. Not all prebuilt adapters use XML as the javax.resource.cci.Record
data type. For example, XML may not be used in the following circumstances:
To facilitate implementation of these types of adapters, the ADK provides the com.bea.connector.IRecordTranslator
interface. At run time, the application integration engine uses an adapter's IRecordTranslator
implementation to translate request and response records before executing the adapter's service.
Because the application integration engine supports only 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 including a class in your adapter's EAR file that implements the IRecordTranslator
interface, the application integration engine can execute the translation methods in your translator class on each record for request and response.
There is a one-to-one correlation between an InteractionSpec
implementation class and an IRecordTranslator
implementation class. An adapter with more than one type of InteractionSpec
implementation requires an IRecordTranslator
implementation class for each. 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 name of the adapter's InteractionSpec
class is com.bea.adapter.dbms.cci.InteractionSpecImpl
, then the engine loads the com.bea.adapter.dbms.cci.InteractionSpecImplRecordTranslator
class (if the latter class is available).
For a description of the methods that must be implemented, see the Javadoc for com.bea.connector.IRecordTranslator
at the following URL:
http://download.oracle.com/docs/cd/E13214_01/wli/docs92/wli.javadoc/
javax.resource.cci.ConnectionFactory
ConnectionFactory
provides an interface for getting a connection to an EIS instance. An implementation of the ConnectionFactory
interface must be provided by an adapter.
The application looks up a ConnectionFactory
instance from JNDI namespace and uses it to get EIS connections.
To support JNDI registration, java.io.Serializable
and javax.resource.Referenceableinterfaces
must be implemented. For this purpose, an implementation class for ConnectionFactory
is required.
The ADK provides ConnectionFactoryImpl
, a concrete implementation of the javax.resource.cci.ConnectionFactory
interface that provides the following functionality:
Usually you can use this class as is, without extending it.
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.
By default, the ADK provides an implementation of this class via the com.bea.adapter.spi.AbstractConnectionMetaData
class. You must extend this abstract class and implement its four abstract methods for your adapter.
javax.resource.cci.ConnectionSpec
ConnectionSpec
is used by an application component to pass connection request-specific properties to the ConnectionFactory.getConnection()
method.
We recommend that you implement the ConnectionSpec
interface as a JavaBean so that it can support tools. Define the properties of the ConnectionSpec
implementation class through the getter and setter methods pattern.
The CCI specification defines a set of standard properties for a ConnectionSpec
. The properties are defined on either 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.
Because the ConnectionSpec
implementation must be a JavaBean, the ADK does not supply an implementation for this class.
javax.resource.cci.InteractionSpec
An InteractionSpec
holds properties for driving an interaction with an EIS instance. Specifically, 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 the 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 the InteractionSpec
interface is required to implement the java.io.Serializable
interface.
The InteractionSpec
contains information that is not in Record
but that helps to determine which EIS function to invoke.
The standard properties are described in the following table.
The following standard properties are used to give hints to an interaction instance about the ResultSet
requirements:
A CCI implementation can provide properties other than the one described in the InteractionSpec
interface.
Note: | The format and type of any additional properties are specific to an EIS; they are outside the scope of the CCI specification. |
The ADK contains a concrete implementation of javax.resource.cci.InteractionSpec
called InteractionSpecImpl
. This interface provides a base implementation that you can extend by using getter and setter methods for the standard interaction properties described in Table 6-5.
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 managing local transactions.
A local transaction is managed within a resource manager. No external transaction manager is 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 about local transactions, see Transaction Demarcation.
The javax.resource.cci.Record
interface is the base interface for representing an input to or output from the execute()
methods defined for an Interaction. For more information about 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 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 the following table.
If the adapter implements a CCI interface, the next question to consider is which record format to use for a service. For each service, a format must be specified for the request records (which provide input to the service) and response records (which provide the EIS responses).
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 the name and description of a record.
For an adapter provider who 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
.
javax.resource.cci.ResourceAdapterMetaData
The interface javax.resource.cci.ResourceAdapterMetaData
provides information about the 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 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. |
The ADK provides an interface that encapsulates adapter metadata and provides getters and setters for all properties: ResourceAdapterMetaDataImpl
.
This optional step is required if you allow the use of environment variables in service definitions. For more information on how environment variables are defined and what they mean to your adapter, see Developing a Design-Time GUI.
At runtime, your adapter uses a set of environment variables to obtain values a system administrator or application deployer has configured for use in the target environment. Use of variables generally involves replacing a variable reference within one or more property values for the service with a runtime variable value. What properties, where in the property value, and what the variable reference looks like are all adapter-specific.
In order to use environment variables, your adapter must obtain the set of environment variables intended for use with the currently executing service. Your adapter can obtain this set of variables in one of two ways.
This interface provides an IClientData
instance in the setClientData(IClientData)
method. You obtain the variable set by calling client_data_object
.getVariableSet()
method.
In this case, you listen for java.beans.PropertyChange
events in your own implementation of the java.beans.VetoableChangeListener.vetoableChange
method. IClientData
is obtained when the PropertyChangeEvent.getPropertyName()
method returns clientData
and by calling the getOldValue()
method on the event. The returned IClientData
instance can be used to obtain the variable set (IVariableSet
instance) by calling the client_data_object
.getVariableSet()
method.
Once you have obtained an IVariableSet
instance, you can retrieve variables from the set by calling getVariable()
and use the variable's value to generate a runtime property value (by replacing any variable references in the original property value).
If desired, you can listen for changes on this variable set, by implementing the com.bea.connector.VariableChangeListener
interface and adding an instance of your implementation class to the variable sets listener list by calling IVariableSet.addListener(VariableChangeListener)
method. Any time the variables in the variable set change, or their values change, you will be notified by a call to variableChange()
on your listener.
For examples of how to use environment variables at runtime, see the source code for the DBMS sample adapter located at WLI_HOME
/adapters/dbms/src
.
To help you test your adapter, the ADK provides com.bea.adapter.test.TestHarness
, a test harness that leverages JUnit, an open-source tool for unit testing. The com.bea.adapter.test.TestHarness
performs the following functions:
You can find more information about JUnit at:
To use the test harness in the ADK, complete the following steps:
junit.framework.TestCase
. The class must provide a static method named suite
that returns a new junit.framework.TestSuite
. test
.test.properties
in the project directory. (If you clone the sample adapter, then your adapter will have a base test.properties
in the project directory.) The properties file should contain any configuration properties needed for your test case.build.xml
file needs a test target that invokes the com.bea.adapter.test.TestHarness
class with the properties file for your adapter. For example, the sample adapter uses the Ant target shown in Listing 6-28.<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 the following main class: com.bea.adapter.test.TestHarness
. This class uses the classpath established for the sample adapter and passes the following command-line argument:
The sample adapter provides two basic TestCase
extensions:
NonManagedScenarioTestCase
allows you to test your SPI and CCI classes in a nonmanaged scenario. Specifically, this class tests the following:
sample.event.OfflineEventGeneratorTestCase
allows you to test the inner workings of your event generator outside WebLogic Server. Specifically, this class tests the following for the event generator:
test.properties
to the event generator for initialization so you can test your initialization logic.setupNewTypes()
and removeDeadTypes()
methods.
The sample.client.ApplicationViewClient
class offers an additional way to 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. An Ant build.xml
file provides the client target so you can use the ApplicationViewClient
program. When you execute ant
client
, the default configuration is to display the usage for the program. You can change the input parameters for the client program by editing the build.xml
file.
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. |
After implementing the SPI and CCI interfaces for an adapter, and then testing the adapter, you can deploy the adapter in a WebLogic Integration environment, either manually or from the WebLogic Server Administration Console. For complete information, see Deploying Adapters.
![]() ![]() ![]() |