OracleAS Portal Developer Kit (PDK)
JCA Data Source Adapter

Creation Date: October 21, 2002
Status: Production
Version: PDK Release 2, (9.0.2.4 and later)

Introduction

J2EE Connector Architecture (JCA) is a specification to implement adapters for the connectivity to enterprise applications. This document will describe the requirement and syntax to add a JCA Data Source adapter into an Oracle portlet. 

OracleAS Portal JCA Data Source provides a framework to plug-in a JCA adapter as a data source to portlets. The user needs to implement the JCA adapter to plug into the portlet JCA Data Source. The adapter implementation will handle fetching data from the backend enterprise application. The portlet with the JCA Data Source will use the implemented adapter to fetch data from the remote application. To create the JCA adapter to plug into Portlet JCA data source, it is required to implement certain interfaces as specified by the JCA specification. 

Once the adapter is implemented, the user will define the data source for the portlet and plug in the adapter to the data source in the provider.xml definition file. The adapter implementation classes can have any number of custom properties as long as they are implemented following the JavaBean style. All exposed custom properties must have associated "set" methods in their respective implementation classes. Those properties can be used to set the values while describing the adapter in the data source definition. 

The portlet loader loads the portlet definition from the provider definition file. It loads the class corresponding to the tags defined in the definition. Any sub tag used under a tag will be used as a bean property name for the class and the loader will call the corresponding "set" method for the property with the value specified in the definition.

Definition

The JCA data source definition contains a set of predefined tags to describe a JCA data source adapter.  Some of the tags will point to the adapter classes for their implementations and the plugged in adapter must implement them. 

Adapter implemented classes can support any number of properties to be set. The classes must be implemented as JavaBeans and must have "set" methods for the corresponding properties. These properties can be used in the definition as sub-tags to the tag that the class implements.

Data Source Definition Tags

Provider Definition Tags Description
connectionHandler This is a container tag to contain adapter defined connection definitions. 
     

      

connectionFactory The implementation of this tag will be provided by the adapter. It must point to an implementation class of the ConnectionFactory interface of JCA.
connectionSpec Points to an adapter defined class implementing ConnectionSpec interface of JCA.
interactionHandler A container class to contain adapter defined interaction definitions. 
       interactionSpec Points to an adapter defined class implementing InteractionSpec interface of JCA. 
inputRecordHandler Container tag to describe the input record. 
      

      

recordName Name of a record that is available in the record factory metadata of the adapter. The created record can be of two types, either javax.resource.cci.MappedRecord or javax.resource.cci.IndexedRecord according to the JCA specification. If the record name is not provided, the data source will create a javax.resource.cci.MappedRecord as an input record. Record elements defined are used to set the values to the created record.
recordElement A tag to define record elements. This tag contains a name value pair. If the created record is of type javax.resource.cci.MappedRecord, the values are set by the name. If the record is of javax.resource.cci.IndexedRecord type, names are ignored and the values are set according to their sequence of definition. This tag supports the following tags.
  name Name of the element expected by the record.
value Value of the element to set.

The inputRecordHandler tag can have multiple recordElement tag defined under it.

Adapter Implemented Tags 

The adapter implementation needs to implement classes referenced in the following tags:

All the implementation classes MUST have at least one constructor without parameters. 

Implementation

The adapter implementation must implement the following JCA interfaces.

The Sample

The following sections describes a sample adapter implementation. The sample implementation will connect to an URL to get XML data, to keep the backend application integration part simple. It will demonstrate how to create an adapter to plug into the JCA data source. It implements required interfaces and provides data to the JCA data source driver.

Sample Adapter With Data Source 

The sample adapter implements a very simple backend that returns records from an XML data file depending on the value of the input record elements. The main aim for the sample adapter is to explain how to plug in an adapter into the JCA data source. 
It supports two methods,
    - getEmployee: returns a single record of an employee identified by "EmployeeNumber" element name of input record.
    - getEmployeesUnderManager: returns all employees under a manager identified by "ManagerEmployeeNumber" element name of input record.

