Java EE6 Weblogic Exercice 3

De $1

Version de 08:45, 19 Avr 2024

cette version.

Revenir à liste des archives.

Voir la version actuelle

Introduction

In this exercice we will use JMS and Message Driven beans, by adding to the previous exercice the possibility to process Bank Account operations asynchronously by sending messages.

We will also play with some other goodies like EJBTimers and Asyncrhonous method calls.

Add a JMS destination queue to Weblogic, write a MDB and a Servlet to test

This is the tricky part... Follow the instruction from the  Weblogic / Java EE6 FAQ and Guides, follow the section  "Use JMS and a Message Driven Bean on Weblogic" entirely. You will add the Message Driven Bean and the Servlet in the EJB project from exercice 2. Try to execute the Servlet to see the results.

Adapt the Message Driven Bean and the Servlet so that it can be used to send Bank Account Orders

Write a new java class called BankAccountOrder

In a new package "beans" write a new class that describes an order we will send as a message to the Message Driven Bean, that will read the message, decode the object received and then delegate the treatment to the AccountFace session bean.

For example, if you send a "createAccount" order with an inital balance of 10.000 and an owner name equals to "Michel Buffa", then when the MDB gets this message, it will call the AccountFacade's create() method for creating a new bank Account. Etc. 

The BankAccountOrder bean should have these properties: order, ammount, name, id1, id2. Not all properties will be necessarily used depending on the value of the order (create, remove, transfert, add, remove, etc.)

It should implements Serializable as instances of BankAccountOrder will be sent through the network as ObjectMessage content.

Adapt the code from the Servlet in order to send instances of BankAccountOrders within JSM ObjectMessages

The example you wrote from the previous section sends TextMessages. Modify the code from the Servlet in order to send an BankAccountOrder. Instead of sending TextMessages, you will have to send ObjectMessages. Just look at the current code of the two methods that send messages:

 private TextMessage createJMSMessageForjmsLoggingMessages(Session session, String messageData) throws JMSException {  
     TextMessage message = session.createTextMessage();
     message.setText(messageData);
     return message;
}

private void sendJMSMessageToDemoQueue(String messageData) throws JMSException {
Connection connection = null; Session session = null;
try {
connection = demoMessageFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(demoQueue);
messageProducer.send(createJMSMessageForjmsLoggingMessages(session, messageData));
String messageClient = "Message sent :" + messageData;
System.out.println(messageClient);
} finally {
if (session != null) {
try {
session.close();
} catch (JMSException e) {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot close session", e);
}
}
if (connection != null) {
connection.close();
} }

Just change the "String messageData" into "BankAccountOrder messageData" in the input parameters of these methods, change TextMessage by ObjectMessage everywhere.

Adapt the message driven bean so that it can handle ObjectMessages as well as TextMessages

Modify the content of the onMessage(Message message) method by adding a new test:

if (message instance of ObjectMessage) {
    ... 
    //get the object inside the message
    ....
    // Cast it in AccountOrderObjects
    ....
    // decode it (look at the value of the "order" property, get other properties...
    ....
    // Call the AccountFacade to do the work...
}

Make a rapid test to check that more than one instance of the message driven bean may be created

For this test, we will simulate a process that takes a long time. Add this code to the message driven bean in the previous code...

// at the beginning...
System.out.println("Just got an order to proceed, will take some time...");
// call account facad
...
// simulate a 7s treatment
Thread.sleep(7000);

// Print end of treatment
System.out.println("Order processing finished");

Add the required try.. catch... test it. Then when you invoke the servlet, press the reload button a few times quickly in your web browser so that several JMS messages are sent in a short ammount of time. 

Look at the console logs... You should see something like:

Just got an order to proceed, will take some time...
Just got an order to proceed, will take some time...
Just got an order to proceed, will take some time...
Just got an order to proceed, will take some time...
Just got an order to proceed, will take some time...
Just got an order to proceed, will take some time...
Order processing finished
Just got an order to proceed, will take some time...
Order processing finished
Order processing finished
Just got an order to proceed, will take some time...
Just got an order to proceed, will take some time...
Order processing finished
Order processing finished

This means that each time a message arrived processing has been done in parallel (by different instances)

Try the @Asynchronous annotation

This time, you will run the Servlet you developped for exercice 2, the one with the forms for creating or displaying new accounts.

Modify the createTestData() method by adding a Thread.sleep(7000) too so that executing this method takes 7s. Add a link in the Servlet for calling this method when the link is clicked and try clicking on it. Hmmm the jsp page with the list of Accounts is displayed seven seconds later as we have been actively waiting for the createTestData() to perform.

Now add just the @Asynchronous annotation before the method. Do the same test. Huh !

Try the new EJBTimers from EJB 3.1 specification

Just add to the "sessions" package of your project a new class of type "EJB timer", call it MyTimer.

This will pop up a dialog in which you will be able to configure the schedule for your timer. The syntax for specifying when your timer will be called is similar to the one used by Unix's crontabs.

A typical schedule:

second="*/10", minute="*", hour="8-23", dayOfWeek="Mon-Fri", dayOfMonth="*", month="*", year="*", info="MyTimer"

This is the default value proposed by the Eclipse dialog for creating EJB timers, it means:

  • Call the timer every 10 seconds (*/10)
  • Every minute,
  • For the hours between 8 and 23,
  • For days from Monday to Friday,
  • Every month,
  • Every year... 

The class you should get looks like that:

package sessions;

import javax.ejb.Schedule;
import javax.ejb.Stateless;
import javax.ejb.Timer;

@Stateless
public class MyTimer {

/**
* Default constructor.
*/
public MyTimer() {
// TODO Auto-generated constructor stub
}

@SuppressWarnings("unused")
@Schedule(second="*/10", minute="*", hour="8-23", dayOfWeek="Mon-Fri",
dayOfMonth="*", month="*", year="*", info="MyTimer")
private void scheduledTimeout(final Timer t) {
System.out.println("@Schedule called at: " + new java.util.Date());
}
}

Notice that an EJB timer is a stateless session bean (@Stateless), that the method that should be called at given period of times is preceeded by a @Schedule annotation that is parameterized by a schedule definition. Deploy this project and look at the console, you should see some messages in the console, and every 10s, a new message should appear...