The Cloud Foundry Blog

Cloud Foundry Now Supports Play!

Cloud Foundry now supports Play 2.0 as a first-class framework. Play is a lightweight, stateless, web-friendly framework for Java and Scala. Developers can leverage this event-driven non-blocking IO architecture to build highly scalable applications. Play 1.0 applications were previously deployable to Cloud Foundry as WAR files. Play 2.0, which doesn’t have built-in support for WAR files, can now be deployed to CloudFoundry.com and take advantage of being a fully supported framework that includes auto-reconfiguration, simplified service connections, and automatic database management. Play developers, welcome to Cloud Foundry!

Getting Started with Play 2.0

First, we will need to install or update the Cloud Foundry command line tool, VMC, to the latest version by using the following command:

gem install vmc 

We can verify that we have the right version using:

vmc -v 

which should show the version to be 0.3.18 or higher. Now let’s get started with the Java zentasks sample found in the Play 2.0 distribution. We’ll run the “play dist” command which will compile our code, retrieve all the required dependencies and create a self-contained binary that can be uploaded to Cloud Foundry.

dev$: cd play-2.0.1/samples/java/zentasks
zentasks$: play clean dist
[info] Loading project definition from /Users/jencompgeek/development/resources/play-2.0.1/samples/java/zentasks/project
[info] Set current project to zentask (in build file:/Users/jencompgeek/development/resources/play-2.0.1/samples/java/zentasks/)
[success] Total time: 0 s, completed May 15, 2012 2:27:29 PM
[info] Updating {file:/Users/jencompgeek/development/resources/play-2.0.1/samples/java/zentasks/}zentask...
[info] Done updating.
[info] Compiling 10 Scala sources and 9 Java sources to /Users/jencompgeek/development/resources/play-2.0.1/samples/java/zentasks/target/scala-2.9.1/classes...
[warn] Note: Some input files use unchecked or unsafe operations.
[warn] Note: Recompile with -Xlint:unchecked for details.
[info] Packaging /Users/jencompgeek/development/resources/play-2.0.1/samples/java/zentasks/target/scala-2.9.1/zentask_2.9.1-1.0.jar ...
[info] Done packaging.

Your application is ready in /Users/jencompgeek/development/resources/play-2.0.1/samples/java/zentasks/dist/zentask-1.0.zip

Now we can deploy the application to Cloud Foundry with the VMC push command:

zentasks$: vmc push --path=dist/zentask-1.0.zip
Application Name: zentasks
Detected a Play Framework Application, is this correct? [Yn]:
Application Deployed URL [zentasks.cloudfoundry.com]:
Memory reservation (128M, 256M, 512M, 1G, 2G) [256M]:
How many instances? [1]:
Create services to bind to 'zentasks'? [yN]: y
1: mongodb
2: mysql
3: postgresql
4: rabbitmq
5: redis
What kind of service?: 3
Specify the name of the service [postgresql-38199]: tasks-db
Create another? [yN]:
Would you like to save this configuration? [yN]: y
Manifest written to manifest.yml.
Creating Application: OK
Creating Service [tasks-db]: OK
Binding Service [tasks-db]: OK
Uploading Application:
  Checking for available resources: OK
  Processing resources: OK
  Packing application: OK
  Uploading (186K): OK
Push Status: OK
Staging Application 'zentasks': OK
Starting Application 'zentasks': OK

Looks like zentasks deployed successfully. Let’s check the logs:

zentasks$: vmc logs zentasks
====> logs/stdout.log <====

Auto-reconfiguring default
Enabling JPA auto-reconfiguration
Play server process ID is 13269
[warn] play - Plugin [play.db.jpa.JPAPlugin] is disabled
[info] play - database [default] connected at jdbc:postgresql://172.31.244.70:5432/dd2c9bc5b72134998adcfe4dcfa6660f4
[info] play - Application started (Prod)
[info] play - Listening for HTTP on port 59907...

Our Play 2.0 application is up and running on Cloud Foundry in 2 simple steps, no modification required!

Like most Play applications, zentasks contains database evolutions. Cloud Foundry automatically applied these evolutions to the database on application start. But how was the app able to make use of the PostgreSQL service we provisioned and bound to the application during deployment? If we look at the application.conf file, we see that the application is configured to use an in-memory database:

 
db.default.driver=org.h2.Driver db.default.url="jdbc:h2:mem:play"

Cloud Foundry actually used a mechanism called auto-reconfiguration to automatically connect the Play application to the relational database service. If a single database configuration is found in the Play configuration (for example, “default” from above) and a single database service instance is bound to the application, Cloud Foundry will automatically override the connection properties in the configuration to point to the PostgreSQL or MySQL service bound to the application. This is a great way to get simple apps up and running quickly. However, it is quite possible that your application will contain SQL that is specific to the type of database you are using. For example, several of the samples that come with Play make use of sequences in evolution scripts. This, of course, works with the in-memory database and will also work on PostgreSQL, but it will not work on MySQL. In these cases, or if your app needs to bind to multiple services, you may choose to avoid auto-reconfiguration and explicitly specify the service connection properties.