The sample provider is described in the provider.xml file under <oc4j_install_home>/applications/portalTools/sample/WEB-INF/providers/omniPortletSample folder. The provider description file contains description of portlets. The tags are defined along with their implementing class names following this syntax,

<tag class="class_name_implementing_the_tag">

To use the JCA data source in a portlet we need to define the dataSource tag  under data tag in the provider.xml file as follows.

<dataSource class="oracle.webdb.reformlet.data.jca.JCASourceDefinition">
 <version>1.0</version>
 <name>JCASampleDS</name>

  <!-- Adapter definition will be here -->
  ...  

</dataSource>


Now we will plug in our adapter into the data source. 

Connection Definition

We will first define connections. We define connectionHandler that takes a factory class to create a connection to the custom adapter. 

<dataSource class="oracle.webdb.reformlet.data.jca.JCASourceDefinition">
 <version>1.0</version>
 <name>JCASampleDS</name>

  <!-- Adapter definition follows -->
  <connectionHandler class="oracle.webdb.reformlet.data.jca.ConnectionHandler">
    <connectionFactory class="oracle.portal.sample.portalTools.devguide.jcasample.SampleConnectionFactory"/>
    <connectionSpec class="oracle.portal.sample.portalTools.devguide.jcasample.SampleConnectionSpec">
      <userName>scott</userName>
      <password>tiger</password>
      <dataLocation>data/employees.xml</dataLocation>

(You probably want to note where the relative URL is pointing to - I know they can search for the file but it would be useful if we can at least give them a hint).
    </connectionSpec>
  </connectionHandler>

</dataSource>

The tags connectionFactory and connectionSpec are implemented by the sample adapter through SampleConnectionFactory and SampleConnectionSpec classes respectively. These classes MUST have default constructors. They can support any number of properties to be set as long as the implementation follows JavaBean style.

For this sample adapter, the SampleConnectionFactory does not support any property to set. But the SampleConnectionSpec supports three properties to be set through the definition. They are
    - userName: This sample adapter supports only one user name, "scott".
    - password: The password will always be "tiger".
    - dataLocation: The location of the data file.
We pretend that only the user "scott" with password "tiger" can use this adapter. This is not a recommended security solution but only there to demonstrate how the parameters can be set for the ConnectionSpec class implementations. Another adaptor could have a different set of properties required for the underlying application. The ConnectionFactory class uses the ConnectionSpec to cerate a Connection class that connects to the sample adapter.

The SampleConnectionSpec implements the ConnectionSpec interface and defines "set" methods corresponding to the properties it exposes.

public class SampleConnectionSpec implements ConnectionSpec
{
  private String mUserName = null;
  private String mPassword = null;
  private String mDataLocation = null;
  ...

  public void setUserName(String val)
  {
    mUserName = val;
  }

  public void setPassword(String val)
  {
    mPassword = val;
  }

  public void setDataLocation(String val)
  {
    mDataLocation = val;
  }

  ...

}

The framework loads the class with the properties set to the values defined in the definition file. The SampleConnectionFactory creates SampleConnection class by using the SampleConnectionSpec properties. This class then creates an Interaction class.

Interaction Definition

Interactions are defined under the interactionHandler tag. This tag supports interactionSpec tag that is to be implemented by the adapter. The adapter needs to define this tag only if it is required to set some properties to execute an interaction. 

<dataSource class="oracle.webdb.reformlet.data.jca.JCASourceDefinition">
 <version>1.0</version>
 <name>JCASampleDS</name>

  <!-- Adapter definition follows -->
  <connectionHandler class="oracle.webdb.reformlet.data.jca.ConnectionHandler">
    <connectionFactory class="oracle.portal.sample.portalTools.devguide.jcasample.SampleConnectionFactory"/>
    <connectionSpec class="oracle.portal.sample.portalTools.devguide.jcasample.SampleConnectionSpec">
      <userName>scott</userName>
      <password>tiger</password>
      <dataLocation>data/employees.xml</dataLocation>
    </connectionSpec>
  </connectionHandler>

  <interactionHandler class="oracle.webdb.reformlet.data.jca.InteractionHandler">
    <interactionSpec class="oracle.portal.sample.portalTools.devguide.jcasample.SampleInteractionSpec">
      <methodName>getEmployeesUnderManager</methodName>
      <maxRow>5</maxRow>
    </interactionSpec>
  </interactionHandler>

