Sun Java Solaris Communities My SDN Account Join SDN
 
Article

What's New in the J2EE Connector Architecture 1.5 (Part 2)

 
 
Articles Index



This article is intended for EIS vendors, messaging providers, and developers who want to learn more about the Message Inflow and Transaction Inflow contracts that were introduced in the latest version of the Java 2, Enterprise Edition (J2EE) Connector Architecture (Connector 1.5). Since this article is the second in a two-part series, the resource adapter and system-level contracts will not be discussed in detail. This information can be found in Part 1 of this article, which was published in March 2003. Instead, I'll focus solely on the two new contracts. Implementation details and specification requirements will be covered, and pseudo-code will be examined to see how an EIS vendor or messaging provider might implement the new contracts for a Connector 1.5-compatible resource adapter. The new Connectors v 1.5 can be found in the J2EE 1.4 SDK or in the J2EE 1.4 Application Server. Download it for free at http://java.sun.com/j2ee/1.4/download-dr.html.

Resource Adapter Overview

The resource adapter plays a central role in the integration and connectivity between an EIS and an application server, since it helps reduce both development time and cost. For seamless integration with compatible application servers, a resource adapter must abide by the guidelines or contracts that are defined by the Connector Architecture. These contracts exist between the application server and an EIS, and are implemented through the resource adapter to facilitate a smooth integration.

New Contracts in Version 1.5

In version 1.5 of the Connector Architecture, new functionality and features were added to the specification in the form of four new contracts. A resource adapter can support these contracts by implementing the required interfaces defined in the specification for each contract.

  • Lifecycle Management Contract: Allows the application server to manage the lifecycle (startup and shutdown functionality) of the resource adapter.
  • Work Management Contract: Allows the resource adapter to do work by submitting it to an application server for execution. Since the application server does the work for the resource adapter, the resource adapter doesn't have to worry about thread management. Instead, the application server manages this aspect efficiently and can use thread pooling if necessary. Although a work management contract is not required (the resource adapter can choose to manage its own thread for work), it is definitely recommended.
  • Message Inflow Contract: Allows the resource adapter to synchronously or asynchronously deliver messages to endpoints that reside within the application server, irrespective of message style, semantics, and infrastructure.
  • Transaction Inflow Contract: Allows a resource adapter to propagate an imported transaction to an application server, as well as flow-in transaction completion and crash recovery initiated by an EIS.

As mentioned earlier, this article will focus on the Message Inflow contract and the Transaction Inflow contract. The next few sections will take a look at each interface and class, in relation to these contracts, to provide a foundation for the design and implementation of a specific resource adapter within an n-tier environment. Code samples show how you might start to implement parts of the interfaces.

Message Inflow Contract

The Message Inflow contract specifies a standard contract between an application server and a resource adapter; this allows the resource adapter to deliver messages to endpoints deployed within the application server, in a standardized way. The resource adapter delivers messages to these endpoints, either synchronously or asynchronously, without caring about messaging style, semantics, or infrastructure. The end result is that these endpoints -- which are typically message-driven bean applications -- are no longer restricted to receiving only JMS messages. Instead, through a Connector 1.5-compatible resource adapter, EIS vendors and messaging providers can communicate with these endpoints using any type of message, which includes but is not limited to their own proprietary brand. For a resource adapter to meet the requirements of this contract, it must implement methods for the ResourceAdapter and ActivationSpec interfaces. The place of these interfaces within the Connector contracts is illustrated in Figure 1.

Figure 1
Figure 1: Message Inflow Interfaces for Resource Adapter

ResourceAdapter Interface

The ResourceAdapter interface plays an essential role in a variety of the resource adapter's contracts. With respect to the Message Inflow contract, the ResourceAdapter interface supports the activation and deactivation of message endpoints that reside within the application server, and assists with crash recovery.

endpointActivation

The endpointActivation method is called by the application server to activate a message endpoint. This method accepts two parameters: a MessageEndpointFactory instance and a configured ActivationSpec instance.

The MessageEndpointFactory instance is used by the resource adapter to create message endpoint instances within the application server using the createEndpoint method, once the adapter has a message to propagate. Once the endpoint instances are created, the resource adapter can deliver messages to the instances, either serially or concurrently. Although you could use the MessageEndpointFactory instance to create an unlimited number of endpoint instances, the application server may restrict the number of endpoint creations.

In addition to a MessageEndpointFactory instance, a configured ActivationSpec instance is passed to the resource adapter by the application server and is used for configuration during endpoint activation. This instance stores crucial information regarding the type of endpoint listener that the resource adapter will send messages to. The ActivationSpec instance is configured by an endpoint deployer during endpoint deployment.

If the activation of the endpoint is rejected, for either incorrect configuration or for another reason, this method can throw a NotSupportedException.

