Thursday, August 24, 2006

Using EJB 3.0 Message Driven Bean with JCA-Resource Adapters

MDB was the only bean type that did not suffer obesity problems with EJB 2.x. It was simple to develop and use and it was liked by most developers.

For many developers the verbose XML descriptor was still a sour-point. EJB 3.0 further simplified message driven bean by removing the requirement to use descriptors and you can use annotations to specify the activation config properties.

An Example MDB with EJB 3.0 Annotations

A simple MDB will look like as follows:

@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "ConnectionFactoryJndiName", propertyValue = "jms/TopicConnectionfactory"),
@ActivationConfigProperty(propertyName = "DestinationName", propertyValue = "jms/demoTopic"),
@ActivationConfigProperty(propertyName = "DestinationType", propertyValue = "javax.jms.Topic"),
@ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "RECIPIENT = 'MDB'")
})

public class MessageLogger implements MessageListener{..}

This problem with MDB is that it works will the default JMS provider of the container i.e . in-memory JMS provider of OracleAS.

Using MDB with a JCA-compliant Resource Adapter

There are many instances probably you want to use a messaging provider (JMS or non-JMS) plugged-in using a JCA-compliant connector or resource adapter. Let us assume that OracleAS JMS wit the global connector (named OracleASjms) packaged with Oracle AS. Unfortunately EJB or JCA does not standardize configurations for using a resource adapter and you have to depend upon a proprietary feature such as vendor specific annotation or activation config property to designate the resource adapter to be used with your MDB. Oracle provides a vendor specific annotation (@oracle.j2ee.ejb.MessageDrivenDeployment) to specify Oracle specific configuration properties and you need to use resourceAdapter element to specify the resource adapter that you intend to use. For example you can modify the above MDB as follows to use the OracleASjms global connector to use the In-memory JMS as follows:

@oracle.j2ee.ejb.MessageDrivenDeployment(resourceAdapter="OracleASjms")@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "ConnectionFactoryJndiName", propertyValue = "OracleASjms/MyTCF"),
@ActivationConfigProperty(propertyName = "DestinationName", propertyValue = "jms/demoTopic"),
@ActivationConfigProperty(propertyName = "DestinationType", propertyValue = "javax.jms.Topic"),
@ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "RECIPIENT = 'MDB'")
})

public class MessageLogger implements MessageListener {.}

Note that we have modified the ConnectionFactoryJndiName to use a pre-configured connection factory OracleASjms/MyTCF.

Using a non-JMS Connector

Let us assume that you want to use your own non-JMS resource adapter let us say thirdra then your EJB 3.0 MDB will look as follows:

import oracle.j2ee.ejb.MessageDrivenDeployment;
import thirdra.common.ThirdListener;

@MessageDriven(name="thirdmdb",messageListenerInterface=ThirdListener.class)@MessageDrivenDeployment(resourceAdapter="thirdra")
public class MessageLogger

Isn’t is simpler than EJB 2.x where you had to handle at least two XML descriptors? If you want to use mix-n-match with descriptor (ejb-jar.xml) make sure that version is set to "3.0" in your ejb-jar element otherwise annotations will not be parsed and container will treat it as an EJB 2.1 descriptor.

However I strongly feel that specifying a resource adapter should be standardized by the future release of specification.

4 comments:

Anonymous said...

Hi Debu,

Which is the jndi that I need to use?

...lookup("java:comp/env/OracleASjms/MyTCF");
...lookup("java:comp/resource/OracleASjms/MyTCF");

How about the queues and topics?

Thanks,
Patrick.

Jeff said...

Please note that in the "Using MDB with a JCA-compliant Resource Adapter" section/case,

@ActivationConfigProperty(propertyName = "DestinationName", propertyValue = "jms/demoTopic"),

should be:

@ActivationConfigProperty(propertyName = "DestinationName", propertyValue = "OracleASjms/MyTopic1"),

(The former style of directly referencing the underlying JMS provider object may function in the current release, but is not supported by the documentation and is recommended against by the maintainer of the JMS Connector.)

Anonymous:

Both are (probably) wrong.

"java:comp/resource" is only for accessing items bound to JNDI using a resource-provider element which is not a supported method of mapping JMS Connector objects. (It is only intended for interfacing "raw" JMS providers.)

"java:comp/env" is only used if you have remapped a JNDI object/location via your application's deployment descriptors. (So unless you explictly mapped "OracleASjms/MyTCF" to "OracleASjms/MyTCF", "java:comp/env" is not the correct answer either.)

Since the JMS Connector instance deployed by default has a topic connection factory mapped at JNDI location "OracleASjms/MyTCF", you are most likely attempting to do a direct JNDI access (not "java:comp/env" mapped), so you should use lookup("OracleASjms/MyTCF").

Krishna said...

Please read this article:
EJB 3.0 Transaction

Naviya Nair said...

Interesting Article

EJB 3 Online Training | Java Online Training

Java Online Training from India | Core Java Online Training