</dataSource>

The sample adapter implements the interactionSpec tag through SampleInteractionSpec class. This tag supports two sub tags,
    - methodName: Name of the method to call.
    - maxRow: Maximum number of rows present in the returned result set.
SampleInteractionSpec defines the corresponding "set" methods to set the values of these tags.

public class SampleInteractionSpec implements InteractionSpec
{
  private String mMethodName = null;
  private int mMaxRow = 5;

  ...

  public void setMethodName(String val)
  {
    mMethodName = val;
  }
  public void setMaxRow(String val)
  {
    mMaxRow = Integer.parseInt(val);
  }

  ...

}

JCA data source driver creates an Interaction object from the Connection object. The sample adapter's SampleConnection class creates a SampleInteraction class. JCA data source driver then calls execute(...) on the Interaction class by passing the InteractionSpec and the input record.

Input Record Definition

Input records are defined under the inputRecordHandler tag. This tag supports two sub tags, recordName and recordElement. The tag recordName identifies a record stored in the metadata repository of the adapter. Tag recordElement defines the element names and their values of the record. 

If the recordName is given, JCA data source creates the record from the RecordFactory of the adapter. The created record can be either javax.resource.cci.MappedRecord or javax.resource.cci.IndexedRecord  type as specified by JCA. If the record name is not given, the data source creates a javax.resource.cci.MappedRecord for the adapter. 

The tag recordElement represents elements to be set for the created record. The tag defines a name value pair. If the record created is of javax.resource.cci.MappedRecord type, the element values are set by name. For javax.resource.cci.IndexedRecord type record, the name is ignored and the values are set following the sequence they are defined.

<dataSource class="oracle.webdb.reformlet.data.jca.JCASourceDefinition">
 <version>1.0</version>
 <name>JCASampleDS</name>

  <!-- Adapter definition follows -->
  <connectionHandler class="oracle.webdb.reformlet.data.jca.ConnectionHandler">
    <connectionFactory class="oracle.portal.sample.portalTools.devguide.jcasample.SampleConnectionFactory"/>
    <connectionSpec class="oracle.portal.sample.portalTools.devguide.jcasample.SampleConnectionSpec">
      <userName>scott</userName>
      <password>tiger</password>
      <dataLocation>data/employees.xml</dataLocation>
    </connectionSpec>
  </connectionHandler>

  <interactionHandler class="oracle.webdb.reformlet.data.jca.InteractionHandler">
    <interactionSpec class="oracle.portal.sample.portalTools.devguide.jcasample.SampleInteractionSpec">
      <methodName>getEmployeesUnderManager</methodName>
      <maxRow>5</maxRow>
    </interactionSpec>
  </interactionHandler>

  <inputRecordHandler class="oracle.webdb.reformlet.data.jca.InputRecordHandler">
    <recordElement class="oracle.webdb.reformlet.data.jca.RecordElement">
      <name>ManagerEmployeeNumber</name>
      <value>740</value>
    </recordElement>
  </inputRecordHandler>

</dataSource>

The sample adapter does not support any record metadata. So no record name is given. The data source creates a MappedRecord for it. The sample adaper method getEmployeesUnderManager,as defined in the interactionSpec, takes a parameter called ManagerEmployeeNumber to execute and returns the records of employees under the given manager id. 

Output

The adapter MUST return a javax.resource.cci.ResultSet as a return value from the execute(...) call to the Interaction object. 

The sample adapter data source displays the result by defining the following data fields,

<dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
  <name>name</name>
  <displayName>Name</displayName>
  <alignment>left</alignment>
  <text>##NAME##</text>
</dataField>
<dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
  <name>job</name>
  <displayName>Job</displayName>
  <alignment>left</alignment>
  <text>##JOB##</text>