Similar calls to the endpointActivation method by the application server must be treated separately by the resource adapter.

Once an endpoint is activated, it can receive messages from the message provider through the resource adapter. When the message provider sends a message, the resource adapter determines which message listener type the endpoint supports; it then forwards the appropriate message to the endpoint.

endpointDeactivation

The endpointDeactivation method is called by the application server to deactivate a message endpoint during undeployment or application server shutdown. Like endpointActivation, this method is passed a handle to a MessageEndpointFactory instance and an ActivationSpec instance. The application server must guarantee that the same instances will be used for both endpoint activation and deactivation. The resource adapter should remove any information about the endpoint and notify any message providers once this method is called.

Note: A resource adapter must implement the endpointActivation and endpointDeactivation methods in such a manner that the application server can make concurrent calls to them.

getXAResources

If a system crash occurs, the application server restarts the resource adapter instances that were active before the crash. Once the instances are restarted, the application server then calls the getXAResources method for each instance. This method is passed an array of ActivationSpec JavaBeans, which coincide with endpoint applications that were active before the crash. If the resource adapter implements the XAResource interface, it must return an array of XAResource objects that correspond to a unique resource manager. Otherwise, it can return null.

Below is a code sample that illustrates how an EIS vendor might implement this interface.


import javax.resource.spi;
import javax.resource.NotSupportedException;
import javax.resource.spi.endpoint.MessageEndpointFactory;

public class MyResourceAdapter implements ResourceAdapter { // ... void endpointActivation(MessageEndpointFactory eFact, ActivationSpec aSpec) throws NotSupportedException { /* Store the MessageEndpointFactory instance, eFact, in a manner that coincides with the resource adapter implementation.

This MessageEndpointFactory instance is used by the resource adapter when it receives a message from a provider and needs to create an endpoint (via the createEndpoint method). The MessageEndpointFactory instance is needed to locate the activated endpoint in the application server. For example:



   	Message msg = ... /from provider
	MessageEndpointFactory endpointFactory = eFact;
	Object obj = endpointFactory.createEndpoint (...); */



	/* Store the information from the ActivationSpec instance,
	aSpec. This information should be used by the resource
	adapter to determine the type of message listener it is
	sending messages to.*/


  	/* A NotSupportedException is thrown for incorrect configuration or other reasons */
}

void endpointDeactivation(MessageEndpointFactory eFact, ActivationSpecaSpec){

	/* The implementation should remove and cleanup any information
	about the endpoint that is stored by the resource adapter.


	Additionally, the resource adapter should notify any message
	providers that were using the endpoint so the message provider
	can do its own cleanup. */
}


XAResource [] getXAResources (ActivationSpec [] specs)
	throws ResourceException{


 	/* If Resource Adapter does not implement XAResource, return null.
	  Otherwise, return an array of XAResource objects that correspond
	  to a unique resource manager. */

}

}


ActivationSpec JavaBean Class

Any resource adapter that can deliver messages to endpoints within an application server must provide a way for endpoint developers and deployers to know what type of endpoint listeners it supports. Without this information, endpoint developers and deployers would have no idea whether or not a particular resource adapter solves their individual integration needs. The way a resource adapter shares this support information is through its deployment descriptor.

A resource adapter's deployment descriptor details each type of message listener that the adapter supports. This information includes the fully qualified Java name of each message listener interface that is supported by the resource adapter. In addition, the deployment descriptor also lists the name of each ActivationSpec JavaBean class, where every ActivationSpec JavaBean class maps to a different type of endpoint message listener that the resource adapter supports. The name of each ActivationSpec JavaBean class must be listed in the resource adapter's deployment descriptor in addition to "required-config-property" names.

Before any endpoint activations can occur, however, an endpoint deployer must configure properties that belong to the appropriate ActivationSpec JavaBean, in order to prepare the environment for endpoint activation. The ActivationSpec JavaBean should be configured according to details in the endpoint deployment descriptor, as well as to message provider specifics.

Here are some important points to note about the ActivationSpec JavaBean class:

  • You can implement a validate method in the ActivationSpec class to verify the configuration information set by the endpoint deployer during endpoint deployment
  • The configured ActivationSpec JavaBean instance is created during endpoint deployment and is passed to the resource adapter by the application server during endpoint activation and deactivation. The configuration information within the JavaBean instance is used by the resource adapter to determine what type of message listener it will send messages to.
  • One requirement of the specification is that each ActivationSpec JavaBean must be treated uniquely by the resource adapter. To guarantee this, the resource adapter cannot override the java.lang.Object.equals method for the ActivationSpec JavaBean.

Below is a code sample that illustrates how an EIS vendor might implement this interface.


import javax.resource.spi;
import java.beans.PropertyDescriptor;
import java.io.Serializable;

