Java EE6 Weblogic Exercice 3

De $1

Version de 14:19, 24 Oct 2020

cette version.

Revenir à liste des archives.

Voir la version actuelle


In this exercice we will play a little more with relations, relations attributes, bidirectional relations, the removal of linked entities, etc. 

Then 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.

Play more with the relations in our example

Try to remove an operation by adding a remove button on the right of the table of operations

Like we did in exercice 1, code a way to remove an operation from the table of operations. There is a trap !

Try to remove an account, what happens to the operations ?

Ah ? 

And what happens if you change the CASCADE annotation to @OneToMany(cascade = { CascadeType.NONE}... in, try again to remove an Account.

Change the Account-Operations to a bidirectional relationship

Look at the example in the course and change the unidirectional relation between accounds and operations into a bidirectional one. Try to display from the list of operations the detail of the account the operation belongs to.

Add a new n-n relation between customers and bank accounts

Now, we are not going to create all the JSP/Servlet code for testing this as it would take too much time (although some of you may finish in advance, this could be an exercice)...

We would like to modelize the fact that a Customer may have several bank accounts and a bank account may be owned by more than one Customer at a time (like joint accounts, or family accounts).

For the exercice, we will say thet a Customer has an id, and a name, plus a list of Accounts. In that case, the Account no more has a "name" of owner, but instead, the names of the different owners would have to be found in every Customer's name property, in the list of Customers associated to an Account.

So, create a n-n relation between Customers and Accouts, and try to associate some customers to accounts and vide-versa in the AccountFace createTestData() method. You will check in the database that the data you inserted are correct.

Try to test removing an account from a customer or a customer from an Account

You may try this just by hard coding it just after you created the test data, or you may modify your servlet so that it takes an "action=removeCustomer&id=3" HTTP parameters for example...

See the difficulty here ?

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();
     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;
} finally {
if (session != null) {
try {
} catch (JMSException e) {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot close session", e);
if (connection != null) {
} }

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

// 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;

public class MyTimer {

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

@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...

Look at a bigger example