</dataField>
<dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
  <name>salary</name>
  <displayName>Annual Salary</displayName>
  <alignment>left</alignment>
  <text>##ANNUAL_SALARY##</text>
</dataField>
<dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
  <name>hire_date</name>
  <displayName>Hire Date</displayName>
  <alignment>left</alignment>
  <text>##HIRE_DATE##</text>
</dataField>
<dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
  <name>email</name>
  <displayName>EMail</displayName>
  <alignment>left</alignment>
  <text>##EMAIL_ID##</text>
  <link>hyperlink</link>
  <hyperlink>mailto:##EMAIL_ID##</hyperlink>
</dataField>

 

Using Third Party Adapter

You can use adapters already available in the market to plug into the JCA Data Source. If the adapter implementation follows the considerations described above, you can plug it in as it is. Otherwise you need to create wrapper classes following the described considerations to use the adapter. Here are some points you should consider before plug in the adapter.

 

Troubleshooting

File Not Found Exception For the Sample Provider

Description
If you drop the sample adapter portlet on a page, at the runtime you may get the following error

Error:   Error occurred while rendering portlet - see provider log file for details

If you see the log file you may find that the file location specified for the dataLocation tab can not be found.

Reason

The dataLocation tag under connectionSpec should have a file name that can be resolved under the running context of the portlet. The sample code tries to resolve the file location as a URL (see SampleInteraction.java). If it can not create a URL out of the file name, it fails.

Solution

  1. Open the provider.xml file for the sample provider. The file should be under OC4J_HOME/applications/portalTools/sample/WEB-INF/providers/omniPortletSample. 
  2. Change the file location to whatever is correct for your installation. 
  3. Restart provider.

 

 

Appendix A

Complete Provider Definition

