bea.com | products | dev2dev | support | askBEA

Download Docs | Site Map | Glossary
Search

Developing Adapters

Developing a Service Adapter

A service adapter receives an XML request document from a client and invokes the associated function in the underlying EIS. Service adapters are consumers of messages; they may or may not provide responses. They perform the following four functions:

- They receive service requests from an external client.

- They transform an XML request document into the EIS-specific format. The request document conforms to the request XML schema for the service. The request XML schema is based on metadata in the EIS.

- They invoke the underlying function in the EIS and wait for a response from that function.

- They transform the response from the EIS-specific data format to an XML format that conforms to the response XML schema for the service. The response XML schema is based on metadata in the EIS.

This section contains information about the following subjects:

- Service Adapters in a Run-Time Environment

- Flow of Events

- Step 1: Research Your Environment Requirements

- Step 2: Configure the Development Environment

- Step 3: Implement the SPI

- Step 4: Implement the CCI

- Step 5: Test the Adapter

- Step 6: Deploy the Adapter

J2EE-Compliant Adapters Not Specific to WebLogic Integration

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.

Service Adapters in a Run-Time Environment

Figure 6-1 and Figure 6-2 show the processes that are executed when a service adapter is used in a run-time environment. Figure 6-1 shows an asynchronous service adapter; Figure 6-2, a synchronous adapter.

Figure 6-1 Asynchronous Service Adapter in a Run-Time Environment

Figure 6-2 Synchronous Service Adapter in a Run-Time Environment

Flow of Events

Figure 6-3 outlines the steps required to develop a service adapter.

Figure 6-3 Flow of Events in Service Adapter Development Process

Step 1: Research Your Environment Requirements

Before you start developing your service adapter, 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.

- Identify the required EIS and the service appropriate for it.

Based on your knowledge of the EIS, identify the interface to the back-end functionality.

- Identify the expensive connection object.

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.

- Identify your security needs.

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:

http://java.sun.com/j2ee/

- Identify the type of transaction support needed for your adapter.

Decide which of the following types of transaction demarcation support to implement with your adapter:

- Local transaction demarcation

- XA-compliant transaction demarcation

Note: For more information about transaction demarcation support, see Transaction Demarcation, or see:

>     http://java.sun.com/blueprints/guidelines/designing_enterprise_applications/transaction_management/platform/index.html

Step 2: Configure the Development Environment

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.

Step 2a: Set Up the Directory Structure

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.

Table 6-1 ADK Directory Structure

Pathname | Description
--- | ---
adapters | Directory containing the ADK.
adapters/src/war | Directory containing .jsp files, images, and so on. All files in this directory should be included in the WAR file for an adapter.
adapters/utils | Directory containing files used by the build process, including a file that timestamps JAR files.
adapters/dbms | Directory containing a sample J2EE-compliant adapter built with the ADK.
adapters/dbms/docs | Directory that should contain the user guide, release notes, and installation guide for the sample adapter.
adapters/sample | Directory containing a sample adapter that you can use to start developing your own adapter.
adapters/sample/project | 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.
adapters/sample/src | Directory containing all the source code for an adapter. The decision about whether to provide source code with your adapter is yours.
adapters/sample/src/ BEA_WLS_SAMPLE_ADK.properties | File containing messages used by the adapter for internationalization and localization.
adapters/sample/src/ BEA_WLS_ SAMPLE_ADK.xml | File that provides a basic configuration file for the logging framework. You should use this file to develop your own adapter logging configuration file.
adapters/sample/src/ eventrouter/WEB-INF/web.xml | Configuration file for the event router Web application.
adapters/sample/src/rar/ META- INF/ra.xml | File containing configuration information about a J2EE-compliant adapter. Use this file as a guide to which parameters are needed by the ADK run-time framework.
adapters/sample/src/rar/META- INF/weblogic-ra.xml | File containing configuration information for a J2EE-compliant adapter that is specific to the WebLogic Server J2EE engine. Use this file as an example for setting up the weblogic-ra.xml file for your adapter. The file is required for WebLogic Server.
adapters/sample/src/sample | Directory containing the source code for the adapter.
adapters/sample/src/war | Directory containing .jsp files, .html files, images, and so on. All files in this directory should be included in the Web application archive (.war) file for an adapter.
adapters/sample/src/war/WEB- INF/web.xml | Web application descriptor.
adapters/sample/src/war/WEB-INF/ weblogic.xml | File containing WebLogic Server-specific attributes for a Web Application.
adapters/sample/src/ear/META-INF/application.xml | J2EE application that contains a connector and a Web application for configuring application views for the adapter.