Connecting to Cloud Foundry Services

As always, Cloud Foundry provides all of your service connection information to your application in JSON format through the

VCAP_SERVICES environment variable. However, connection information is also available as series of properties you can use in your Play configuration. Here is an example of connecting to a PostgreSQL service named “tasks-db” from within an application.conf file:

db.default.driver=${?cloud.services.tasks-db.connection.driver} 
db.default.url=${?cloud.services.tasks-db.connection.url} 
db.default.password=${?cloud.services.tasks-db.connection.password} 
db.default.user=${?cloud.services.tasks-db.connection.username}

This information is available for all types of services, including NoSQL and messaging services. Also, if there is only a single service of a type (e.g. postgresql), you can refer to that service only by type instead of specifically by name, as exemplified below:

db.default.driver=${?cloud.services.postgresql.connection.driver} 
db.default.url=${?cloud.services.postgresql.connection.url} 
db.default.password=${?cloud.services.postgresql.connection.password} 
db.default.user=${?cloud.services.postgresql.connection.username} 

We recommend keeping these properties in a separate file (for example “cloud.conf”) and then including them only when building a distribution for Cloud Foundry. You can specify an alternative config file to “play dist” by using “-Dconfig.file”.

Opting Out of Auto-Reconfiguration

There may be situations in which you would like to opt out of auto-reconfiguration. For example, you may have an in-memory database that should not be bound to a Cloud Foundry service. If you use the properties referenced above, you will automatically be opted-out. To explicitly opt out, include a file named “

cloudfoundry.properties” in your application’s conf directory, and add the entry “autoconfig=false“.

Debugging Your Play Application

If you are using a local Cloud Foundry setup, you can remotely debug your Play applications. Simply use the flag “--debug” when doing a “vmc push” or “vmc start“. You can then run “vmc instances” to get the debug host and port information:

zentasks$: vmc instances
+-------+---------+--------------------+-----------------+------------+
| Index | State   | Start Time         | Debug IP        | Debug Port |
+-------+---------+--------------------+-----------------+------------+
| 0     | RUNNING | 05/15/2012 05:50PM | 192.168.193.193 | 59845      |
+-------+---------+--------------------+-----------------+------------+

Just use the displayed debug IP and port in the remote debugger in your favorite IDE and start debugging!

Conclusion

We look forward to seeing your Play applications on Cloud Foundry. Please feel free to send us feedback or submit a pull request to help us improve our support for the Play Framework. Now get started building those apps!

- Jennifer Hickey The Cloud Foundry Team
Don’t have a Cloud Foundry account yet?  Sign up for free today

This entry was posted in Announcement, CloudFoundry, Media. Bookmark the permalink.