<portlet class="oracle.webdb.reformlet.ReformletPortlet">
  <id>1</id>
  <portletInstanceClass>oracle.webdb.reformlet.ReformletPortletInstance</portletInstanceClass>
  <name>UniPortletSample</name>
  <resource>oracle.webdb.reformlet.resource.ReformletUIBundle</resource>
  <title>UniPortlet: JCA Data Source (Sample Adapter)</title>
  <shortTitle>UniPortlet: JCA Data Source (Sample Adapter)</shortTitle>
  <description>This portlet uses a JCA data source with a sample adapter implementation.</description>
  <timeout>50</timeout>
  <timeoutMessageKey>dataViewTimeoutKey</timeoutMessageKey>
  <showEdit>true</showEdit>
  <showEditDefault>true</showEditDefault>
  <showPreview>true</showPreview>
  <hasHelp>true</hasHelp>
  <hasAbout>true</hasAbout>
  <renderer class="oracle.portal.provider.v2.render.RenderManager">
    <renderContainer>true</renderContainer>
    <renderCustomize>false</renderCustomize>
    <contentType>text/html</contentType>
    <editPage>/htdocs/omniPortlet/reformlet_custom.jsp</editPage>
    <editDefaultsPage>/htdocs/omniPortlet/reformlet_edit_defaults.jsp</editDefaultsPage>
    <aboutPage>/htdocs/omniPortlet/help/reformlet_about.html</aboutPage>
    <helpPage>/htdocs/omniPortlet/help/reformlet_help.html</helpPage>
    <showDetailsPage>/htdocs/omniPortlet/help/reformlet_details.html</showDetailsPage>
    <previewPage class="oracle.portal.provider.v2.render.http.ResourceRenderer">
      <resourcePath>/htdocs/omniPortlet/reformlet_preview.jsp</resourcePath>
      <pageExpires>1440</pageExpires>
      <useInvalidationCaching>true</useInvalidationCaching>
    </previewPage>
    <showPage class="oracle.webdb.reformlet.ReformletResourceRenderer">
      <resourcePath>/htdocs/omniPortlet/reformlet_show.jsp</resourcePath>
      <contentType>text/html</contentType>
    </showPage>
  </renderer>
  <definition class="oracle.webdb.reformlet.definition.ReformletDefinition">
    <name>omniPortlet</name>
    <displayNameKey>dataViewTitleKeyBeta</displayNameKey>
    <descriptionKey>dataViewDescriptionKey</descriptionKey>
    <style>tabular</style>
    <header class="oracle.webdb.reformlet.definition.HeaderDefinition">
      <name>Header</name>
      <alignment>left</alignment>
      <text>Employees Under a Manager.</text>
    </header>

    <data class="oracle.webdb.reformlet.definition.DataDefinition">
      <name>data</name>
      <displayNameKey>dataViewTitleKeyBeta</displayNameKey>
      <customize>true</customize>

      <!-- Definition for JCA Data Source -->
      <dataSource class="oracle.webdb.reformlet.data.jca.JCADataDefinition">
        <version>1.0</version>
        <name>jcads</name>

        <!-- Define the connection related stuff. -->
        <connectionHandler class="oracle.webdb.reformlet.data.jca.ConnectionHandler">
          <!-- Adapter's connection factory -->
          <connectionFactory class="oracle.portal.sample.portalTools.devguide.jcasample.SampleConnectionFactory"/>
          <!-- Adapter's connection spec -->
          <connectionSpec class="oracle.portal.sample.portalTools.devguide.jcasample.SampleConnectionSpec">
            <userName>scott</userName>
            <password>tiger</password>
            <dataLocation>htdocs/sample/sampleData/employees.xml</dataLocation>
          </connectionSpec>
        </connectionHandler>

        <!-- Define interaction -->
        <interactionHandler class="oracle.webdb.reformlet.data.jca.InteractionHandler">
          <!-- Adapter's interaction spec -->
          <interactionSpec class="oracle.portal.sample.portalTools.devguide.jcasample.SampleInteractionSpec">
            <methodName>getEmployeesUnderManager</methodName>
            <maxRow>5</maxRow>
          </interactionSpec>
        </interactionHandler>

        <!-- Define input recod for the above interaction -->
        <inputRecordHandler class="oracle.webdb.reformlet.data.jca.InputRecordHandler">
          <recordElement class="oracle.webdb.reformlet.data.jca.RecordElement">
            <name>ManagerEmployeeNumber</name>
            <value>740</value>
          </recordElement>
        </inputRecordHandler>

      </dataSource>



      <parameter class="oracle.webdb.reformlet.definition.ParameterDefinition">
        <name>Param1</name>
        <displayName>Param1</displayName>
        <description>Description for Parameter 1</description>
      </parameter>
      <parameter class="oracle.webdb.reformlet.definition.ParameterDefinition">
         <name>Param2</name>
         <displayName>Param2</displayName>
         <description>Description for Parameter 2</description>
      </parameter>
      <parameter class="oracle.webdb.reformlet.definition.ParameterDefinition">
         <name>Param3</name>
         <displayName>Param3</displayName>
         <description>Description for Parameter 3</description>
      </parameter>
      <parameter class="oracle.webdb.reformlet.definition.ParameterDefinition">
         <name>Param4</name>
         <displayName>Param4</displayName>
         <description>Description for Parameter 4</description>
      </parameter>
      <parameter class="oracle.webdb.reformlet.definition.ParameterDefinition">
         <name>Param5</name>
         <displayName>Param5</displayName>
         <description>Description for Parameter 5</description>
      </parameter>
    </data>
    <dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
      <name>Field1</name>
      <displayName>Column1</displayName>
      <description>Field1</description>
      <text>##Name##</text>
      <alignment>left</alignment>
      <displayAs>text</displayAs>
    </dataField>
    <dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
      <name>Field2</name>
      <displayName>Column2</displayName>
      <description>Field2</description>
      <text>##Job##</text>
      <alignment>left</alignment>
      <displayAs>text</displayAs>
    </dataField>
    <dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
      <name>Field3</name>
      <displayName>Column3</displayName>
      <description>Field3</description>
      <text>##Salary##</text>
      <alignment>left</alignment>
      <displayAs>text</displayAs>
    </dataField>
    <dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
      <name>Field4</name>
      <displayName>Column4</displayName>
      <description>Field4</description>
      <text>##column4##</text>
      <alignment>left</alignment>
      <displayAs>hidden</displayAs>
    </dataField>
    <dataField class="oracle.webdb.reformlet.definition.DataFieldDefinition">
      <name>Field5</name>
      <displayName>Column5</displayName>
      <description>Field5</description>
      <text>##column5##</text>
      <alignment>left</alignment>
      <displayAs>hidden</displayAs>
    </dataField>
    <event class="oracle.webdb.reformlet.definition.EventDefinition">
      <name>Event1</name>
      <displayName>Event1</displayName>
      <eventParameter class="oracle.webdb.reformlet.definition.EventParameterDefinition">
        <name>Event1Param1</name>
        <displayName>Event1Param1</displayName>
        <binding>column1</binding>
        <description>Event Parameter 1</description>
        <private>false</private>
      </eventParameter>
      <eventParameter class="oracle.webdb.reformlet.definition.EventParameterDefinition">
        <name>Event1Param2</name>
        <displayName>Event1Param2</displayName>
        <binding>column2</binding>
        <description>Event Parameter 2</description>
        <private>false</private>
      </eventParameter>
      <eventParameter class="oracle.webdb.reformlet.definition.EventParameterDefinition">
        <name>Event1Param3</name>
        <displayName>Event1Param3</displayName>
        <binding>column3</binding>
        <description>Event Parameter 3</description>
        <private>false</private>
      </eventParameter>
    </event>
    <event class="oracle.webdb.reformlet.definition.EventDefinition">
      <name>Event2</name>
      <displayName>Event2</displayName>
      <eventParameter class="oracle.webdb.reformlet.definition.EventParameterDefinition">
        <name>Event2Param1</name>
        <displayName>Event2Param1</displayName>
        <binding>column1</binding>
        <description>Event Parameter 1</description>
        <private>false</private>
      </eventParameter>
      <eventParameter class="oracle.webdb.reformlet.definition.EventParameterDefinition">
        <name>Event2Param2</name>
        <displayName>Event2Param2</displayName>
        <binding>column2</binding>
        <description>Event Parameter 2</description>
        <private>false</private>
      </eventParameter>
      <eventParameter class="oracle.webdb.reformlet.definition.EventParameterDefinition">
        <name>Event2Param3</name>
        <displayName>Event2Param3</displayName>
        <binding>column3</binding>
        <description>Event Parameter 3</description>
        <private>false</private>
      </eventParameter>
    </event>
    <event class="oracle.webdb.reformlet.definition.EventDefinition">
      <name>Event3</name>
      <displayName>Event3</displayName>
      <eventParameter class="oracle.webdb.reformlet.definition.EventParameterDefinition">
        <name>Event3Param1</name>
        <displayName>Event3Param1</displayName>
        <binding>column1</binding>
        <description>Event Parameter 1</description>
        <private>false</private>
      </eventParameter>
      <eventParameter class="oracle.webdb.reformlet.definition.EventParameterDefinition">
        <name>Event3Param2</name>
        <displayName>Event3Param2</displayName>
        <binding>column2</binding>
        <description>Event Parameter 2</description>
        <private>false</private>
      </eventParameter>
      <eventParameter class="oracle.webdb.reformlet.definition.EventParameterDefinition">
        <name>Event3Param3</name>
        <displayName>Event3Param3</displayName>
        <binding>column3</binding>
        <description>Event Parameter 3</description>
        <private>false</private>
      </eventParameter>
    </event>
  </definition>
  <personalizationManager class="oracle.portal.provider.v2.personalize.PrefStorePersonalizationManager">
    <dataClass>oracle.webdb.reformlet.definition.ReformletPersonalizationObject</dataClass>
  </personalizationManager>
</portlet>

 

Related Links

 

Revision History:
Revision No Last Update
1.0 October 21, 2002

Oracle Corporation
World Headquarters
500 Oracle Parkway
Redwood Shores, CA 94065, USA
http://www.oracle.com/
Worldwide Inquiries:
1-800-ORACLE1
Fax 650.506.7200
Copyright and Corporate Info