Sanity check your ORM

Have you ever had your application completely crash under load and wondered why something that just worked fine yesterday can drive you mental today?

Most of the time an Object-Relational Mapping package is the right solution for your applications to interact with a database. It does not matter if it is free, commercial or home grown, you will generally find that it reduces the amount of code. Moreover, the application code is better designed and easier to test. Depending on your chosen solution, you may even see performance improvements with caching and database specific optimisations.

However, you may also find substational performance degradations when the data volume increases. It is important to remember that no matter how sophisticated your ORM package is, it may still produce inefficient SQL statements. If you had SQL statements embedded in your code you would review that as part of the code review. So if you are going to hand over a critical operation such as the generation of SQL statements then these need to be reviewed.

Your application can become a performance crime scene. What can you do to prevent it? Early analysis.

The execution plan, sometimes called query plan or explain plan, for an SQL statement will provide insight into how the database will act on the SQL statement. It is available in most databases and is a useful tool to determine the efficiency of the statement. For example, an execution plan can indicate what indexes would be used. When code is being reviewed, the execution plans for SQL statements should also be reviewed, in much the same way that the running test classes would be reviewed for correctness.

I learned this the hard way when I found a delete operation took too long and eventually timed out in a test environment that had a high volume of records. A review of the code showed a nice, clean object oriented design and a very simple, easy to understand ORM configuration. The application in question was used to manage financial documents. It had the concept of a ChequeBook, one or more Cheques in a ChequeBook, but also that both a ChequeBook and Cheque were a Document. The class diagram in this article illustrates that relationship. The relationship was also reflected in the database with corresponding tables. The ‘type’ attribute was used as a discriminator for the two concrete objects: ChequeBook and Cheque.


The problem arose when attempting to delete a ChequeBook. The ORM could delete the Cheque records using the parentContentId easily enough, but since there was no corresponding column on the Documents table, the ORM then produced this innocuous looking statement.

DELETE FROM DOCUMENTS
WHERE TYPE = ‘CHEQUE’ AND
ROW_ID NOT IN (SELECT ROW_ID FROM CHEQUES)

Appears quite innocent at first, in fact it might even be thought quite a clever attempt to clean up all records on the DOCUMENTS table that should have a corresponding CHEQUES record but doesn’t. In the development database with only a few hundred CHEQUES, this performs ok. Push that up to a few thousand and you soon realise the problem with doing this blanket select statement on CHEQUES even if it does use an index.

In this case I had to code around the ORM with a hand crafted SQL statement. I could have just invoked remove() on each Cheque entity, but for large ChequeBooks this would have produced a lot of SQL statements. Another approach could have been to use a stored procedure but that would not have been easily portable.

The key lesson learned though was to sanity check the ORM before it drives you crazy with it’s unexpected eccentricities. Check your ORM documentation to see how you can get profile details of the SQL statements generated. Go to your database server and get reports on SQL execution plans. The ORM is effectively another developer on your team generating SQL statements. Know and understand what it is producing.

Dice Service does not auto deploy on WLS 10

I really wanted to see if WLS 10 would auto deploy the Dice Service WAR file just as easily as the OC4J, JBoss and Glassfish containers did. Since my early J2EE days (I started developing with Tengah WebLogic before BEA bought the small San Francisco based company) WLS has been a platform of choice for me. However, I have found that the Dice Service does not automatically deploy on WLS like it does on the other platforms.

The deployment error is:
weblogic.application.ModuleException: [HTTP:101216]Servlet: “DiceServicePort” failed to preload on startup in Web application: “WebServices.war”.
javax.servlet.ServletException: Servlet class: ‘soastation.jaxwsdice.Dice’ does not implement javax.servlet.Servlet

This will require some investigation, perhaps running through some of the WLS JAX-WS examples to find out what it’s real dependancies are. Watch this space.

JAX-WS & JAXB rock and roll…

During his Wednesday keynote at the JavaOne conference last week, Oracle Senior Vice President Thomas Kurian unveiled the next-generation architecture for Oracle Fusion Middleware. The 11g Technology Preview of JDeveloper and OC4J are currently available. Also available are some nifty tutorials and demos like Web Services Development in Oracle JDeveloper which shows off some great JEE 5 features like JAX-WS and JAXB 2.0. Although the latter is not really focused on much in the tutorial, it is the basis of what gets your java objects to and from XML.