15 Responses to Cloud Foundry Now Supports Play!

  1. Mike says:

    Thanks for sharing this. It’s very helpful. Though I needed to change the evolution script and change User to another name as this is a reserved word in PostgreSQL. Changes were made also on the code of course. Otherwise an error will be thrown when deploying it to Cloud Foundry. HTH.

  2. Mike says:

    …also Global.scala failed to populate the tables due to : org.postgresql.util.PSQLException: ERROR: syntax error at or near “value”..still figuring out why

    • Jennifer Hickey says:

      Thanks for posting. I was using the Java Zentasks sample in this post, but I do see the errors you are referring to when I try the Scala Zentasks sample. I’m looking into this as well and will report back, but in the meantime it’s worth noting that if a failure occurs applying evolutions, it won’t be visible in the logs right now. This is an issue that has been reported to the Play team. To see evolution errors, use the “vmc tunnel” command to inspect the postgres database using psql and run “select last_problem from play_evolutions”. This may give you more insight into the issue.

      • Jennifer Hickey says:

        Got it working. Besides changing the table name from “user” to “account” (and updating the model classes accordingly), I had to change the following:

        Project.scala: create
        Change “select next value for project_seq” to “select nextval(‘project_seq’)”

        Do the same in Task.scala:create

  3. Steinar Rune Eriksen says:

    I am trying to deploy a Play 2.0.1 app to my local Micro Cloud Foundry on my Mac OS, but it seems unable to determine that this is a play application

    user$ vmc target http://api.sparksoft.cloudfoundry.me
    Successfully targeted to [http://api.sparksoft.cloudfoundry.me]

    user$ vmc push –path=dist/sparksoft-1.0-SNAPSHOT.zip
    Application Name: Sparksoft
    [WARNING] Can’t determine the Application Type.
    Select Application Type:

    It does not display any application type/list. Have I installed the micro cloud foundry incorrectly do you think? The console seems to be OK, saying that services are OK.

    VMC version 0.3.18 and Play 2.0.1

    • Jennifer Hickey says:

      Micro Cloud hasn’t been updated to include the Play support yet. In the meantime, you could consider using dev_setup to install the latest source code on your own Ubuntu VM.

  4. Mayer says:

    I have got some evolutions to add to database. By start of application I get error: play – Run with -DapplyEvolutions.default=true if you want to run them automatically (be careful)
    How I can do this?

    • Jennifer Hickey says:

      Is this happening locally or on Cloud Foundry? Cloud Foundry should be running evolutions for you automatically….

      • Mayer says:

        I try to deploy my application on Cloud Foundry. I solved this problem by adding “applyEvolutions.default=true” to application.conf. But I have now another problem:
        ====> /logs/stderr.log <====

        java.lang.Exception: there should be a database plugin registered at this point but looks like it's not available, so evolution won't work. Please make sure you register a db plugin properly
        at play.api.db.evolutions.EvolutionsPlugin$$anonfun$15.apply(Evolutions.scala:409)
        at play.api.db.evolutions.EvolutionsPlugin$$anonfun$15.apply(Evolutions.scala:409)
        at scala.Option.getOrElse(Option.scala:108)
        at play.api.db.evolutions.EvolutionsPlugin.onStart(Evolutions.scala:409)
        at play.api.Play$$anonfun$start$1.apply(Play.scala:60)
        at play.api.Play$$anonfun$start$1.apply(Play.scala:60)
        at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
        at scala.collection.immutable.List.foreach(List.scala:45)
        at play.api.Play$.start(Play.scala:60)
        at play.core.StaticApplication.(ApplicationProvider.scala:51)
        at play.core.server.NettyServer$.createServer(NettyServer.scala:132)
        at play.core.server.NettyServer$$anonfun$main$5.apply(NettyServer.scala:153)
        at play.core.server.NettyServer$$anonfun$main$5.apply(NettyServer.scala:152)
        at scala.Option.map(Option.scala:133)
        at play.core.server.NettyServer$.main(NettyServer.scala:152)
        at play.core.server.NettyServer.main(NettyServer.scala)
        at org.cloudfoundry.reconfiguration.play.Bootstrap.main(Bootstrap.java:19)

        ====> /logs/stdout.log <====

        No database found in Play configuration. Skipping auto-reconfiguration.
        Play server process ID is 16231
        [warn] play – Plugin [org.cloudfoundry.reconfiguration.play.JPAPlugin] is disabled
        Oops, cannot start the server.

        • Mayer says:

          Now I have another error:

          [error] application –

          ! @6b4dc6dde – Internal server error, for request [GET /] ->

          play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[UnsupportedClassVersionError: controllers/routes : Unsupported major.minor version 51.0]]
          at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:134) [play.play_2.9.1-2.0.1.jar:2.0.1]
          at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:115) [play.play_2.9.1-2.0.1.jar:2.0.1]
          at akka.actor.Actor$class.apply(Actor.scala:311) [com.typesafe.akka.akka-actor-2.0.1.jar:2.0.1]
          at play.core.ActionInvoker.apply(Invoker.scala:113) [play.play_2.9.1-2.0.1.jar:2.0.1]
          at akka.actor.ActorCell.invoke(ActorCell.scala:619) [com.typesafe.akka.akka-actor-2.0.1.jar:2.0.1]
          at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:196) [com.typesafe.akka.akka-actor-2.0.1.jar:2.0.1]
          Caused by: java.lang.UnsupportedClassVersionError: controllers/routes : Unsupported major.minor version 51.0
          at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.6.0_24]
          at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632) ~[na:1.6.0_24]
          at java.lang.ClassLoader.defineClass(ClassLoader.java:616) ~[na:1.6.0_24]
          at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) ~[na:1.6.0_24]
          at java.net.URLClassLoader.defineClass(URLClassLoader.java:283) ~[na:1.6.0_24]
          at java.net.URLClassLoader.access$000(URLClassLoader.java:58)~[na:1.6.0_24]

          • Jennifer Hickey says:

            Are you definitely pushing the zip file created from the dist command (vmc push –path=dist/foo.zip)? You shouldn’t need to set the property for applying evolutions yourself. Also, did you compile with Java 7? If so, you need to specify –runtime=java7 to “vmc push”. The default runtime for Play apps is Java 6. If these suggestions don’t help, I’d recommend posting in Stack Overflow so our support engineers can take a closer look.

  5. Mayer says:

    @Jennifer Hickey
    Thank you for your hint!

    Best Regards
    Djon

  6. Emilian Ionascu says:

    Error: Could not find or load main class org.cloudfoundry.reconfiguration.play.Bootstrap

    I get this error when trying to use “vmc push” for a play 2.1.1 + scala 2.10.0 app into a micro instance. I’ve read that this could be solved by using an auto-reconfigure jar (0.6.5 – said the post author) but I wasn’t able to find that specific version of the jar nor other versions. Help please!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>