Developing Adapters

     Previous  Next    Open TOC in new window  Open Index in new window  View as PDF - New Window  Get Adobe Reader - New Window
Content starts here

Developing a Service Adapter

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:

 


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 Connections in a Run-Time Environment

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-1 Asynchronous Service Connection in a Run-Time Environment

Asynchronous Service Connection in a Run-Time Environment

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

Synchronous Service Connection in a Run-Time Environment

 


Flow of Events

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

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

Flow of Events in Service Connection Development Process

 


Step 1: Research Your Environment Requirements

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.

 


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/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
-base.properties
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.
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/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. See The web.xml and weblogic.xml Descriptor Files for details.
adapters/sample/src/war/WEB-INF/ weblogic.xml
File containing WebLogic Server-specific attributes for a Web Application. See The web.xml and weblogic.xml Descriptor Files for details.
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.

The web.xml and weblogic.xml Descriptor Files

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:

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.

Creating A Development Tree Within the Directory Structure

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.

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

Listing 6-2 Shared JAR File Creation
<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.

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:
  2.  <project name='BEA_WLS_SAMPLE_ADK' default='all' basedir='.'>
  3. The following line reads the value of the WL_HOME environment variable from your system.
  4. <property environment="env" />
  5. The location of the weblogic.jar file and the integration home directory (WLI_HOME) are defined, ensuring access to required parsers and J2EE packages:
  6. <property name="WEBLOGIC_JAR" value="${env.WL_HOME}/lib/weblogic.jar" />
    <property name="WLI_HOME" value="${basedir}/../../.." />
  7. Names are assigned to the archive files (JAR, WAR, and RAR files), as shown in the following example listing. Note that as of WebLogic Integration 8.1 the EventRouter is no longer a separate component within the adapter, so its JAR and WAR files are no longer built
  8. Listing 6-3 Setting Archive Filenames
    <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" />
  9. The standard properties for the ADK are listed as shown in Listing 6-4.
  10. Listing 6-4 Standard ADK Properties
    <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.

  11. The classpath is set up for compiling as shown in the following listing.
  12. 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_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:

    • All the binaries and archives for the adapter
    • 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
  13. 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.
  14. Listing 6-6 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}'>

    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-7 Sample Code for Including the Includes List
    <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.

    Listing 6-8 Setting JAR File Version Information
    <!-- Include version information about the JAR file -->
       <fileset dir='${basedir}'
                         includes='version_info.xml'/>
    </jar>
  15. The JAR file for the dummy EIS used by this adapter is created. The classes making up this dummy EIS are placed in a separate JAR file to allow for the control of which ClassLoader loads these classes. You can remove this target and any references to it when implementing your own EIS communication logic.
  16. Listing 6-9 Sample Code for Creating the Dummy EIS
    <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>
  17. 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-10 Sample Code for Creating the Connection Architecture RAR File
      <target name='rar' depends='jar'>
      <delete file='${LIB_DIR}/${RAR_FILE}'/>
         <mkdir dir='${LIB_DIR}'/>
         <jar jarfile='${LIB_DIR}/${RAR_FILE}'
           manifest='${SRC_DIR}/rar/META-INF/MANIFEST.MF'>
            <fileset dir='${SRC_DIR}/rar'includes='META-INF/ra.xml,
              META-INF/weblogic-ra.xml' excludes=
              'META-INF/MANIFEST.MF'/>
         </jar>
      </target>
  18. The J2EE Web application archive (WAR) file is created. This file also includes code that cleans up the existing environment.
  19. Listing 6-11 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' 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.

    Listing 6-12 Including JAR Files Needed by Web Application
    <lib dir='${WLI_LIB_DIR}' includes='adk-web.jar,
    webtoolkit.jar,wlai-client.jar'/>
  20. The EAR file is created. This listing also shows all common or shared JAR files.
  21. Listing 6-13 Including the EAR File
    <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>
  22. All the Java source files for this project are compiled.
  23. Listing 6-14 Compiling Java Source
    <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>
  24. The Javadoc is generated.
  25. Listing 6-15 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>
  26. The targets that clean the files created by their counterparts are listed.
  27. Listing 6-16 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_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>

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.

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

 


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:

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

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

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-17 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-18 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-19 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-20 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-21 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-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().

Listing 6-22 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
Determines the desired locale for log messages
en
CountryCode
java.lang.
String
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:

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:

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:

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:

 


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:

If possible, implement these interfaces in the order specified here.

In addition, you can implement any of the following interfaces needed for your adapter:

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:

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:

Interaction

javax.resource.cci.Interaction

The javax.resource.cci.Interaction enables a component to execute EIS functions. An Interaction instance supports the following ways of interacting with an EIS instance:

An Interaction instance is created from a connection and is required to maintain 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:

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-23 shows an interaction represented by InteractionSpec.

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

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-24 also executes an Interaction represented by InteractionSpec.

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

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:

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

Listing 6-25 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-26.

Listing 6-26 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-27 to submit a query.

Listing 6-27 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.

Proper Use of Namespaces in IDocument Instances

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.

Given the following 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.

ADK-Supplied XCCI Classes

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

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.

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

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:

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/

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:

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:

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: Enable Environment Variable Support (Optional)

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.

Implementing ClientDataInteractionSpec

This interface provides an IClientData instance in the setClientData(IClientData) method. You obtain the variable set by calling client_data_object.getVariableSet() method.

Extending DocumentInteractionSpecImpl

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.

 


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

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-28.
  5. Listing 6-28 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

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

sample.event.OfflineEventGeneratorTestCase

sample.event.OfflineEventGeneratorTestCase allows you to test the inner workings of your event generator outside WebLogic Server. Specifically, this class tests the following for the event generator:

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


  Back to Top       Previous  Next