Thursday, May 27, 2010

Using Play! precompiled classes

If you want to run Play! in PROD mode, after precompiling your code, you probably noticed that Play.usePrecompiled is set to false and doesn't change. This causes your code to be compiled when the PROD server starts.
I read somewhere that in the GAE module it's set to true.

Well, what if I want to deploy my Play! application without the sources and use my precompiled classes?
This only requires setting Play.usePrecompiled to true, writing a new module for this seems too much.
I thought the plugins architecture was the way to go, setting this in the onLoad() method, but without setting usePrecompiled Play! can not invoke my plugin.

I found an acceptable hack.
One of the first thing Play! does in the init() method is invoke initStaticStuff(), this method searches for files named "play.static" in the classpath, each line in the files must be a Java class name, and Class.forName() is invoked for each such class.
This doesn't do much but I can set the usePrecompiled value to true in a static initializer block.
I use a JVM property ("usePrecompile") to control the use of the precompiled classes.
I wrote a new class
package org.oded;

import play.Play;

public class Bootstrap {
 static {
  Play.usePrecompiled = Boolean.getBoolean( "usePrecompile" ) && Play.getFile( "precompiled" ).exists();
 }
}

I added a "play.static" file to my conf directory, the file has one line "org.oded.Bootstrap".

In addition I updated my build script, the one that invokes "play precompile", also creates a jar file in myserver/lib with only the Bootstrap file in it.

This is probably not the use that was intended for this hook, but it works.

6 comments:

  1. Thanks Oded. But I'm a bit confused, what does the following snippet do?

    Boolean.getBoolean( "usePrecompile" )

    ReplyDelete
  2. If you use this hack then the code in the static initializer block will always be executed. I wanted to avoid using precompiled classes in a dev environment (which in my case sometimes has precompiled classes), so I added a JVM property to control the use of precompiled classes.

    Boolean.getBoolean() is like calling Boolean.parseBoolean(System.getProperty(...))

    So now when I run play in prod mode I run
    play start "-DusePrecompile=true"

    ReplyDelete
  3. thanks for the explanation, if it's the same, I'd prefer Boolean.parseBoolean(System.getProperty(...)) because it's self-documenting, otherwise I'd at least put a comment on it... just a matter of taste, actually...

    saludos

    sas

    ReplyDelete
  4. How come I get the Cannot init static : org.oded.Bootstrap error? Where to do need to put this Bootstramp.class

    ReplyDelete
  5. Thanks for your explanation Oded. But, I didn't understand this:
    "In addition I updated my build script, the one that invokes "play precompile", also creates a jar file in myserver/lib with only the Bootstrap file in it."

    Could you explain more detailed this step?

    Thank you

    ReplyDelete
  6. The bootstrap code is invoked before Play! has a chance to set up its classloader. Your bootstrap classes need to be available to the system classloader. To achieve that you can jar your bootstrap classes and place them in your application's "lib" directory.

    ReplyDelete