Modifying the Directory Structure

When you clone a development tree by using GenerateAdapterTemplate, the contents of all the directories under 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/docs/api/index.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.

Step 2b: Assign the Adapter Logical Name

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:

vendor_EIS-type_EIS-version

For example:

BEA_WLS_SAMPLE_ADK

For more information about the logical name of an adapter, see Adapter Logical Name.

Step 2c: Set Up the Build Process

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.

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 wlai-core.jar
>       wlai-client.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 preceeding 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:

Listing 6-2

>     <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}/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},
>       ${EVENTROUTER_WAR_FILE}'/>
>     </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.

build.xml Components

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.

1. The first line sets the name attribute of the root project element:

   >      <project name='BEA_WLS_SAMPLE_ADK' default='all' basedir='.'>

2. Names are assigned to the archive files (JAR, WAR, and RAR files), as shown in the following example listing.

Listing 6-3 Setting Archive Filenames

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

1. The standard properties for the ADK are listed as shown in Listing 6-4.

Listing 6-4 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_CORE' value='${WLI_LIB_DIR}/
>       wlai-core.jar'/>
>     <property name='WLAI_CLIENT' value='${WLI_LIB_DIR}/
>       wlai-client.jar'/>
>     <property name='WLAI_COMMON' value='${WLI_LIB_DIR}/
>       wlai-common.jar'/>
>     <property name='WLAI_EVENTROUTER' value='${WLI_LIB_DIR}/
>       wlai-eventrouter.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.

1. The classpath is set up for compiling as shown in the following listing.

Listing 6-5 Setting the Classpath

>       <path id='CLASSPATH'>
>         <pathelement location='${SRC_DIR}'/>
>         <pathelement   path='${ADK}:${ADK_EVENTGENERATOR}:
>                   ${ADK_WEB}:${ADK_TEST}:${WEBTOOLKIT}:${WLAI_CORE}:
>                   ${WLAI_EVENTROUTER}:${WLAI_CLIENT}'/>
>         <pathelement path='${WEBLOGIC_JAR}:${env.BEA_HOME}'/>
>         <pathelement path='${JUNIT}:${HTTPUNIT}:${TIDY}'/>
>       </path>

After this information, you have the option of calling any of the following three combinations of files:

- All the binaries and archives for the adapter, as shown in the following sample listing

Listing 6-6 Sample of Calling All Binaries and Archives

>     <!-- This target produces all the binaries and archives
>        for the adapter -->
>     <target name='all' depends='ear'/>

- All the binaries and archives for the adapter, plus the Javadoc:

>     <target name='release' depends='all,apidoc'/>

- A version_info file for inclusion with the archive files, as shown in Listing 6-7.

Listing 6-7 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}'/>
>           </classpath>
>        </java>
>     </target>

1. The contents of the JAR file for the adapter are specified: run-time aspects of the adapter are included in the main JAR, while additional classes, such as the design-time GUI support classes, are included in the WAR or other JAR files, as shown in the following listing.

Listing 6-8 Sample Code for Setting Values in a JAR File

>     <target name='jar' depends='packages,version_info'>
>        <delete file='${LIB_DIR}/${JAR_FILE}'/>
>        <mkdir dir='${LIB_DIR}'/>
>        <jar jarfile='${LIB_DIR}/${JAR_FILE}'>

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

