Tuesday, January 8, 2013

Updated SSH Deployment module for Play 1.2.x

I just pushed a new version of my SSH deployment module to github. The plugin should now be much easier to use with Amazon EC2 instances as you can define the key file in a simple argument (application.conf or on command line).

Friday, December 28, 2012

Using custom models in routes in Play framework Java 2.x, aka PathBindable.

If you want to reduce clutter in your controllers you can use PathBindables to automatically convert URL parameters to your model objects or other custom objects. For example you can get rid of the code that takes an id, looks up the user in a database and checks for null etc by wrapping into a custom PathBindable implementation. This will also make it easier to reuse code among your controllers.

You will need to do 3 things to get this to work,

1. Create a controller and action, such as
public static userName(User user)
{
   return ok(user.getName());
}

Note that user is always non null and is safe to use. An exception is thrown internally if the lookup fails and Play will return a bad request response to the client.

2. Create a route, such as
GET /user/:user   MyController.userName(user : models.User)

Here we create an actual callable URL, for example, /user/124. In this example we use the id in the route but it can be anything that you can map to your model, for example unique email addresses.

3. Implement the PathBindable interface

You can add the PathBindable code to your existing model,

package models;

import javax.persistence.Entity;
import javax.persistence.Id;

import play.Logger;
import play.db.ebean.Model;
import play.db.ebean.Model.Finder;
import play.mvc.PathBindable;

@Entity
public class User extends Model implements PathBindable
{
    @Id
    Long id;

    String name;

    public String getName()
    {
        return name;
    }

    @Override
    public User bind(String key, String id)
    {
        // key is "user"
        // id is the ":user" part of the route, i.e. 1 if you have /user/1
        User user = find.byId(new Long(id));
        if (user == null)
            throw new IllegalArgumentException("User not found");
        return user;
    }

    @Override
    public String javascriptUnbind()
    {
        return null;
    }

    @Override
    public String unbind(String arg0)
    {
        return name;
    }

    public static Finder find = new Finder(Long.class, User.class);
}
References, https://github.com/playframework/Play20/blob/master/framework/src/play/src/main/java/play/mvc/PathBindable.java http://julien.richard-foy.fr/blog/2012/04/09/how-to-implement-a-custom-pathbindable-with-play-2/

Friday, November 16, 2012

Dojo strikes back

Dojo is nice and you can do nice things quickly with it once you have learned all of it's oddities and strange behaviour. Today I ran into this really crappy thing, dijit.form.Checkbox.getValue() returns either "on" if it is checked or false if it isn't! WTF

// rant over...

Sunday, November 11, 2012

SSH Deployment module for Play 1.2.x released!

This modules simplifies deployment of Play 1.2.x application instances to Linux servers. Changes are pushed to servers using rsync and can be started, stopped and restarted over SSH. Combining this plugin with SSH keys you get a really easy way of deploying your code to testing instances and to production. It also works well in continuous integration setups.

Here is some of the copy pasted docs I wrote (for full docs, go here),


What it does

Easily deploy your application to Linux boxes using SSH and Rsync. You can deploy the same application to multiple machines, for example pushing to a test environment or multiple production backend nodes.

Usage

Push changes to server

    play deploy:update

Start, stop & restart your play application

    play deploy:start
    play deploy:stop
    play deploy:restart

The module supports command line arguments for overriding any of the parameters, you can also specify which instance to use (deploy.INSTANCE_NAME.host=10.0.0.1 etc). For full docs see, https://github.com/nylund/play-deploy/blob/master/documentation/manual/home.textile


Setup

Add this to your application.conf:

    deploy.default.host=IP_or_hostname
    deploy.default.login=remote_user_name
    deploy.default.port=remote_port
    deploy.default.path=remote_directory, for example /home/user/app-deploy/test1
    deploy.default.play_path=remote_path_to_play_binary, for example /home/user/app-deploy/play-1.2.5/play

Add this to your dependencies.yml:

     require:
        - play
        - deploy -> deploy 0.1
     repositories:
        - deploy:
            type: http
            artifact: http://albin.abo.fi/~ninylund/play_modules/deploy-0.1.zip
            contains:
                - deploy -> *



Get the module, http://www.playmodules.net/module/34
Check the code at Github, https://github.com/nylund/play-deploy

Sunday, November 14, 2010

Simple Boost Spirit example.

Here's an example of a parser for a really simple domain specific language (DSL) created with Boost's Spirit framework.

Download the full source code

The parser accepts the following input:
new order
*(buy|sell amount stock_name price)
end order

Here are a few examples:
new order
buy 10 ABC 2.50
sell 20 QWE 5.00
end order

new order
buy 10 ABC 2.50
buy 10 ABC 2.50
buy 10 ABC 2.50
sell 20 QWE 5.00
end order

As you can see the input the parser accepts is really simple and I could have probably saved lots of time by writing the parser manually without using any framework. If you download and look at the source code you see it's fairly easy to extend the parser to take much more complicated input.

Wednesday, May 26, 2010

JUnit reporter for Unitest++

The C++ testing framework Unittest++ includes a XML reporter but it is not directly usable with most continuous integration (CI) servers such as Hudson and TeamCity. I wrote a XML reporter for Unittest++ that uses the same format as JUnit, the reporter will split test suites into different files and they can be directly used by for example the junitreport task in ant or in your CI build. Download the header and cpp files below and add them to your Unittest++ build.

This is how you normally use Unittest++'s built-in XML reporter:
std::ofstream f("test-report.xml");
UnitTest::XmlTestReporter reporter(f);
UnitTest::TestRunner runner(reporter);
return runner.RunTestsIf(UnitTest::Test::GetTestList(), NULL, UnitTest::True(), 0);
Simply replace it with the following,
std::string f = "TESTS-";
UnitTest::JUnitXmlTestReporter reporter(f);
UnitTest::TestRunner runner(reporter);
return runner.RunTestsIf(UnitTest::Test::GetTestList(), NULL, UnitTest::True(), 0);
Note that the JUnit reporter does not take a complete filename because the JUnit format requires that different test suites are split into different files. The output files are named TESTS-suitename.xml.

Download
JUnitXMLTestReporter.h
JUnitXMLTestReporter.cpp

Wednesday, February 17, 2010

Testing blogging from my iPhone, this seems to work ok. Yay.
Keep an eye on this blog if you are interested in continous integration methods for improving your software team. I am preparing a post on the subject....