Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 5 of 6
An MDB class must implement the MessageListener interface. When the container detects a message for this bean, it invokes the onMessage() method and passes the incoming message as the call parameter. The MDB decides what to do with the message in the onMessage() method. You can use annotations to configure which message queues this MDB monitors. When the MDB is deployed, the container
uses the configuration information specified in the annotations. In the following example, the CalculatorBean MDB is invoked when the container detects an incoming message in the queue/mdb JMS queue. The MDB parses the message and performs the investment calculation based on the message content.
@MessageDriven(activateConfig =
{
@ActivationConfigProperty(propertyName="destinationType",
propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination",
propertyValue="queue/mdb")
})
public class CalculatorBean implements MessageListener {
public void onMessage (Message msg) {
try {
TextMessage tmsg = (TextMessage) msg;
Timestamp sent =
new Timestamp(tmsg.getLongProperty("sent"));
StringTokenizer st =
new StringTokenizer(tmsg.getText(), ",");
int start = Integer.parseInt(st.nextToken());
int end = Integer.parseInt(st.nextToken());
double growthrate = Double.parseDouble(st.nextToken());
double saving = Double.parseDouble(st.nextToken());
double result =
calculate (start, end, growthrate, saving);
RecordManager.addRecord (sent, result);
} catch (Exception e) {
e.printStackTrace ();
}
}
// ... ...
}
| Message-driven beans and POJOs |
|---|
It is important to note that EJB 3.0 MDBs are not pure POJOs. They are lightweight components as they still need to implement
the MessageListener interface. JBoss has a message-driven POJO solution (see References) that uses EJB 3.0-style annotations to build completely
POJO-based messaging applications.
|
In the previous section, you learned how to develop loosely coupled service components. However, to access those service objects, you need to look up stub objects (for session beans) or message queues (for MDBs) from the server's JNDI. JNDI lookup is a key step that decouples the client from the actual implementation of the service object. However, plain JNDI lookup based on string names is not elegant. Here are a few reasons:
EJB 3.0 features a simple and elegant way to make decoupled service objects and resources available to any POJO. Using the
@EJB annotation, you can inject an EJB stub object into any POJO managed by the EJB 3.0 container. If the annotation is tagged
on a field variable, the container will assign the correct value to the variable before the first time it is accessed. The
following example shows how to inject a CalculatorBean stateless session bean stub into a CalculatorMDB MDB class:
public class CalculatorMDB implements MessageListener {
@EJB Calculator cal;
// Use the cal variable
// ... ...
}
If the annotation is tagged on a JavaBean-style setter method for a property, the container automatically calls the setter method with the correct parameters before the property is first used. The following snippet illustrates how that works:
public class CalculatorMDB implements MessageListener {
Calculator cal;
@EJB
public void setCal (Calculator cal) {
this.cal = cal;
}
// Use the cal variable
// ... ...
}
In addition to the @EJB annotation, EJB 3.0 supports the @Resource annotation to inject any resource from the JNDI. In the following example, I illustrate how to inject the server's default
TimerService and SessionContext objects, as well as how to inject named database and JMS resources from the JNDI:
@Resource
TimerService tms;
@Resource
SessionContext ctx;
@Resource (name="DefaultDS")
DataSource myDb;
@Resource (name="ConnectionFactory")
QueueConnectionFactory factory;
@Resource (name="queue/A")
Queue queue;
Furthermore, you can also inject a container-managed persistence manager (i.e., the EntityManager—it resembles the Hibernate Session object) into EJB 3.0 POJOs. I will cover EntityManager in this article's second installment.
In addition to managing the lifecycle and access of the loosely coupled service objects, the EJB 3.0 container also provides runtime services to its managed POJOs via simple annotations.
The most useful container service is probably the transaction service, which ensures database integrity in case of application
failure or exception. You can simply annotate a POJO method to declare its transaction attribute. The container runs the method
in the appropriate transactional context. For instance, the following code declares that the container should create a new
transaction to run the updateExchangeRate() method. The transaction commits when the method exits. In fact, all the methods called from within updateExchangeRate() also execute in the same transaction context, unless explicitly declared otherwise. The database operations performed in
the updateExchangeRate() method either all succeed or all fail.
@Stateless
public class CalculatorBean implements Calculator {
// ... ...
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void updateExchangeRate (double newrate) throws Exception {
// Update the database in a loop.
// ... ...
// The operations in the loop must all be successful or
// the database is not updated at all.
}
}
The container can also provide security services to authenticate users and limit access to its managed POJOs based on user
roles. For each POJO class, you can specify a security domain using the @SecurityDomain annotation, which tells the container where to find the password and user role lists. The other domain in JBoss indicates that the files are users.properties and roles.properties files in the classpath. Then, for each method, you can tag a security constraint annotation to specify who is allowed to
run this method. For instance, in the following example, the container authenticates all users who attempt to execute the
addFund() method and only allows users with the AdminUser role to actually run it. If you are not logged in or are logged in as a nonadministrative user, a security exception will
be thrown.
Archived Discussions (Read only)