Listing 6-9 Sample Code for Including the Includes List

>     <fileset dir='${SRC_DIR}'
>        includes='sample/cci/*.class,sample/spi/*.class,
>        sample/eis/*. class,*.xml,*.properties'/>

1. Version information about the JAR file is provided, as shown in the following listing.

Listing 6-10 Setting JAR File Version Information

>     <!-- Include version information about the JAR file -->
>        <fileset dir='${basedir}'
>                          includes='version_info.xml'/>
>     </jar>

1. The J2EE adapter archive (RAR) file is created. This file should contain all the classes and JAR files needed by the adapter. It can be deployed on any J2EE-compliant application server on which the adapter depends. Our example adapter includes the following targets:

   - Version information for this RAR file

   - The deployment descriptor for the adapter

   The following listing shows how the RAR file for the sample adapter is created.

Listing 6-11 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>

1. The J2EE Web application archive (WAR) file is created. This file also includes code that cleans up the existing environment.

Listing 6-12 Sample Code for 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

>     -->

1. All JAR files needed by the Web application are included in the <lib> component of the build.xml file.

Listing 6-13 Including JAR Files Needed by Web Application

>     <lib dir='${WLI_LIB_DIR}' includes='adk-web.jar,
>       webtoolkit.jar,wlai-client.jar'/>

1. The EAR file is included.

Listing 6-14 Including the 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'/>
>          </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,
>                       wlai-core.jar,wlai-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}'/>
>          <delete file='${LIB_DIR}/${JAR_FILE}'/>

>     </target>

Because an event router specific to the EAR deployment cannot be deployed by itself, it is called from within the EAR target, as shown in the following listing.

Listing 6-15 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}'/>
>            <libdir='${WLI_LIB_DIR}'
>             includes='adk-eventgenerator.jar,
>             wlai-eventrouter.jar'/>

>         </war>

Within the EAR target shown in the previous listing you can also find all common or shared JAR files, as shown in the following listing.

Listing 6-16 Including 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,
>                   wlai-core.jar,wlai-client.jar'/>

>     </jar>

1. All the Java source files for this project are compiled.

Listing 6-17 Compiling Java Source

>     <target name='packages'>
>         <echo message='Building ${ant.project.name}...'/>
>         <javac srcdir='${SRC_DIR}'
>                   excludes='war/jsp_servlet/**'
>                   deprecation='true' debug='true'>
>            <classpath refid='CLASSPATH'/>
>         </javac>
>     </target>

1. Construct the EventRouter JAR file, as shown in the following listing.

Listing 6-18 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>

1. Produce the J2EE WAR file, the event router used for stand-alone deployment, as shown in the following listing.

Listing 6-19 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,wlai-core.jar,
>                   wlai-eventrouter.jar,wlai-client.jar''/>
>         </war>
>     </target>

1. The Javadoc is generated.

Listing 6-20 Generating Javadoc

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

1. The targets that clean the files created by their counterparts are listed.

Listing 6-21 Including Cleanup 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='${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_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 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.

For instructions on creating a message bundle, see the JavaSoft tutorial on internationalization at:

http://java.sun.com/docs/books/tutorial/i18n/index.html

Step 3: Implement 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.

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.

Basic SPI Implementation

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.

ManagedConnectionFactory

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.

Transaction Demarcation

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:

- XA-compliant transactions

- Local transactions

XA-Compliant Transaction

In a distributed transaction processing (DTP) environment, a javax.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.

Local Transaction

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:

>     http://java.sun.com/blueprints/guidelines/
>     designing_enterprise_applications/transaction_management/
>     platform/index.html

ADK Implementations

The ADK provides an abstract foundation for an adapter called the AbstractManagedConnectionFactory. This foundation provides the following features:

- Basic support for internationalization and localization of exception and log messages for an adapter

- Hooks into the logging toolkit

- Getter and setter methods for standard connection properties (username, password, server, connectionURL, and port)

- Access to adapter metadata gathered from a java.util.ResourceBundle for an adapter

- Support for the ability to plug license checking into the initialization process for the factory. If license verification fails, client applications cannot get a connection to the underlying EIS, which makes the adapter useless.

- State verification checking to support JavaBeans-style post-constructor initialization

You must provide your own implementations for the following key methods:

- createConnectionFactory()

- createManagedConnection()

- checkState()

- equals()

- hashCode()

- matchManagedConnections()

The following sections describe these methods.

createConnectionFactory()

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.

Listing 6-22 createConnectionFactory() Example

>     protected Object
>         createConnectionFactory(ConnectionManager connectionManager,
>                                 String strAdapterName,
>                                 String strAdapterDescription,
>                                 String strAdapterVersion,
>                                 String strVendorName)
>         throws ResourceException

createManagedConnection()

createManagedConnection() is used to construct a ManagedConnection instance for your adapter. The following listing shows an example of this method.

Listing 6-23 createManagedConnection() Example

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.

checkState()

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

equals()

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)

hashCode()

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

matchManagedConnections()

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.

Listing 6-24 compareCredentials() Implementation

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

Listing 6-25 Extracting a PasswordCredential

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

Listing 6-26 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 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;

Explanation of the Implementation

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-27) 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().

Listing 6-27 matchManagedConnections() Method Implementation

>     public ManagedConnection
>     matchManagedConnections(Set connectionSet,
>                                 Subject subject,
>                                 ConnectionRequestInfo info)
>             throws ResourceException

This class uses the following approach to match a connection:

1. For each object in the set, it iterates over the appropriate connectionSet until a match is found. Then it determines whether the object is an AbstractManagedConnection class.

2. If it is, this connection is compared to the ManagedConnectionFactory for the AbstractManagedConnection from the set.

3. If the factories are equal, then the compareCredentials() method is invoked on the AbstractManagedConnection.

4. If the compareCredentials() method returns true, then the instance is returned.

AbstractManagedConnectionFactory Properties Required at Deployment

To use the base implementation of AbstractManagedConnectionFactory, you must, at deployment time, provide the properties described in the following table.

Table 6-2 AbstractManagedConnectionFactory Properties

Property Name | Property Type | Applicable Values | Description | Default
--- | --- | --- | --- | ---
LogLevel | java.lang. String | ERROR, WARN, INFO, DEBUG | Logs verbosity level | WARN
LanguageCode | java.lang. String | For a valid ISO language code, see http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt . | Determines the desired locale for log messages | en
CountryCode | java.lang. String | For a valid ISO country code, see http://www.chemie. fu-berlin.de/ diverse/doc/ISO_3166.html . | Determines the desired locale for log messages | US
MessageBundleBase | java.lang. String | Any valid Java class name or filename | Determines the message bundle for log messages | None, required
LogConfigFile | java.lang. String | Any valid filename | Configures the LOG4J system | None, required
RootLogContext | java.lang. String | Any valid Java string | Categorizes log messages from this connection factory | None, required
AdditionalLog Context | java.lang. String | Any valid Java string | Adds additional information to uniquely identify messages from this factory | None, optional

Other Key ManagedConnectionFactory Features in the ADK

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

ManagedConnection

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.

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

- Provides access to the ADK logging framework

- Manages a collection of connection event listeners

- Provides convenience methods for notifying all connection event listeners of connection-related events

- Simplifies the cleanup and destruction of a ManagedConnection instance

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

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:

- Simplifies exception handling

- Provides access to an AbstractManagedConnection instance

- Allows you to focus on implementing EIS-specific logic

- Makes it unnecessary for you to have separate metadata classes for the CCI and SPI implementations

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

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:

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

- Logs connection-related events using the ADK logging framework

- Destroys ManagedConnection instances when a connection-related error occurs

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 that can be used by 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 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.

ConnectionRequestInfo

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.

ADK Implementation

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.

LocalTransaction

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.

ADK Implementation

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:

- Simplifies exception handling

- Allows adapter providers to focus on implementing EIS-specific transaction logic

- Makes it unnecessary to have separate metadata classes for the CCI and SPI implementations

Step 4: Implement the CCI

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.

How to Use This Section

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.

Basic CCI Implementation

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 connection

- Interaction, 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:

- ConnectionFactory

- ConnectionMetaData

- ConnectionSpec

- InteractionSpec

- LocalTransaction

- Record

- ResourceAdapterMetaData

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 implementation provides the following functionality:

- Access to the ADK logging framework

- Access to an AbstractManagedConnection instance

- State management and assertion checking

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:

- Returns an Interaction instance

- Throws a ResourceException if the create operation fails

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

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

ADK Implementation

The ADK provides an implementation of this interface called AbstractInteraction. This implementation:

- Provides access to the ADK logging framework

- Manages warnings

You must supply a concrete extension to AbstractInteraction that implements execute(). Two versions of execute() are available. They are described in the following sections.

execute() Version 1

The execute() method declared in Listing 6-28 shows an interaction represented by InteractionSpec.

Listing 6-28 Example of execute() Version 1

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

- Returns true if execution of the EIS function is successful and the output (Record) has been updated; otherwise it returns false.

- Throws ResourceException if the execute operation fails.

The parameters for execute() version 1 are described in the following table.

Table 6-3 Parameters for execute() Version 1

Parameter | Description
--- | ---
ispec | InteractionSpec representing a target EIS data or function module
input | Input record
output | Output record

execute() Version 2

The execute() method declared in Listing 6-29 also executes an Interaction represented by InteractionSpec.

Listing 6-29 Example of execute() Version 2

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

This method:

- Returns an output Record if execution of the EIS function has been successful; otherwise it throws an exception.

- Throws ResourceException if the execute operation fails.

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.

Table 6-4 Parameters for execute() Version 2

Parameter | Description
--- | ---
ispec | InteractionSpec representing a target EIS data or function module
input | Input record

Using XCCI to Implement the CCI

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.

Services

A service represents functionality available in an EIS. It includes four components:

- Unique business name

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.

- Request document definition

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.

- Response document definition

A response document definition describes the output of a service.

- Additional metadata

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.

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

IDocument

com.bea.document.IDocument

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-30 shows how XML is used to record details about a person named Bob.

Listing 6-30 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 XPath code shown in Listing 6-31.

Listing 6-31 Sample Code for Retrieving IDocument Data

>     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-32 to submit a query.

Listing 6-32 Sample Code for Retrieving DOM Data

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

ADK-Supplied XCCI Classes

To help you implement XCCI for your adapters, the ADK provides the following classes and interfaces:

- AbstractDocumentRecordInteraction

- DocumentDefinitionRecord

- DocumentInteractionSpecImpl

- IProxiedMarker

- IProxiedConnection

This section describes those classes and interfaces.

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 that 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 are not invoked on the concrete implementation until it has been verified that the output records 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 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.

IProxiedMarker and IProxiedConnection Interfaces

com.bea.connector.IProxiedConnection
com.bea.connector.IProxiedMarker

The IProxiedMarker interface is implemented by the com.bea.adapter.cci.ConnectionFactoryImpl class. The marker is used to determine whether the associated connection is a proxy object. The IProxiedConnection interface is implemented by the com.bea.adapter.cci.AbstractConnection class and is used to return the real connection associated with the proxy. The IProxiedConnection interface has one method, getAdapterConnection(). The getAdapterConnection method is defined in the AbstractConnection class returning the pointer. The IProxedConnection interface is required because a proxy can return only those Interfaces that it implements. A proxy cannot distinguish class objects in its derivation tree.

XCCI Design Pattern

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.

Using NonXML J2EE-Compliant Adapters

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:

- You have developed a J2EE-compliant adapter with a proprietary record format.

- You have purchased a third-party J2EE-compliant adapter that uses a proprietary record format in the adapter's CCI layer.

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 in the following directory:

WLI_HOME/docs/apidocs/com/bea/connector/IRecordTranslator.html

ConnectionFactory

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.

ADK Implementation

The ADK provides ConnectionFactoryImpl, a concrete implementation of the javax.resource.cci.ConnectionFactory interface that provides the following functionality:

- Access to the ADK logging framework

- Access to adapter metadata

- Implementation of the getConnection() method

Usually you can use this class as is, without extending it.

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

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.

ADK Implementation

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

Table 6-5 Standard InteractionSpec Properties

Property | Description
--- | ---
FunctionName | Name of an EIS function
InteractionVerb | Mode of interaction with an EIS instance: SYNC_SEND, SYNC_SEND_RECEIVE, or SYNC_RECEIVE
ExecutionTimeout | The number of milliseconds an Interaction waits for an EIS to execute the specified function

The following standard properties are used to give hints to an interaction instance about the ResultSet requirements:

- FetchSize

- FetchDirection

- MaxFieldSize

- ResultSetType

- ResultSetConcurrency

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.

ADK Implementation

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.

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

Record

javax.resource.cci.Record

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.

Table 6-6 Record Interface Representations

Representation | Description
--- | ---
MappedRecord | A set of key-value pairs that represents a record. This interface is based on the java.util.Map.
IndexedRecord | An ordered and indexed collection representing a record. This interface is based on the java.util.List.
JavaBean-based representation of an EIS abstraction | An example is a custom record generated to represent a purchase order in an ERP system.
javax.resource.cci. ResultSet | This interface extends both java.sql.ResultSet and javax.resource.cci.Record. A ResultSet represents tabular data.

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

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

ResourceAdapterMetaData

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.

ADK Implementation

The ADK provides an interface that encapsulates adapter metadata and provides getters and setters for all properties: ResourceAdapterMetaDataImpl.

Step 5: Test the Adapter

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:

- Reads a properties file containing test configuration information

- Initializes the logging toolkit

- Initializes JUnit TestSuite

- Loads test classes and executes them using JUnit

- Allows you to test code offline and outside WebLogic Server

You can find more information about JUnit at:

http://www.junit.org

Using the Test Harness

To use the test harness in the ADK, complete the following steps:

1. Create a class that extends junit.framework.TestCase. The class must provide a static method named suite that returns a new junit.framework.TestSuite.

2. Implement test methods. The name of each method should begin with test.

3. Create or alter the 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.

4. Invoke the test using Ant. Your Ant 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-33.

Listing 6-33 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 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:

-DCONFIG_FILE=test.properties

Test Case Extensions Provided by the ADK

The sample adapter provides two basic TestCase extensions:

- sample.spi.NonManagedScenarioTestCase

- sample.event.OfflineEventGeneratorTestCase

sample.spi.NonManagedScenarioTestCase

NonManagedScenarioTestCase allows you to test your SPI and CCI classes in a nonmanaged scenario. Specifically, this class tests the following:

- Initialization of the ManagedConnectionFactory implementation.

- Serialization or deserialization of the ManagedConnectionFactory instance.

- Opening of a connection to the EIS.

- Closing of a connection to the EIS. Make sure all associated resources are closed when a connection is closed.

sample.event.OfflineEventGeneratorTestCase

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:

- It simulates the event router and instantiates a new instance of the adapter's event generator.

- It passes the test.properties to the event generator for initialization so you can test your initialization logic.

- It refreshes the event generator randomly so you can test your setupNewTypes() and removeDeadTypes() methods.

- It receives event postings and displays them in the log file for the adapter.

sample.client.ApplicationViewClient

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.

Step 6: Deploy the Adapter

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.