public class MyActivationSpec1 implements ActivationSpec, Serializable {

//
...

private Property myProperty1;

public Property getMyProperty1() {
	return myProperty1;
}

public void setMyProperty1(Color newProperty) {

	myProperty1 = newProperty;
}


public MyActivationSpec1() {

  	/* Set configuration property, myProperty1, for this instance
	based on the configuration established by deployer. */
}

void validate () throws InvalidPropertyException {

	/* Validate property set by deployer for MyActivationSpec1 instance.
	If the property is notconfigured properly, throw an InvalidPropertyException.
	This method is optional.*/
}


Transaction Inflow Contract

The Transaction Inflow Contract introduced in Connector 1.5 expands the support of transactions within the standard. Prior to Connector 1.5, J2EE applications could propagate transactions to an EIS, but an EIS could not pass transactions to the application server using a resource adapter. With the latest version of this architecture, however, transactions can now flow both ways. Due to this contract, a compliant resource adapter can now import transactions from an EIS and then propagate them to an application server. In addition to providing this transaction flow functionality, this contract also defines a mechanism for transaction completion and crash recovery flows from the EIS. The contract also guarantees that all ACID properties of the imported transaction are maintained. For a resource adapter within an n-tier environment to meet the requirements of this contract, it must implement methods for the BootstrapContext and XATerminator interfaces. The place of these interfaces within the Connector Architecture is illustrated in Figure 2.

Figure 2
Figure 2: BootstrapContext and XATerminator interfaces.

BootStrapContext Interface

The BootStrapContext interface enables a resource adapter to gain access to instances of WorkManager and XATerminator from the application server, using the following methods:

getWorkManager

When the resource adapter imports a transaction from an EIS, it does it in an EIS-specific way; the resource adapter must understand the execution context of the transaction, as well as the protocol the EIS uses. Once the transaction is imported, the resource adapter represents it in a standardized way via a javax.transaction.xa.Xid instance and packages it into an ExecutionContext instance. Once the resource adapter is ready to pass the imported transaction to the application server, it uses the getWorkManager method to obtain a WorkManager instance that belongs to the application server. This method takes no arguments and simply returns the application server's WorkManager. The resource adapter can use this imported transaction context to do work within the application server, such as accessing application components. This is accomplished by submitting a Work instance to the WorkManager, along with an ExecutionContext that contains the imported transaction.

getXATerminator

The getXATerminator method returns an XATerminator instance from the application server that is used by the resource adapter for transaction completion and crash recovery. The instance returned by this method can be used by the resource adapter on multiple transactions at the same time. The next section of this article illustrates how the instance obtained by this method is used for transaction completion and crash recovery.

Here is a code sample that illustrates how an EIS vendor might implement this interface.


import javax.resource.spi;
import javax.transaction.xa.Xid;
import java.transaction.xa.XAException;
import javax.resource.spi.work.WorkManager;


public class MyBootstrapContext implements BootStrapContext {


public WorkManager getWorkManager () {

	// return WorkManager instance from application server
}


public XATerminator getXATerminator () {

	// return XATerminator instance from application server
}


//
...

}

XATerminator Interface

The XATerminator interface is used by the resource adapter for transaction completion and crash recovery. The following methods need to be implemented for this interface:

commit

The commit method of the XATerminator interface is used by the resource adapter to commit transactions that originated from the EIS during either transaction completion or crash recovery.

When the resource adapter receives a commit from the EIS for a particular transaction, it calls this method on an instance of the application server's XATerminator instance. The commit method takes two arguments: an Xid instance and a boolean. The Xid instance corresponds to the transaction that was imported from the EIS. If the commit is one-phase, it is not necessary for the resource adapter to call the prepare method first.

Similarly, the commit method can be used when either the EIS or the application server recovers from a crash and there is a transaction in an in-doubt or prepared state.

In the case where the EIS recovers from a crash, the resource adapter informs the application server and queries the status of in-doubt transactions using the recover method. After the EIS knows which transactions are in-doubt, it can choose to send a commit command through the resource adapter. The resource adapter calls this method on an instance of the application server's XATerminator instance and passes an instance of Xid, which maps to the particular transaction.

When the application server recovers from a failure and a transaction is in-doubt, the EIS will reestablish a connection to it through the resource adapter, and the application server will restore the state of all the transactions. At that point, the EIS can issue a commit through the resource adapter. The resource adapter will then call this method on an instance of the application server's XATerminator instance. An Xid instance that corresponds to the specific transaction is sent as an argument.

prepare

In a two-phase commit, the EIS will send a prepare message to the resource adapter, which indicates that two-phase commit of transaction completion should begin. The resource adapter then forwards this message to the application server by using this method of the XATerminator interface on the application server's XATerminator instance. An Xid instance, which corresponds to the original transaction that was imported from the EIS, is passed as an argument to this method. An int value is returned from the application server to the EIS through the resource adapter. The return value determines how the EIS will handle transaction completion.

recover

Therecover method of the XATerminator interface is used by the resource adapter when the EIS is recovering from a crash and there is a transaction in an in-doubt or prepared state on the application server. Once the EIS recovers after the crash and regains communication with the resource adapter, the first thing it will do is ask the resource adapter if there are any in-doubt transactions. The resource adapter forwards this request to the application server using the recover method. The application server returns a list of in-doubt transactions to the resource adapter via an array of Xid instances. At that point, the EIS can continue with transaction completion.

rollback

The rollback method of the XATerminator interface is used by the resource adapter to rollback transactions that originated from the EIS during either transaction completion or crash recovery.

During transaction completion, the resource adapter can receive a rollback message from the EIS for a particular transaction. When this happens, the resource adapter calls the rollback method on an instance of the application server's XATerminator instance. The rollback method takes one argument, which is an Xid instance that maps to the specific transaction. During a one-phase commit, the rollback method can be initiated without having called prepare.

In addition to transaction completion, the rollback method is also used during crash recovery of the application server and EIS.

If the application server recovers from a failure and there is a transaction in-doubt, the EIS will reestablish a connection to it through the resource adapter. Meantime, the application server will restore the state of every transaction. Once that is completed, the EIS can issue a rollback command through the resource adapter. The resource adapter will then call the rollback method on an instance of the application server's XATerminator instance, which corresponds to the specific transaction sent as an argument.

When the EIS recovers from a crash, the resource adapter informs the application server and queries the status of in-doubt transactions using the recovermethod. After the EIS knows which transactions are in-doubt, it can choose to send a rollback command through the resource adapter. The resource adapter passes that message along to the application server using the rollback method on an instance of the application server's XATerminator instance. An instance of Xid is passed in the method so the command can be mapped to a particular transaction.

That last scenario (where the rollback method is used) occurs when the EIS crashes and there is a transaction in an active state. The resource adapter should automatically rollback any active transactions from the failed EIS. To do this, the resource adapter must store and maintain a list of active transactions.

Below is a code sample that illustrates how an EIS vendor might implement this interface.


import javax.resource.spi;
import javax.transaction.xa.Xid;
import java.transaction.xa.XAException;
import javax.resource.spi.work.WorkManager;


public class MyXATerminator implements XATerminator {


public void commit (Xid xid, boolean onePhaseCommit)
	throws XAException{

	/* The resource adapter passes the commit message to the
	application server for a particular transaction, which is
	determined by the Xid instance, xid. */
}

public int prepare (Xid xid)
	throws XAException{

	/* The resource adapter passes the prepare message to the
	application server for a particular transaction, which is
	determined by the Xid instance, xid. The prepare message
	is used to begin transaction completion.*/
}

public Xid[] recover (int flag)
	throws XAException{

	/* The resource adapter queries the application server for in-doubt
	transactions and the query returns an array of Xid
	instances that correspond to the in-doubt transactions. */
}



public void rollback (Xid xid)
	throws XAException{

	/* The resource adapter passes the rollback message to the
	application server for a particular transaction, which is
	determined by the Xid instance, xid. */
}

//
...

}

Summary

Resource adapters are an important piece of the standard integration between an EIS and an application server. Version 1.0 of the J2EE Connector Architecture revolutionized the way in which these integrations were done, thus reducing the cost and time of both design and implementation, as well as creating a portable, standard solution. With all of the enhancements that have been made in the latest specification, it is essential that these new features and functionality, which come in the form of four system-level contracts, are understood in detail. This paper addresses two of the new contracts, the Message Inflow contract and the Transaction Inflow contract. With what you've learned in this article, you should now be able to begin thinking about how to implement a resource adapter that is compliant with these contracts.

See Also

About the author

Jennifer Rodoni Glore is an engineer at Sun Microsystems, Inc. Currently, she works in the Market Development Engineering Organization and helps evangelize Java technology. She is also the author of "An Introduction to the Java Connector Architecture" and "What's New in the J2EE Connector Architecture, Part 1." You can contact her at jennifer.glore@sun.com.


Reader Feedback
Excellent   Good   Fair   Poor  

If you have other comments or ideas for future technical tips, please type them here:

Comments:
If you would like a reply to your comment, please submit your email address:
Note: We may not respond to all submitted comments.

Have a question about Java programming? Use Java Online Support.

Oracle is reviewing the Sun product roadmap and will provide guidance to customers in accordance with Oracle's standard product communication policies. Any resulting features and timing of release of such features as determined by Oracle's review of roadmaps, are at the sole discretion of Oracle. All product roadmap information, whether communicated by Sun Microsystems or by Oracle, does not represent a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. It is intended for information purposes only, and may not be incorporated into any contract.