Tuesday, February 28, 2006

Using Java 5 enums for the Command Pattern

Perhaps posted about elsewhere (my Google search did not turn up what I was looking for), one of the best uses for Java 5 enums is to implement the well-known Command Pattern.

Just one simple example with two commands, START and FINISH, and a simple execution parameter, sessionId:

/**
 * Demonstrates using JDK5 {@code enum}s for the Command Pattern.
 * 
 * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
 */
public enum CommandEnum {
    /**
     * The {@code START} command.
     */
    START() {
        @Override
        public void execute(final SessionId sessionId) {
            System.out.println("Start: " + sessionId);
        }
    },
    /**
     * The {@code FINISH} command.
     */
    FINISH() {
        @Override
        public void execute(final SessionId sessionId) {
            System.out.println("Finish: " + sessionId);
        }
    };
    
    /**
     * Executes the command.
     */
    public abstract void execute(final SessionId sessionId);
    
    public static void main(final String[] args) {
        final SessionId mySessionId = new SessionId(13);
        
        for(final CommandEnum command : CommandEnum.values())
            command.execute(mySessionId);
        
        final SessionId yourSessionId = new SessionId(31);
        
        CommandEnum.valueOf("START").execute(yourSessionId);
        CommandEnum.valueOf("FINISH").execute(yourSessionId);
    }
    
    private static final class SessionId {
        private final int id;
        
        SessionId(final int id) {
            this.id = id;
        }
        
        @Override
        public String toString() {
            return Integer.toString(id);
        }
    }
}

A nice benefit of this use of enum is that one need not refactor existing code to take advantage. Use the enums with the Adapter or Facade Patterns and replace the bodies of execute() with forwarding calls to the original code implementations. Then new code can use the Command Pattern while existing code can continue to use the (possibly @Deprecated) original calls.

Monday, February 20, 2006

Bootstrapping Maven dependencies into Ant

One thing about builds I detest: packing the universe into the source tree. Maven and Ivy are two good solutions for this problem, keeping your external dependencies out of your source control system. And they both work with Ant.

But how to get the ball rolling?

Helpfully, Ant has the get task for fetching files from the Internet. Thus I can fetch Ivy or the Maven-Ant bindings, plug them into build.xml, and pull down my other dependencies all without checking in anything outside of my project.

Here's how:

  1     <property name="target.dir" location="target"/>
  2     <property name="maven-artifact-ant.bootstrap.jar"
  3               location="${target.dir}/maven.artifact-ant-2.0.2-dep.jar"/>
  4 
  5     <target name="-check-get-maven-artifact-ant">
  6         <available property="-get-maven-artifact-ant-done"
  7                    file="${maven-artifact-ant.bootstrap.jar}"/>
  8     </target>
  9 
 10     <target name="-get-maven-artifact-ant"
 11             depends="-check-get-maven-artifact-ant"
 12             unless="-get-maven-artifact-ant-done">
 13         <mkdir dir="${target.dir}"/>
 14         <get src="http://www.apache.org/dist/maven/binaries/maven-artifact-ant-2.0.2-dep.jar"
 15              dest="${maven-artifact-ant.bootstrap.jar}"/>
 16     </target>
 17 
 18     <target name="-maven-artifact-ant" depends="-get-maven-artifact-ant">
 19         <typedef resource="org/apache/maven/artifact/ant/antlib.xml"
 20                  uri="urn:maven-artifact-ant">
 21             <classpath>
 22                 <pathelement location="${maven-artifact-ant.bootstrap.jar}"/>
 23             </classpath>
 24         </typedef>
 25     </target>
 26 
 27     <target name="init" depends="-maven-artifact-ant">
 28         <tstamp/>
 29         <!-- All the other init tasks: buildnumber, mkdir, et al -->
 30     </target>