What these two standards bring to the table from a web service development point of view is a more lightweight POJO oriented way of developing services. They will not make for better SOA in the enterprise though. In fact, they may even make things worse since a poorly designed interface can easily get a false SOA badge of credibility amongs the uninitiated by being exposed as a web service. Enough with the rant already, on with the example…

I thought it would be interesting to expand upon the bottom up HelloService tutorial by making things a bit more complicated with some old world technology: Dice. The Dice class in this example has a roll(List) operation that rolls the dice (plural of die) passed to it and returns the result. So there are really only two classes in this example:

  • Die represents (you guessed it) a die. It has two properties, number of sides and value.
  • Dice provides the collective operation of rolling dice.

This is the Die source:

package soastation.jaxwsdice;

public class Die {
protected int numberOfSides;
protected int value;
public Die() {
this(6); //Default number of sides is Six;
}
public Die(int sides) {
if (sides < 2)
throw new throw new IllegalArgumentException();
this.numberOfSides = sides;
}
public int getNumberOfSides() {
return numberOfSides;
}

public int getValue() {
return value;
}

public void roll() {
int rollValue = (int) (this.getNumberOfSides() * Math.random()) + 1;
if (rollValue > this.getNumberOfSides())
rollValue -= 1;
this.value = rollValue;
}
}

Note that the number of sides property is immutable and the value defaults to zero until the die is first rolled. It would seem natural to extend something like Integer to hold the ‘value’. This can’t be done in Java as these classes (Number, Integer, BigInteger, etc) are immutable so changing the value on every roll is not a runner. Besides, Integer is final so can’t be extended anyway.

You’ll probably also note the lack of comments on the code too. Tell me if you are for or against comments in code!

Here is the Dice source:

package soastation.jaxwsdice;

import java.util.Iterator;
import java.util.List;

public class Dice {

public List roll(List dice) {
Iterator diceIterator = dice.iterator();
while (diceIterator.hasNext()) {
Die die = diceIterator.next();
die.roll();
}
return dice;
}
}

The rest of the steps are identical to the HelloService example (which you can also get to from the Build Web Service link on the Start page of the JDeveloper 11 Technology Preview ).

  1. Add an @WebService annotation to the Dice class
  2. In the code fix menu select Configure project for web services
  3. Choose the Java EE 1.5 option and press OK
  4. Add an @WebMethod annotation to the roll method
  5. Right click on Dice service (note that the icon has changed) and select Test Web Service
  6. Gaze in awe at the handy HTTP Analyzer with Web Service support. That’s all you can do at this stage because JAX-WS doesn’t know what to do with the Die class.

This is where JAXB really comes into play. We want the properties of the Die object to be properly represented in the web service. Lets make the number of sides an attribute and the value of the Die appear as the value of the element. Do this by:

  1. Add @XmlAttribute(name=”sides”) to the numberOfSides field.
  2. Add @XmlValue to the value field.

Now you can test the web service again by right clicking on the Dice service in the Applications Navigator and selecting Test Web Service. In the HTTP Analyzer window you can enter the details of each die you want to roll. By clicking on the plus sign you can add more die to the SOAP request. The value attribute is in the schema but has no relavance to the operation (unless you want to implement a LoadedDie object?). Actually, you could leave the number of sides blank too as it will default to 6.

This example takes advantage of convention over configuration features of JEE 5. The property inspector in JDeveloper 11g Technology Preview provides some great tooling around the annotations. It is worth playing with it to see the extent of configuration possible.

We can improve the WSDL and XML representations with annotations. In the Dice class add a @WebResult(name=”die”) annotation to the roll method so that the result is not called ‘result’ by default. Also, in the roll method arguments add @WebParam(name=”die”) annotation so that the die element does not get call ‘arg0’ by default.

These JAX-WS and JAXB annotations make the web service and XML representation of the java operation and classes much more suitable. Of course these simple examples only scratch the surface of what can be achieved. It is a good idea to get familiar with capabilities of both technologies.

Let me know how you get on.