Chapter 3. Resource Adapter Development

3.1. Developing JCA Adapters

A framework is provided by the Enterprise Data Services API for developers to create custom JCA Adapters. If you already have a JCA Adapter or some other mechanism to get data from your source system, there is no need to develop your own.
If you are not familiar with JCA API, please read the JCA 1.5 Specification at http://docs.oracle.com/cd/E15523_01/integration.1111/e10231/intro.htm.
The process for developing an Enterprise Data Services JCA Adapter is as follows:
  • Define a Managed Connection Factory by extending the BasicManagedConnectionFactory class
  • Specify configuration properties in an ra.xml file
  • Define a Connection Factory by extending the BasicConnectionFactory class
  • Define a Connection by extending the BasicConnection class

Note

The examples contained in this book are simplified and do not include support for transactions or security which would add significant complexity.

Note

The Enterprise Data Services connector framework does not make use of JCA's CCI framework, only the JCA's SPI interfaces.

3.2. Define a Managed Connection Factory

  • Extend the org.teiid.resource.spi.BasicManagedConnectionFactory class, providing an implementation for the createConnectionFactory() method. This method will create and return a Connection Factory object.
  • Define an attribute for each configuration variable, and then provide both "getter" and "setter" methods for them. This class will define various configuration variables (such as user, password, and URL) used to connect to the datasource.
See the following code for an example.
public class MyManagedConnectionFactory extends BasicManagedConnectionFactory 
{
   @Override
   public Object createConnectionFactory() throws ResourceException 
   {
      return new MyConnectionFactory();
   }

   // config property name (metadata for these are defined inside the ra.xml)
   String userName;
   public String getUserName()          {  return this.userName;  }
   public void setUserName(String name){  this.userName = name;  }

   // config property count  (metadata for these are defined inside the ra.xml)
   Integer count;
   public Integer getCount()            {  return this.count;  }
   public void setCount(Integer value) {  this.count = value; }               

}

Important

Use only java.lang objects as the attributes. DO NOT use Java primitives for defining and accessing the properties.

Note

You can navigate to examples of existing connectors from within the teiid-VERSION/connectors directory of the Data Services 5.3.x Source Code ZIP file which can be downloaded from the Red Hat Customer Portal at https://access.redhat.com.

3.3. Specify Configuration Properties in an ra.xml File

Every configuration property defined inside the new Managed Connection Factory class must also be configured in the ra.xml file. These properties are used to configure each instance of the connector.
The ra.xml file is located in the META-INF directory of the relevant connectors's RAR file under SOA_ROOT/jboss-as/server/PROFILE/deploy/teiid/connectors/. An example file is provided in Appendix A, ra.xml file Template.
The following is the format for a single entry:
<config-property>
   <description>
      {$display:"display-name",$description:"description", $allowed:"allowed", 
      $required:"true|false", $defaultValue:"default-value"}
   </description>
   <config-property-name>property-name</config-property-name>
   <config-property-type>property-type</config-property-type>
   <config-property-value>optional-property-value</config-property-value>
</config-property>
For example:
<config-property>
   <description>
      {$display:"User Name",$description:"The name of the user.", $required="true"}
   </description>
   <config-property-name>UserName</config-property-name>
   <config-property-type>java.lang.String</config-property-type>
