Monday, 30 November 2009

Code Dump: Stubbing with a map

A year or so back I wrote a cool little utility class MyInvocationHandler. This is used by simply creating a map of the proprieties and their values simply as I felt that:
Map backing = new HashMap();
backing.put("title", "ihaztehcodez");
backing.put("getURL",
            "ihaztehcodez.michael-lloyd-lee.me.uk");
Blog thisHereBlog = create(backing, Blog.class);

was easier on the eyes that the EasyMock styled
Blog thisHereBlog = createNiceMock(Blog.class);
expect(thisHereBlog.getTitle())
   .andReturn("ihaztehcodez").anyTimes();
expect(thisHereBlog.getURL())
    .andReturn("ihaztehcodez.michael-lloyd-lee.me.uk")
    .anyTimes();
replay(thisHereBlog);

However I was wrong to use either method. If I was to do so again I'd use write a BlogBuilder. It is a good chunk more work up front, but it leads to significantly better reading code.

Blog thisHereBlog = new BlogBuilder()
     .withTitle("ihaztehcodez")
     .withURL( "ihaztehcodez.michael-lloyd-lee.me.uk")
     .build();

This does mean I now have a mini project to start. Write a JPA thingie to generate a builder.

Wednesday, 25 November 2009

Preventing multiple instances of an application from running.

This is a common question, with a very common answer - create a machine wide semaphore. The most common recommendation in Java is to use a socket. However this answer has a flaw. In a multi-user environment you do not want a machine-wide, you want a user-wide semaphore. I have seen some very complex solutions to this issue but there is a very simple answer. Use a file lock.
The common reason against using files is that they are not automatically cleaned when the application is forcible terminated (for example hitting the big red button). This is true if you use the existence of a file to determine if a previous instance is running, but there is a better option than this. Use the FileLock for a file in the users home directory. FileLocks are automatically cleaned by the OS should the application die without unlocking and can be placed in a location that will be local to the user allowing this solution to work on multi-user environment such as Windows Terminal Server.


import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import java.util.logging.Level;
import java.util.logging.Logger;

/** Prevents two instances of the application from starting at the same time.
 *
 * @author Mlk
 *
 */
public final class InstanceChecker {
    /** A singleton instance. */
    public static final InstanceChecker INSTANCE = new InstanceChecker();
    /** The file channel to be locked. */
    private FileChannel channel;
    /** The lock on the file. */
    private FileLock lock;
    /** The file to be locked. */
    private final File file = new File(new File(System.getProperty("user.home")), "/APPLICATION_NAME.lock");
    /** Logger. */
    private Logger log = Logger.getLogger(getClass().getName());

   
   
    /** ctor. */
    private InstanceChecker() {    }

    /** Is this the only instance of this application currently executing.
     *
     * @return should the application be allowed to start up.
     */
    public boolean onlyInstance() {
       
        try {
            channel = new RandomAccessFile(file, "rw").getChannel();
           
            try {
                lock = channel.tryLock();
            } catch (OverlappingFileLockException e) {
                return false;
            }
            if (lock == null) {
                return false;
            }
           
            Runtime.getRuntime().addShutdownHook(new Thread() {
                public void run() {
                    close();
                }
            });
        } catch (IOException e) {
            log.log(Level.WARNING, "Failed to lock file: " + file, e);
            return false;
        }
        return true;
    }

    /** Unlocks the file. */
    private void close() {
        try {
            if (lock != null) {
                lock.release();
            }
            if (channel != null) {
                channel.close();
            }
           
            file.delete();
        } catch (final IOException e) {
            System.err.println("Failed to unlock file!");
        }
    }
}

And you use it:
public static void main(String argv...) {
     if( !InstanceChecker.INSTANCE.onlyInstance()) {
     // Die!
  }
}

It currently lacks the inter application communication, but I think that would be easily added by also having a "ping" file that would be touched during the die section of code.

Monday, 2 November 2009

How to render HTML in Java then save this as an image

A few Java based HTML renders exist, all with different sets of drawbacks. The most common is the one built in. This is quite simple and can only render fairly basic HTML. The most interesting I know of is The Flying Saucer Project. This can render fairly complex XHTML but you will have to convert HTML before you can use it (JTindy or  may be able to help here). Taking a Swing component and creating a image is fairly simple, you just pass an BufferedImagegraphics object and pass it to the Swing components paint method. Then splat that out with ImageIO.

A big advantage to this would be that the renderer would be headless. The disadvantage is that it would not be a perfect rendering and it would lack any plugin support.

The second option requires you to start a web browser, work out where it is and then take a screen shot. Optionally you may also wish to strip out all the Firefox/IE/Opera/etc menus leaving you with just image. To get the dimensions of the web browser the simplest option would be to start it full screen. The other option would be to use something like JDICs browser component to include it as part of the Java application. It would then be able to specify where the HTML is being rendered on screen and then simply use Robot to create a screen shot of that area.

The big advantage to this is that it will give a perfect rendering (for a given browser). The two disadvantages is that it would require native code (or at least using a native component) and it could not be headless¹.


1) You could use a virtual frame buffer. But that is outside Java.