In essence the steps are:

  1. Check if there is already a downloaded jar (-check-get-maven-artifact-ant).
  2. If not, fetch one from a well-known location (-get-maven-artifact-ant).
  3. Load the bindings from the jar into Ant (-maven-artifact-ant).

Now build.xml is ready to proceed with Maven (or Ivy) for fetching dependencies and deploying them.

A tricky ant trick

It took me some time to get this exactly right (if such a thing can be said): How to get ant to copy over a set of files when one is out of date, but do nothing otherwise. Pretty simple, I know, but still I discovered several gotchas. Here is what I wound up with:

(Yes, this does not resemble a production ant script. The real task was signing jars for JNLP deployment from a CVS repository into a staging directory if they were not already there.)

<project default="boom">
    <property name="bob" location="bob"/>
    <property name="nancy" location="nancy"/>

    <fileset id="bobs" dir="${bob}"/>

    <target name="check-up">
        <uptodate property="dental">
            <srcfiles refid="bobs"/>
            <mapper type="glob" from="*" to="${nancy}/*"/>
        </uptodate>
    </target>

    <target name="boom" depends="check-up" unless="dental">
       <echo message="Ka-BOOM!"/>
       <copy todir="${nancy}">
           <fileset refid="bobs"/>
       </copy>
    </target>
</project>

Some of the mistakes I made along the way:

  • The unless attribute of target is just a plain token; do not try to surround it with dollar-curly braces>.
  • If you do not give srcfiles an includes or refid attribute, it silently does nothing rather than complaining.
  • The from attribute to mapper takes a plain asterisk and is relative to the srcfiles: it was easy to get this wrong in several ways and only experimentation saved me.

In short this is a nice setup to avoid extra build work, but it is somewhat fragile and Ant needs more documentation and examples in this area.

Thursday, February 16, 2006

Moving the view away from the controller

One of the most widely used embodiments of MVC architecture is the web application. Finding its most widespread origin in the desktop application framework, modern enterprise MVC applications live and breathe the Internet and the browser.

One result, however, is that the model, controller and viewer are usually colocated: the browser may display the web pages and let the user send input back, but it is in the server pages that the real code for the viewer runs. This is changing, perhaps.

New AJAX technologies are pushing some of the work of the viewer into the browser. One result is that whereas with Web 1.0 the viewer and controller run in situ on the server and developers must take care not to mix them, with Web 2.0 the joys of RPC appear and AJAX writers should bunch up requests for good performance. (Although seeing the responsiveness of Google's AJAX application, I wonder how much larger, faster bandwidth alleviates this problem.)

What I would like to try is this: in addition to enrichening the browser with AJAX, I would like to explore using Java WebStart for full-blown desktop applications while keeping the model and all or a portion of the controller back on the server.

Perhaps with SOAP, or simple XML-RPC, or even with extensions of HTTP (the path followed by WebDAV) the desktop application can call back to the server for work in the domain, model and persistence layers, while keeping a rich presentation layer local.

Thinking more about this, I can see the split between viewer and controller shifting under this circumstance. Say one had a tabbed application interface. Changing tabs with a Web 1.0 application involves trips to the controller to redirect the view. But changing tabs with a desktop application require no such direction. The initial view of the tab, though, would need the model on the server.

By no longer colocating all the MVC pieces, the relation or balance of power among them changes in, I believe, new and interesting ways. It is another option in the new Web 2.0.

Tuesday, February 14, 2006

Fresh, hot JNLP muffins

An OutputStream wrapper class for JNLP muffins (which are to JNLP as cookies are to HTTP):

  1 public class MuffinOutputStream
  2         extends DataOutputStream {
  3     final String name;
  4 
  5     /**
  6      * Constructs a new {@code MuffinOutputStream} for
  7      * the given <var>name</var>.  Nothing
  8      * happens<em>even on writes</em>  9      * until {@link #close()} when everything is written
 10      * at once after all the writes are collected
 11      * together first before committing.
 12      *
 13      * @param name the muffin name relative to the JNLP
 14      * code base
 15      *
 16      * @see PersistenceService#get(URL)
 17      * @see PersistenceService#create(URL, long)
 18      */
 19     public MuffinOutputStream(final String name) {
 20         super(new ByteArrayOutputStream());
 21 
 22         this.name = name;
 23     }
 24 
 25     /**
 26      * Really writes the queued data to the muffin.
 27      * <p/>
 28      * {@inheritDoc}
 29      *
 30      * @throws IOException if the muffin cannot be created,
 31      * opened or written
 32      */
 33     @Override
 34     public void close()
 35             throws IOException {
 36         super.close();
 37 
 38         final ByteArrayOutputStream baos
 39                 = (ByteArrayOutputStream) out;
 40         final OutputStream muffinStream = open(name,
 41                 baos.size());
 42 
 43         copyStreams(new ByteArrayInputStream(
 44                 baos.toByteArray()), muffinStream);
 45 
 46         muffinStream.flush();
 47         muffinStream.close();
 48     }
 49 
 50     private static OutputStream open(final String name,
 51             final int maxsize)
 52             throws IOException {
 53         try {
 54             final PersistenceService ps = lookup(
 55                     PersistenceService.class);
 56             final URL codeBase = lookup(
 57                     BasicService.class).getCodeBase();
 58             // Escape bad URL characters
 59             final URL muffin = createMuffin(codeBase,
 60                     encode(name, "UTF-8"));
 61 
 62             // Parent must exist, but do not clobber if so
 63             boolean parentAlreadyExists = false;
 64 
 65             try {
 66                 try {
 67                     ps.create(codeBase, 0);
 68 
 69                 } catch (final IOException e) {
 70                     parentAlreadyExists = true;
 71                 }
 72 
 73                 try {
 74                     // Remove exising in case size is wrong
 75                     ps.delete(muffin);
 76                 } catch (final IOException e) {
 77                     // Truly ignore: ok to fail on deletion
 78                 }
 79 
 80                 ps.create(muffin, maxsize);
 81                 // Saved on client, not on server
 82                 ps.setTag(muffin, DIRTY);
 83 
 84                 return ps.get(muffin).getOutputStream(true);
 85 
 86             } finally {
 87                 if (!parentAlreadyExists)
 88                     ps.delete(codeBase);
 89             }
 90 
 91         } catch (final IOException wrapped) {
 92             final IOException e = new IOException(
 93                     "Cannot save data to " + name);
 94 
 95             e.initCause(wrapped);
 96 
 97             throw e;
 98         }
 99     }
100 }

(Note several helper methods used in the code, but not presented here: lookup, createMuffin and copyStreams.)

Writing MuffinInputStream is much simpler since one need not worry about parent muffins, nor bunch up the output to work out the size of the muffin before persisting. And neither does the "delay until close" pattern come into play. This is one of those times I wish I had C++ destructors for my Java.

More on service lookup helpers

I recently wrote about a JNLP convenience method for looking up JNLP services based on a class literal rather than a string name of class, and handling casting for you with generics rather than having the calling code cast the return. It turns out that Sun has been thinking in that direction already for JDK6 with the java.util.Service class and metadata conventions.

I was fortunate to run across this interesting improvement from a commenter on Bob Lee's blog and his remarks on Spring. Thank you Sam Pullarra for pointing this out. As suggested by the Java generics tutorial, using class literals as type tokens leads to many curious and beneficial paths.

UPDATE: As usual, Erik's linkblog is the place to find great links like this.

Sunday, February 12, 2006

Generics and the EJB Business Interface Pattern

A common EJB pattern which gets both praise and condemnation is the Business Interface Pattern. The very excellent Bitter EJB digs right in early on, pointing out one of the problems is that whereas remote interface methods must declare throws RemoteException, local interfaces are specifically forbidden from actually throwing this exception.

One idea I would like to try is to leverage generics:

 1 public class LocalException
 2         extends RuntimeException {
 3     // Constructors, et al
 4 }
 5 
 6 public interface SomeBusinessInterface<E extends Exception> {
 7     public void payForHoneymoon()
 8             throws E;
 9 }
10 
11 public interface LocalSomeBusinessInterface
12         extends SomeBusinessInterface<LocalException>, EJBLocalObject {
13     // Local methods
14 }
15 
16 public interface RemoteSomeBusinessInterface
17         extends SomeBusinessInterface<RemoteException>, EJBObject {
18     // Remote methods
19 }
20 

The generic specification for the exception hides RemoteException from the local interface, while it can harmlessly declare that the interface throws LocalException. Worth a try.

UPDATE: Fortunately, EJB 3.0 should moot all of this.

Also some variations include declaring a private constructor for LocalException so no one can actually create one to throw, and overriding the declaration of the business methods in LocalSomeBusinessInterface to have no throws clause for any of the methods. Code generation is good for this.

Friday, February 10, 2006

A JNLP API convenience method

I am working with the JNLP API at the moment, and I find myself constantly using ServiceManager.lookup(String) and the painful call with a string (have you seen my typing?) and casting of the return.

Since I am fortunate to be using JDK5 on this project, I created a convenience method for this purpose:

  1 private static <T> T lookup(final Class<T> clazz) {
  2     final String className = clazz.getName();
  3 
  4     try {
  5         return (T) ServiceManager.lookup(className);
  6 
  7     } catch (final UnavailableServiceException e) {
  8         final String message = "No JNLP service: "
  9                 + className;
 10 
 11         showMessageDialog(null, message,
 12                 "WebStart Error", ERROR_MESSAGE);
 13 
 14         throw new IllegalStateException(message, e);
 15     }
 16 }
 17 

There are two advantages to this technique.

First, I can replace all my calls using strings and casts to just this: final BasicService basicService = lookup(BasicService.class);.

Second, I can lose the try { /* lookup */ } catch (final UnavailableServiceException e) { /* Handle exception */ } blocks anytime I use a service, and trade them for helpful dialogs with the user.

Thursday, February 09, 2006

Matt Raible on Tomcat and Ant

I was casting about the Internet for tidbits on deploying to Tomcat from an Ant build, and found just the right thing: Matt Raible's wiki page on Tomcat Ant Tasks. His is possibly the best site on the Internet for this sort of practical advice on Java web application development. And his blog is always worth a read.

Tuesday, February 07, 2006

SmoothMetal 1.1

I just made my first release of SmoothMetal, 1.1. The release notes are simple:

Version 1.1 of SmoothMetal has just been released. What's new?

  • Compilable with JDK 1.4.2.
  • Tested with JDK6 beta.
  • Smooth borders of internal frames, internal dialogs and color palettes with SmoothMetal.
  • Update demo app to demonstrate the new smoothings.
  • Show demo app with a JDK default border rather than the native platform border to demonstrate smooth frames better.
  • In demo app toggling anti-alias and font metrics rebuilds the UI from the top-level pane down, not just refreshing it. Smoothed fonts often have somewhat different metrics than unsmoothed, and the layout is imperfect otherwise.

This is the first release from me, as I am usually stuck on Windows when in a coporate environment, or when writing WebStart applications which run on Windows. (Notice a theme here?)

I made the error of dropping James Shiell a line so he added me to the SourceForge project as an admin. Serves me right.

Please drop me a line if you would like to see something about SmoothMetal changed.

Monday, February 06, 2006

The SmoothMetal project

I had a pleasant email conversation with the administrator of the SmoothMetal project on SourceForge, James Shiell--a very fine fellow--, and lo and behold, I am now one of the project admins!

Basically, I volunteered to add some more smoothing pieces to the project, and James does not have the hardware or time to look after them, so I will make them myself.

That means that in a few days there will be a 1.1 release of SmoothMetal. More anon.