</config-property>
The format and contents of the <description> element may be used as extended metadata for tooling. This use of the special format and all properties is optional and must follow these rules:
  • The special format must begin and end with curly braces e.g. { }.
  • Property names begin with $.
  • Property names and the associated value are separated with a colon (:).
  • Double quotes (") identifies a single value.
  • A pair of square brackets ([ ]), containing comma separated double quoted entries indicates a list value.
The following are optional properties:
  • $display: Display name of the property
  • $description: Description about the property
  • $required: The property is a required property; or optional and a default is supplied
  • $allowed: If property value must be in certain set of legal values, this defines all the allowed values
  • $masked: The tools need to mask the property; Do not show in plain text; used for passwords
  • $advanced: Notes this as Advanced property
  • $readOnly: Property can be modified; or read-only

Note

Although these are optional properties, in the absence of this metadata, Data Services tooling may not work as expected.

3.4. Define a Connection Factory

Extend the org.teiid.resourse.spi.BasicConnectionFactory class, and provide an implementation for the getConnection() method. This method will create and return a Connection object.
public class MyConnectionFactory extends BasicConnectionFactory 
{
   @Override
   public MyConnection getConnection() throws ResourceException 
   {
      return new MyConnection();
   }  
}
Since the Managed Connection Factory object creates a Connection Factory object, it has access to all the configuration parameters so that the getConnection() method can pass credentials to the requesting application. Therefore, the Connection Factory class can reference the calling user's javax.security.auth.Subject from within the getConnection() method.
Subject subject = ConnectionContext.getSubject();
A Subject object can give access to logged-in user's credentials and roles that are defined. This may be null.

Note

You can define a security-domain for this resource adapter that is separate from the default Data Services security-domain for validating the JDBC user. It is the user's responsibility to perform the necessary logins before the application server's thread accesses this resource adapter. This can become very complex for the end user.

3.5. Define a Connection

Extend the org.teiid.resource.spi.BasicConnection class, and provide an implementation based on your access of the Connection object in your translator. If your connection is stateful, then override the isAlive() and cleanup() methods and provide suuitable implementations. These are called to check if a connection is stale and needs flushing from the connection pool by the application server.
public class MyConnection extends BasicConnection 
{
   public void doSomeOperation(command)
   {
      // do some operation with requesting application..
      // This is method you use in the Translator, you should know
      // what need to be done here for your source..
   }
     
   @Override
   public boolean isAlive() 
   {
      return true;
   }
   
   @Override
   public void cleanUp() 
   {
         
   }
}

3.6. XA Transactions

If the requesting application can participate in XA transactions, then your Connection object must override the getXAResource() method and provide the XAResource object for the application. Refer to Section 3.5, “Define a Connection”. To participate in crash recovery you must also extend the BasicResourceAdapter class and implement the public XAResource[] getXAResources(ActivationSpec[] specs) method.
Data Services can make XA-capable resource adapters participate in distributed transactions. If they are not XA-capable, then they can only participate in distributed queries. Transaction semantics are determined by whether the data source file (SOA_ROOT/jboss-as/server/PROFILE/deploy/DATASOURCE-ds.xml) is defined with local-tx or no-tx.

3.7. Packaging the Adapter

When development is complete, the resource adapter files are packaged into an artifact called a Resource Adapter Archive or RAR file. The file format is defined by the JCA specification and should not be confused with the RAR file compression format.
The method of creating a RAR artifact will depend on your build system:
JBoss Developer Studio
If you create a Java Connector project in JBoss Developer Studio, it will include a build target that produces a RAR file.
Apache Ant
When using Apache Ant, you can use the standard rar build task.
Apache Maven
When using Apache Maven, set the value of the <packaging> element to rar. Since Data Services uses Maven, you can refer to any of the Connector projects; for example, pom.xml shown below.
<project>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>connector-{name}</artifactId>
   <groupId>org.company.project</groupId>
   <name>Name Connector</name>
   <packaging>rar</packaging>
   <description>This connector is a sample</description>

   <dependencies>
      <dependency>
         <groupId>org.jboss.teiid</groupId>
         <artifactId>teiid-api</artifactId>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>org.jboss.teiid</groupId>
         <artifactId>teiid-common-core</artifactId>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>javax.resource</groupId>
         <artifactId>connector-api</artifactId>
         <scope>provided</scope>
      </dependency>
   </dependencies>

Make sure that the RAR file, under its META-INF directory contains the ra.xml file. If you are using Apache Maven, refer to http://maven.apache.org/plugins/maven-rar-plugin/. In the root of the RAR file, you can embed the JAR file containing your connector code and any dependent library JAR files.

3.8. Deploying the Adapter

Once the RAR file is built, deploy it by copying the RAR file into the server's PROFILE/deploy directory. The server will not need to be restarted when a new RAR file is added. You can also use the web-based Administration Console to deploy the RAR file.
Once the adapter's RAR file has been deployed you can create an instance of this connector to use with your Translator. Creating an instance of this adapter is the same as creating a Connection Factory. There are two ways you can do this:
  1. Create the name-ds.xml file, and copy it into the server/PROFILE/deploy/ directory of your server.
    <!DOCTYPE connection-factories PUBLIC 
       "-//JBoss//DTD JBOSS JCA Config 1.5//EN" 
       "http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">
    
    <connection-factories>
          <no-tx-connection-factory>
             <jndi-name>${jndi-name}</jndi-name>
             <rar-name>${name}.rar</rar-name>
             <connection-definition>javax.resource.cci.ConnectionFactory</connection-definition>
    
       <!--  
       define all the properties defined in the "ra.xml" that required or needs to be 
       modified from defaults each property is defined in single element 
       --> 
             <config-property name="prop-name" type="java.lang.String">prop-value</config-property>
    
    </no-tx-connection-factory>
    </connection-factories>
    There are more properties that you can define in this file; for example, for pooling, transactions, and security. Refer to the JBoss Enterprise Application Platform documentation for all the available properties, http://docs.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/5/.
  2. You can use the web-based Administration Console to create a new ConnectionFactory.