Articles Index
Jennifer Rodoni Glore
January 2004
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: 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: 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.
|