Accueil > Intranet Michel Buffa > Java EE6 Weblogic Exercice 3

Java EE6 Weblogic Exercice 3

De $1

Introduction

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 = { }... in Account.java, try again to remove an Account. Just remove the CASCADETYPE attribute.

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();
     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...

Play with the bean validation API

Bean Validation is a new specification added to the Java EE 6 platform, the JSR-303 specification. It defines an extensible validation constraints mechanism, with a pre-defined set of constraints that can be specified on field, method, type, or annotations. It also defines a validation facility for the Java application developer. The constraints can be specified on a JPA entity and the validation facility ensure these are met during the pre-persist, pre-update, and pre-remove lifecycle events. These constraints can also be used on “backing beans” for forms displayed by JSF. This ensures that the data entered in the form meets the validation criteria.

Here is a good presentation of the bean validation API: http://fr.slideshare.net/openwms/jsr...on-api-3415687

Important things to notice is that this API proposes the same mechanisms to validate in the presentation layer (in JSF2 pages), in the business layer (managed beans, EJBs, etc), and in the data layer (entity classes). the Java Bean validation API is part of JavaEE6 and you do not have to add any external libs to your project.

Let's try a simple example: in the entity bean Manufacturer from the first example of day one, add this line before the "name" :

@Size(min=3 max=10)

private String name;

 

 

Now, try to insert a manufacturer whose name is shorter than 3 characters or longer than 10 characters, you should see such an exception:

Caused By: javax.validation.ConstraintViolationException: Bean Validation  constraint(s) 
violated while executing Automatic Bean Validation on callback event:'prePersist'. 
Please refer to embedded ConstraintViolations for details.

Notice that the validation has been performed by the persistence manager in that case. While the bean validation API can be used without entity classes, in regular java beans, when ussed in entity classes it involves the persistence layer: the validation has been done in some generated code that implements the @PrePersist callback.

Possible values for predefined constraint annotations are (look at this picture: http://miageprojet2.unice.fr/@api/de...nnotations.jpg)

INSERT SCREENSHOT

Notice that it is possible to create your own constraints, or use the bean validation API in a context where code injection is not always possible, like in standalone clients, etc. See this blog post (in french) for such examples: http://blog.octo.com/jsr-303-bean-va...tat-des-lieux/

Look at bigger examples

Example 1

Here is more advanced example of a bank account management program that uses EJBs. It has been written by a student from the Univiersity of Nice so it is not guaranteed that this code is top clean state of the art, but it shows how we could go from the small toy examples we built to a litlle bigger application.

  • Unzip this BigBank.zip archive available at the bottom of this page in your workspace. You should see 4 projects whose names start with BigBank: BigBankEAR, BigBankEJB, BigBankWeb, etc. as usual. 
  • Look at the persistence.xml file in the EJB project, it will indicate the name of the database that has been used by the author of this project. Notice that the settings in this file are "create-and-drop-tables".
  • Just create a new database (use javaDB or MySQL), connect it to Eclipse and Weblogic as we did in previous exercices, change the JNDI name in persistence.xml so that it matches the JNDI name of your database.
  • Deploy the project, run the Web project

Now, look at the code of the EJB part, of the Web part. Notice that there is not @Singleton, @Startup EJB for populating the database this time. The project has been written before EJB 3.1x proposed this feature. SO try to see where the database is populated and  what method has been used to populate it at first use. Can you criticize this method ? What method could have been used (not @Singleton) instead ?

 Example 2

Again, another "bank account manager" that uses entity inheritance.

 

 

Mots clés:
FichierTailleDateAttaché par 
 BigBank.zip
Aucune description
152.84 Ko05:29, 17 Oct 2012MichelBuffaActions
Images (1)
Voir 1 - 1 sur 1 images | Voir tout
Aucune description
BeanValid...  Actions
Commentaires (0)
Vous devez être connecté pour poster un commentaire.