| Sign In/My Account | View Cart |
A year ago, I wrote an article about JBoss 2.x for the 2001 O'Reilly Open Source Conference. There, I showed how JBoss enables you
to create a new DataSource without bouncing the server -- just through the HTML management front-end. The only drawback was that you had to load the JDBC driver when the JBoss server was started.
In JBoss 3, this is history; you can deploy and undeploy libraries at runtime, including the classes they contain. For example, assume the running JBoss server needs to provide Postgres connections (new client or new project) on a high-availablity server, but the JDBC driver was not available or is out of date. Now you have to do the following:
deploy directory.postgres-server.xml file (from JBoss/docs/examples/jca directory) and
adjust the settings to your needs -- JNDI name, user name, password, etc.postgres-service.xml file into the deploy directory.Now you can deploy applications using this DataSource. This also works when you update libraries and/or service.xml files to redeploy
them.
In JBoss a few years ago, the challenge was to wrap the Enterprise JavaBeans (EJB) services -- like transaction, security, CMP and more -- around a client's call. But Rickard Oeberg didn't want to create a static construct, but a flexible and, for the user, easy-to-change implementation. So he used an "Interceptor Stack" as the base of the implementation; this not only survived into the current JBoss 3 implementation but also was extended and used more often.
An Interceptor Stack is a stack of stateless components in which every call proceeds through the stack from first to last, until finally the target is called. After the target is finished with its method, the call will unwind through the stack in reverse order.
Because Interceptors are stateless, information about the state of the call then must be added to the context of the calling thread. So all of the information is piggybacked on the thread context, and each Interceptor can read, add, change, or remove data from the thread context. Figure 1 is a simple diagram of an Interceptor Stack embedded in a container like, in JBoss, the EJB Container.

Figure 1. Diagram of Interceptor stack.
Note that the last Interceptor is the "Container Interceptor" and is added to the stack by the container itself. Its only task is to return the call to the container, thus the user does not have to indicate in an Interceptor that it is the last one in the stack.
The code of an Interceptor looks like this:
public Object invoke( final Invocation mi )
throws Exception
{
Object lReturn;
// PERFORM the INBOUND Tasks and when done go to the next
// If the call has to be ended throw the appropriate exception
// Call next Interceptor in the stack
lReturn = getNext().invoke( mi );
// PERFORM the OUTBOUND Tasks and when done return method
// If the call shouldn't be complete throw and exception
return lReturn;
}
As you see, the Interceptor contains four parts:
As mentioned earlier, the reason to use the Interceptor Stack is to implement EJB services like transaction or security. To illustrate this a little bit more, we want to discuss the Container Managed Transaction (CMT) and its implementation.
Assume a Web client calls a CMT EJB and the transaction attribute of the called method is set to Required; that means that when no transaction is in place, a transaction is created, and when one is in place, the call becomes part of the existing transaction. Therefore, the Transaction Interceptor of this EJB has to do the following:
TransactionRolledbackException. If the transaction is not marked as existing, the transaction is committed; otherwise, do nothing.When the transaction attribute is set to Mandatory, meaning
that the caller has to provide a transaction, it looks like this:
TransactionRolledbackException.A little bit more interesting is the case when the transaction attribute is set to RequiresNew, which means that whether or not a transaction exists, a new one is created. Now the Transaction Interceptor has to do the following:
TransactionRolledBackException.For a Bean Managed Transaction EJB (which cannot be an Entity Bean) transactions are handled this way:
One of the goals of the Interceptor Stack is to give the administrator the flexibility to change the Interceptor Stack instead of using a fixed and restrictive configuration.
The layout of the Interceptor Stack is done in the Container Configuration that is set in the standardjboss.xml and the jboss.xml deployment descriptor of the EJB application. There are three types of container configurations:
standardjboss.xml, available server-wide, and used when no specific configuration is set in the jboss.xml deployment descriptor.standardjboss.xml, available server-wide, but must be requested by each EJB in the jboss.xml deployment descriptor.jboss.xml deployment descriptor, available application-wide and must be requested by each EJB as well.Container configurations contain more than just the list of Interceptors; therefore, the following listing is only a part of the default configuration for CMP 2.x Entity Bean:
<container-configuration>
<container-name>Standard CMP 2.x EntityBean</container-name>
<call-logging>false</call-logging>
<container-invoker>org.jboss.proxy.ejb.ProxyFactory</container-invoker>
<container-interceptors>
<interceptor>org.jboss.ejb.plugins.LogInterceptor</interceptor>
<interceptor>org.jboss.ejb.plugins.SecurityInterceptor</interceptor>
<interceptor>org.jboss.ejb.plugins.TxInterceptorCMT</interceptor>
<interceptor metricsEnabled = "true">
org.jboss.ejb.plugins.MetricsInterceptor
</interceptor>
<interceptor>org.jboss.ejb.plugins.EntityCreationInterceptor</interceptor>
<interceptor>org.jboss.ejb.plugins.EntityLockInterceptor</interceptor>
<interceptor>org.jboss.ejb.plugins.EntityInstanceInterceptor</interceptor>
<interceptor>
org.jboss.resource.connectionmanager.CachedConnectionInterceptor
</interceptor>
<interceptor>org.jboss.ejb.plugins.EntitySynchronizationInterceptor</interceptor>
<interceptor>
org.jboss.ejb.plugins.cmp.jdbc.JDBCRelationInterceptor
</interceptor>
</container-interceptors>
...
</container-configuration>
When an Entity Bean is deployed using this container configuration, the first interceptor is the Log, then the SecurityInterceptor, then the JDBCRelation, and last but not least, the ContainerInterceptor. You can change the list and also the order of the
Interceptors.
Assume we are an ISP offering to host customers' EJB applications with a fee per call, let us say two cents per call. All we have to do is add our HitLoggingInterceptor as the first in
the list of container Interceptors on each container configuration in standardjboss.xml, and prevent the client from providing its own container configuration in its jboss.xml. The HitLoggingInterceptor just logs the hit on an EJB in a database.
Now we want to go a step further and charge the client a cent for an incoming call and another cent when the call successfully returns to the caller. This means the HitLoggingInterceptor has to log the call on the inbound as well as on the outbound (when an exception is thrown, the outbound hit is not logged).
Because the concept is so successful in the JBoss EJB Container, JBoss is using it on other parts of the application server. On the client side, the Interceptor Stack is used to shift some of the code with the smart proxy from the server to the client to reduce the number of network calls, and also to make the server lookup methods pluggable for clusters.
The concept is also going into the JBoss JMX implementation to add security, transactions, and other services. Thus it is possible to define MBean-level security, like in J2EE. It would also be possible to make MBeans transactional, to roll back a series of changes to various MBeans.
Even thought the Interceptor Stack is a pretty simple concept, it allows the developer and the administrator to add additional services to the called target, which are performed before and after the call to the target is made.
With Interceptors, it would also be possible to create new types of EJBs by adding the appropriate services as Interceptors. The Interceptors then can change the methods to be called; therefore, you could create an advanced framework like you have for CMP Entity Beans. The Interceptor could also call several methods on the target, like ejbCreate() and ejbPostCreate().
Andreas Schaefer is a system architect for J2EE at SeeBeyond Inc., where he leads application server development.
Return to ONJava.com.