Introduction to POJO (Plain Old Java Object) Programming Model
One of the new features of added by Sun Microsystems in EJB 3.0 is POJO (Plain Old Java Object). It is a Java object that doesn't extend or implement some specialized classes and interfaces respectively require by the EJB framework. Therefore, all normal Java objects are POJO?s only. The following classes are not POJO classes shown as:
class
MyServlet extends HttpServlet {}
class MyRemote implements SessionBean {}
In POJO model, it is recommended that, interfaces should be explicitly implemented whenever you want to pick and choose the methods of the interface. The interfaces are optional for entity beans but required for session beans and message-driven beans. In this model, both the interface and the bean class do not have to throw unnecessary exceptions such as RemoteException.
The interface class in POJO model is a Plain Old Java Interface (POJI).
The Benefits of POJOs:
Decoupling: It decouples the application components
from the infrastructure of the EJB framework that lets you construct an
application from loosely coupled components. There are no longer need to write
the tedious JNDI framework-specific lookup code. You can design and implement
the business logic. Once that's working, and then you can deal with persistence
and transactions.
Easier testing: You can test or run your business
logic outside of the application server in a few seconds.
Flexible: A Java POJO code can be implemented with any type of enterprise
bean such as Message Driven Bean and Entity Bean.
Let?s understand the POJO with Message Driven Bean:
Message Driven POJOs:
Message-driven POJOs offer the functionality like MDB to make a simple JavaBeans for the developers. Similar to a MDB in EJB, it acts as a receiver for JMS messages.
Writing a message-driven POJO is not much different than writing a
message-driven EJB. The major difference between both is that, an message-driven
POJO (MDP) must
implement the javax.jms.MessageListener interface. Like an MDB, you don't have to implement
javax.ejb.MessageDrivenBean and the EJB lifecycle methods defined by the interface.
The EJB 3.0 uses annotations to build completely POJO-based messaging
applications.
In EJB 3.0?s container application server, there is an easier way to implement message driven RPCs. You can use POJOs as message end-points (message driven POJO). The RPC caller retrieves an automatically generated stub of the POJO and makes regular calls against the POJO methods. The message driven POJO works much like a session bean of EJB3, except that all calls are tunneled via a message queue.
Let?s see the structure of Message Driven POJO given below:
Now, let?s
see how message driven POJO is used in EJB3 taking an example.
In our sample
application, the class MessagePojoClient.java asynchronously invokes the onMessage
method to display a simple ?Hello...? message on a message driven POJO over
a message queue. After the message driven POJO finishes the display task, it
saves the result in a server wide cache manager.
The POJO business interface:
In our example, we are using the javax.jms.MessageListener
interface, so we don?t need to define it again. You can also define new
interface using @producer annotation to implement specific methods.
The message driven POJO implementation:
The implementation of the message driven POJO is tagged with the @Consumer annotation. You can specify the message queue property in the annotation attribute. If a message queue is un-defined, the EJB container will create one for you at server start-up.
The code for MDP is given below:
package mdb.pojo; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; @Consumer(activationConfig = { @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"), @ActivationConfigProperty(propertyName="destination", propertyValue="queue/mdpojo") }) public class MDPojoBean implements MessageListener { public void onMessage(Message message) { if (message instanceof TextMessage) { try { TextMessage tmsg = null; tmsg = (TextMessage) msg; System.out.println( "Message received: " + tmsg.getText()); } catch (JMSException ex) { throw new RuntimeException(ex); } } else { throw new IllegalArgumentException("Message must be of type TextMessage"); } } }
Note that, here we didn?t use @MessageDriven annotation to map the JNDI name.
The Client:
To
use the message driven POJO on the client side, client looks up a stub object of
the @Producer
interface from the JNDI. The auto-generated stub-object not only implements the
@Producer interface but also a component interface named ProducerObject. Using the
ProducerObject.getProducerManager()
method, you can get a ProducerManager object, which is used to make JMS connections. After a JMS connection is
established, you can call any method in the @Producer
stub object and the method is actually invoked over the pre-defined message
queue. The following code snippet shows how the message driven POJO client
works.
package mdb.pojo; import javax.jms.*; import javax.naming.*; import java.text.*; class MessagePojoConn{ public MessagePojoConn(){ ProducerManager manager = null; MessageListener msglst=null; try { // lookup a stub object of the MessageListener interface from the JNDI InitialContext ctx = new InitialContext(); msglst = (MessageListener) ctx.lookup(MessageListener.class.getName()); ProducerObject po = (ProducerObject)msglst; ProducerManager manager = po.getProducerManager(); } catch (Exception e) { e.printStackTrace (); } manager.connect(); // internally create a JMS connection try{ msglst.onMessage("Hello Message Driven POJO"); } finally{ manager.close(); // clean up the JMS connection } } } public class MessagePojoClient{ public static void main(String[] args){ MessagePojoConn msgcon = new MessagePojoConn(); } }
Description of Code:
When the EJB3 container deploys the @Consumer, it looks
for all of its implemented interfaces and registers each one of them in JNDI
under. The client code above looks up the MessageListener interface in
JNDI. Each producer implements the ProducerObject. The client typecasts
the MessageListener to the ProducerObject. It then gets a ProducerManager
that manages the JMS connection for this proxy. To start being able to send
messages to the Queue, the client calls Connect( ) method on the manager.
It then can successfully call methods on the "msglst" object.
This method called onMessage( ) is
converted into a JMS message and published to the Queue of the Consumer. The
consumer will receive the message and invoke its onMessage method.
There are a variety of ways to send a JMS message such as using JmsTemplate or Spring. Let?s see the configuration of the message listener containers that ships with Spring.
<!-- this is the Message Driven POJO (MDP) --> <bean id="queue/mdpojo" class="jmsexample.MDPojoBean" /> <!--This is the message listener container --> <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory"/> <property name="destination" ref="destination"/> <property name="messageListener" ref="messageListener" /> </bean>
Deploy and Run the MDP Application: