The Source for Java Technology Collaboration
User: Password:



Michael Nascimento Santos's Blog

December 2003 Archives


JXPath to rescue!

Posted by mister__m on December 31, 2003 at 07:36 AM | Permalink | Comments (6)

Querying a database is no big deal. SQL has been around for a long time and has become the de facto standard for doing that. So has JDBC, even though nowadays it is being used more as the foundation of other solutions and frameworks. But what you do when you have to query objects? Most people wouldn't be able to answer it, really. Three more common ways of querying your objects in Java are custom indexing, OQL and JXPath. This entry is specifically about JXPath.

Jakarta Commons JXPath basically defines a simple XPath interpreter that can be applied to general object graphs: POJOs, Maps, Servlet contexts, DOMs and more. XPath is a W3C standard originally conceived for navigating XML nodes, but can be easily applied to Java.

Let's see it in action. To ilustrate its use and advantages, we will work with the classical Order problem (Order, LineItem and Product). Let's assume all Orders are stored in a Collection which is a property of our OrderHistory object. What if we wanted to get all the Orders which contained more than 5 CDs? In plain Java:

Collection selectedOrders = new ArrayList();
Order order;
LineItem item;

for (Iterator orders = orderHistory.getOrders().iterator(); orders.hasNext(); ) {
    order = (Order)orders.next();

    for (final Iterator items = order.getLineItems().iterator(); items.hasNext(); ) {
      item = (LineItem)items.next();

      if (item.getQuantity() > 5 && item.getProduct().getType().getName().equals("CD")) {
         selectedOrders.add(order);
      }
    }
}

return selectedOrders.iterator();

To avoid being unfair, using 1.5 sintax:

Collection selectedOrders = new ArrayList();

for (Order order : orderHistory.getOrders()) {
    for (LineItem item : order.getLineItems()) {
      if (item.getQuantity() > 5 && item.getProduct().getType().getName().equals("CD")) {
         selectedOrders.add(order);
      }
    }
}

return selectedOrders.iterator();

With JXPath:

JXPathContext history = JXPathContext.newContext(orderHistory);

return history.iterate("/orders[lineItems[quantity = 5 and product/type/name = 'CD']]");

That is it. As simple as that. JXPath becomes more valuable as your queries become more complex, but I am not going to show an example here.

Someone might ask: hey, but when I would like to manipulate objects in memory? There are a lot of occasions, actually. One very common is when you have a small application that needs to persist a small amount of data. If you combine Prevayler - an option to databases, as it keeps everything in memory and performs persistence through serialization and guarantees data integrity - and JXPath, you have a very fast solution with fewer lines of code. Consider using it when you have the chance.

As a final note, JXPath has many powerful features, as compiled expressions and variables - similar to PreparedStatements -, pointer, and many more, but you can find more about these by yourself. Go to the above link, download and start using it. The User Manual in the docs is probably the best one for a Apache Project and is highly recommended reading. Try it as soon as you can: you may become addicted to it...



A simple method call: that is all it takes

Posted by mister__m on December 29, 2003 at 06:56 PM | Permalink | Comments (0)

Not having the burden of managing transactions by yourself - a.k.a Container Managed Transactions, CMT for short - is a compelling reason for using EJBs. Obviously, EJB is not the only technology that gives you that, but that's a entirely different discussion. Back to the point, the fact you don't have to call any transaction management method neither in java.sql.Connection nor in any class contained in javax.transaction makes a lot of people happy - especially those who already experienced the painful job of calling these manually. Although CMT is good and works - ok, in decent containers, let me be sincere here -, it is not magic and you have certain rules to obey so the container can do its job.

The most obvious thing - at least it should be - you should do is to specify which transaction attribute applies to each method in each EJB you wrote. There are a bunch of ways of doing it in the deployment descriptor, from specifying different attributes to each overloaded version of a method to using the same for all of them, and some containers have decent default values for when you don't declare anything, but I'm not going to cover this here. Today's point is more subtle than that and is something I've seen a considerable number of developers - including some good ones - not doing: calling setRollbackOnly().

javax.ejb.EJBContext, superclass of EntityContext, MessageDrivenContext, SessionContext is the interface that contains this method. The J2EE 1.4 javadoc description for this method is:

Mark the current transaction for rollback. The transaction will become permanently marked for rollback. A transaction marked for rollback can never commit. Only enterprise beans with container-managed transactions are allowed to use this method.

Note that only EJBs that use CMT - most of them - are allowed to use this method. But when are they required to? When it must be called? The answer is relatively simple, but astonishing for some people (from now on, everything here refers to CMT EJBs). Let's start to answer these questions by taking a look at section 17.3.4.2 of the recently published EJB 2.1 spec:

Typically, an enterprise bean marks a transaction for rollback to protect data integrity before throwing an application exception, because application exceptions do not automatically cause the container to rollback the transaction.

I highlighted the bold part and I wish it was already printed in bold in the pdf, actually. A lot of people read this section and simply ignore this important sentence. An application exception does not cause the container to rollback a transaction. It is a simple, but ignored fact. But what is an application exception? Section 18.1.1 defines it:

An application exception is an exception defined in the throws clause of a method of an enterprise bean’s home, component, message listener, or web service endpoint interface, other than the java.rmi.RemoteException.

Enterprise bean business methods use application exceptions to inform the client of abnormal application-level conditions, such as unacceptable values of the input arguments to a business method. A client can typically recover from an application exception. Application exceptions are not intended for reporting system-level problems.

Although the explanation is somewhat deceiving - Java won't stop you from declaring any RuntimeException subclasses in yours throws clause, but that won't make them application exceptions -, I think you got the point. Transactions are not automatically rolled back when you throw your custom Exception-derived instance. The same does not apply to system exceptions, as section 18.2.2 points out:

The Bean Provider can rely on the container to perform the following tasks when catching a non-application exception:

  • The transaction in which the bean method participated will be rolled back.

So, if you throw a RuntimeException or a javax.ejb.EJBException to wrap a checked exception, you are safe. Let's see how we could perform the classical withdraw operation in a Entity Bean:

// Some code goes here

public BigDecimal withdraw(BigDecimal amount) throws InsufficientBalanceException {
  BigDecimal balance = getBalance();

   //Ooops, trying to do something that shouldn't be done
   if (balance.compareTo(amount) < 0) {
      // This call is necessary as the exception to be thrown does not derive from RuntimeException
      entityContext.setRollbackOnly();
      throw new InsufficientBalanceException(balance, amount);
   }

   balance = balance.subtract(amount);
   setBalance(balance);

   return balance;
}

// And more code goes here

Throwing a checked exception is not enough; you need to call setRollbackOnly() so things happen as you expect. It is a simple truth most of us ignore and maybe that's why sometimes there is some corrupt data in our tables - the container will commit any modifications you performed before throwing an application exception unless you've called setRollbackOnly(). If you don't call this method, throw application exceptions after modifying data and never seen this error, consider it to be a bug. Really. And start looking for another container, there are plenty out there. :-D It won't be any fun when your broken container rolls back a transaction that should be commited...

To end up, be aware that setRollbackOnly() does not work all the time. Section 17.6.2.8 explicitly says:

The container must throw the java.lang.IllegalStateException if the EJBContext.setRollbackOnly method is invoked from a business method executing with the Supports, NotSupported, or Never transaction attribute.

So, if all you are bean methods are configured with the Supports attribute, you there is no (standard) way to programatically rolling back transactions! It is creepy, scary and terrifying as it sounds! Pay attention to your transaction attributes! And do not forget to call setRollbackOnly() whenever it's necessary!



Achieving better compression with Deflater

Posted by mister__m on December 26, 2003 at 10:48 AM | Permalink | Comments (4)

I've recently been playing more intensively with CVS - I've always used either IDE support for it or any nice GUI client for CVS available - and found out more about GZIP compression than I knew before. That's my main motivation for this post.

It's been quite a while - since JDK 1.1, according to javadocs - Java has been providing support for working with ZLIB compression through its API. The package java.util.zip contains classes for manipulating GZIP and ZIP formats, as well as for coding to compression utilities directly by using the Inflater and Deflater classes.

So, getting straight to code, if you want to compress an object you are writing to a stream:

   public void writeCompressed(OutputStream os, Object toWrite) throws IOException {
      ObjectOutputStream oos = null;

      try {
         oos = new ObjectOutputStream(new GZIPOutputStream(os));
         oos.writeObject(toWrite);
      } finally {
         if (oos != null) {
            try {
                oos.close();
            } catch (IOException ioe) {
                /*
                 * The day someone gives me a sensible explanation why this method 
                 * throws an exception (as if there was something I could do about it or 
                 * if I cared!), I will be sooooo grateful :-D
                 */
                ioe.printStackTrace();
            }
         }
      }

Besides the ugly try inside the finally block - that deserves a whole post to itself, called "API design we don't get", probably better posted by Hani -, it's pretty simple. I've been working a lot with Prevayler- in a simple way, a very good open-source substitute for databases, faster by far - and as it works with serialization, I thought it would be a good idea to compress the serialized stream it generates. I've written a class you can use with Prevayler that does just that, as part of my open-source project, reusable-components, and it'd been a while since I last modified it. However, after some time manually dealing with CVS, I've noticed GZIP streams can have different compression levels and started wondering if java.util.zip provided support for playing with these.

Indeed, Deflater supports compression levels through a method named setLevel(int). The argument this method takes is yet-another-magical-int-constant-in-the-world, an int argument whose value ranges from 1, a.k.a. BEST_SPEED, to 9, a.k.a. BEST_COMPRESSION. Deflater is used internally by DeflaterOutputStream, which is the superclass of GZIPOutputStream, used in the above example. So if there is a method for setting the compression level, it means it's pretty simple to do it, right? Hum, it's easy, but it could be easier, though.

The problem is that DeflaterOutputStream mantains a reference to its Deflater instance via a protected property named def. It means it is not possible to simply get the Deflater instance and set its compression level. As it is a protected property, though, subclassing GZIPOutputStream will make it accessible. A simple way - in terms of a practical solution, not a very readable one - to do it is using an anonymous inner class with the so-called "anonymous constructor" as shown below:

   public void writeCompressed(OutputStream os, Object toWrite) throws IOException {
      ObjectOutputStream oos = null;

      try {
         oos = new ObjectOutputStream(new GZIPOutputStream(os) {
               {
                   def.setLevel(Deflater.BEST_COMPRESSION);
               }
         });
         oos.writeObject(toWrite);
      } finally {
         if (oos != null) {
            try {
                oos.close();
            } catch (IOException ioe) {
                /*
                 * The day someone gives me a sensible explanation why this method 
                 * throws an exception (as if there was something I could do about it or 
                 * if I cared!), I will be sooooo grateful :-D
                 */
                ioe.printStackTrace();
            }
         }
      }

Using Deflater.BEST_COMPRESSION instead of the default compression level decreases a reasonable (more than 20kb) stream total size by around 10%, according to my tests. GZIP compression makes my serialized objects 80% smaller, which is good, at least for me. This method may be used to fine-tuning the compression level so less CPU cycles are used to transmit something through the network, for example. After some experiencing, you may be able to figure out an ideal value in your specific case and use it as the compression level for your own GZIPOutputStream. Yet another obscure, hidden feature inside the API, recently found out. :-D

If you happen to be using Prevayler and would like to get smaller snapshots, take a look at reusable-components and download the latest version from here. Also, the Enum class has been enhanced to support anonymous subclasses and minor javadoc clarifications have been made, thanks to Jonathan O'Connor suggestions. If you want to join, I'd also be glad.



Building javadoc from J2SDK source code

Posted by mister__m on December 25, 2003 at 07:04 AM | Permalink | Comments (8)

If you read my last blog entry about J2SDK 1.5 alpha availability, you know you cannot make public comments about. So, with that information in mind, let's move on :-D

Suppose you download a J2SDK version from Sun that comes with no documentation at all. Well, all of them come without it, but for most you can get the docs as a separate bundle and install them. Very recently, I downloaded a J2SDK version for which there is no documentation at all. And no, you cannot download it from Sun's site; it is not there. How am I supposed to work with a JDK that has no documentation? At least, I can build javadoc from its source code and it becomes more usable - though not completely, as the new features summary and those sections where concepts are explained and detailed are necessary for a full experience :-D.

In case you happen to face the same problem - if you read my blog frequently, there is a chance you are :-D -, here is a sample Ant build script - not the best possible, it's not the point - you may use to build javadoc from source code:



    
        
        
        
        
        
            
                
                
                
            
        
        
            
        
        
        
            
            
            
            
            
            
            
            
            
            
        
    

That is it, folks! Remember to edit the script so JDK_HOME becomes your real JDK installation home (ex: C:\j2sdk1.4.2_02), JDK_MAJOR_VERSION becomes the major version of the JDK you are using (ex: 1.4, 1.5 ...) and PLATFORM_EXTENSION becomes the extension used by executables in your platform (ex: for Windows, it's exe). And yeah, it consumes a lot of memory. You can change the value -J-Xmx512m as you want, but it didn't work for me with 128mb, for example. It took around 8 minutes to run it in a P4 2.4GHz with 1GB - hey, but I was making normal use of it (4 IM softwares, email client, etc.)



BREAKING NEWS: Got Tiger?

Posted by mister__m on December 24, 2003 at 04:36 AM | Permalink | Comments (0)

I was going to blog about Date and Calendar (and how terrible they are), but these must wait now.

Straight to the point: if you want to get J2SDK 1.5.0 alpha, just go to:

http://www.javalobby.org/members/j2se15.jsp

This is a cooperation between JavaLobby - hey, just became a member 3 weeks ago, after years of Java, can you believe it? - and Sun. This is really a private release, so, you are not allowed to share your opinions about it with anyone except Sun. No, no feedback on this blog or any comments about J2SDK 1.5 alpha are allowed at all. You must be a member of JavaLobby to download it.

Are you still reading this??? Go there and download it now!



Writing enums before Tiger

Posted by mister__m on December 10, 2003 at 10:46 PM | Permalink | Comments (12)

One thing I've been missing in Java is support for enums. Some of you might be asking: but what is a enum and why should I care about them? A enum is, in a simple way, a class with a limited domain. For example, a class representing the seasons we have during the year - although climate seems crazy these days, anyway, but that's a different story - is a enum. Another example would be a class that represents gender, as it only has two values, male and female (though, again, some might argue it is not that simple :-D).

Enums for J2SE 1.5 are being defined by JSR-201. I recommend you read the draft spec when you have the chance, but I'll cite the relevant points as needed. First, let's take a look at the main features both - my implementation and the future J2SDK 1.5 one - share, as specified by the draft spec at the JCP site:

  1. Compile-time type safety
  2. Performance comparable to int constants.
  3. Type system provides a namespace for each enum type, so you don't have to prefix each constant name.
  4. Typesafe constants aren't compiled into clients, so you can add, reorder or even remove constants without the need to recompile clients. (If you remove a constant that a client is using, you'll fail fast with an informative error message.)
  5. Printed values are informative. (Which would you rather see in a stack trace: "Indigo" or "6?")
  6. Enum constants can be used in collections (e.g., as HashMap keys).
  7. You can add arbitrary fields and methods to an enum class.
  8. An enum type can be made to implement arbitrary interfaces.

How is it possible to achieve these things now? By using the Enum class provided by my open-source project, reusable-components! Here is a code snippet:

import net.java.dev.reusablecomponents.lang.Enum;

public final class Gender extends Enum implements MyInterface {
   public static final Gender MALE = new Gender("Male");
   public static final Gender FEMALE = new Gender("Female");

   private Gender(String name) {
      super(name);
   }
}

In this example, MyInterface is a simple marker interface that is implemented just to show you it is possible to do so. :-D The code doesn't look that complicated, but it gives you all those things and also these additional features quoted from the JCP spec:

All enum classes have high-quality toString, hashCode, and equals methods. All 
are Serializable, Comparable and effectively final. None are Cloneable.
Arbitrary fields may be added to enum classes, and to individual enum constants.

To be exact, you have to make your Enum subclasses final. If you subclass an Enum subclass, it simply won't work. However, the greatest feature these Enum subclasses have is that their instances may be compared using the == operator. Even if you deserialize an instance, you still can use the operator instead of calling equals. Isn't that great? I think so, but I'm not neutral enough to give opinions about code I wrote. :-D

Surely, there are some differences between my Enum and the one provided by the JSR-201. I hope to explain most of them here, but to be sure you understand all the differences, read the spec linked above and browse the most recent version of my Enum implementation.

While the J2SE 1.5 enum is intended to give you comparability, it limits the way you naturally compare your instances by making compareTo final. reusable-components' implementation doesn't make the method final, giving you freedom to override it as needed. Besides that, JSR-201 is going to give as an enum facility, which is something much bigger than just a class: we will have a new keyword, new syntax and more compiler "gambiarras", as we would say in Portuguese: the compiler is going to make lots of things to your source code to make it look like a regular class. To give you an idea of what the J2SE 1.5 enum probably is going to be like, here is the original example modified:

public enum Gender implements MyInterface {
   male, female
}

Although it is by far cleaner than the code I showed above, it requires special compiler features and most IDEs won't support it now.

Maybe you could be thinking: but why I need to use a superclass if I can write an enum implementation on without one? Well, you would have to rewrite things you need, such as serialization and == support, for example. The fact you have a base class also helps to organize your code and to evolve it as you find bugs.

Now that I gave you a general idea of what net.java.dev.reusablecomponents.lang.Enum can do, it is time to mention a few more things. There are methods that allow you to get all the instances for a given subclass and to get an instance given its class and its identifying name. Those methods are especially useful if you are using enums as part of a web application: you need to populate combos and to get the selected instance to do your job.

If you are interested enough, I recommend you check the code. You can ask questions and leave your comments below. reusable-components is intended to give you more than that, though; in the next few weeks, I expect to commit some validators for user input and also a cool image generator for use in forms to make sure users aren't frauding your application. Join the project if you want to help. And stay tuned.





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds