Thursday, July 8, 2010

Running Play! framework JPA from a command line process

If you are using the Play! framework and wanted to run a command line process that uses the Play! JPA enhancements this post is for you.
It requires some classloader magic and is based on reading the source code of Play 1.0.x, I am not sure if this will be supported in future versions.

You need your Main class to prepare the Play! framework classes, set the classloader and load your "real" Main class using the Play! classloader.
This is how it's done:

public class LoaderMain
 public static void main( String[] args ) throws Exception
        File root = new File(System.getProperty("application.path"));
        Play.init(root, System.getProperty("", ""));
        Thread.currentThread().setContextClassLoader( Play.classloader );
        Class c = Play.classloader.loadClass( "com.incapsula.batch.PlayLoaderMain" );
        Method m = c.getMethod( "run" );
        m.invoke( c.newInstance() );

Now since you are not invoking web services you need to execute the framework methods by yourself, e.g. initializing the plugins and openning a JPA transaction.
You'll have to get yourself familiar with the Play! framework source code for any dependencies your process has on the Play! frameowrk.

public class PlayLoaderMain
 public void run() throws Exception
  new DBPlugin().onApplicationStart();
  new JPAPlugin().onApplicationStart();

  JPAPlugin.startTx( true );
  Fixtures.load( "initial-data.yml" );
  System.out.println( User.findAll() );
  JPAPlugin.closeTx( false );

There are a few things to notice:
  • You need the Play jars in your classpath (play.jar, framework/lib jar files and module/lib jar files for every module you are using)
  • You need to point the "application.path" JVM property to your Play application
  • You need to initialize different Play! plugins if you need them (e.g. if you are using the Play! templates in your process you also need to initialize the MessagesPlugin)

1 comment:

  1. Sadly doesn't work in Play 1.2.5 ... I cannot use model's save() method. Is there a fix?