Showing posts with label play. Show all posts
Showing posts with label play. Show all posts

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("play.id", ""));
        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)

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.

Sunday, March 21, 2010

Howto use Play! + Spring + your own properties file

For those of you who don't know Play!, Play! is a framework for developing Web applications in Java, without the adhering to the JEE specifications. It makes many things easier.

For example, Play! has a Spring integration module for effortless integration of your application with Spring.



Today I added my own properties file to my Spring-powered Play! app.

It sounds very simple, just add the following lines to your
application-context.xml:

   


and use it in your beans:

   ${myapp.somekey}


However, when you run your application you get the error:
Invalid bean definition with name 'a' defined in resource loaded
through SAX InputSource: Could not resolve placeholder
'myapp.somekey'
.

I spent some time trying to figure this out. Urrrghhhh.

Finally, I understood why this happens and how to avoid it.


The Play! Spring module uses a GenericApplicationContext and
problematically adds a PropertyPlaceholderConfigurer to it, allowing
you to substitute place holders with values in your application.conf
file. (I am not sure this feature is documented anywhere)

Now, when Spring invokes
AbstractApplicationContext.invokeBeanFactoryPostProcessors() it
invokes Play's PropertyPlaceholderConfigurer, which tries to convert $
{myapp.somekey}
as well.
Since it can't find ${myapp.somekey} in application.conf the exception
is thrown.

The way to "fool" the PropertyPlaceholderConfigurer Play! adds is to
override your application's place holder prefix and suffix.
This can be done in your application-context.xml file, for example:

   
   #[
   ]



   #[myapp.somekey]

Now your application can read properties from any properties file you
want.