-
Notifications
You must be signed in to change notification settings - Fork 3
Highlights
The whole runtime API for Play have been migrated to Scala 2.10 allowing your applications to take part of the new great features provided by this new language release.
In the same time we have broken the dependency that was existing between the Scala version used by the Build system (sbt), and the Scala version used at runtime. This way, it makes it easier to build and test Play on experimental or unstable branches of the Scala language.
One of the greatest feature provided by Scala 2.10 is the new standard scala.concurrent.Future
library for managing asynchronous code in Scala. Play is now based itself on this API, and its great asynchronouns HTTP and streaming features are now compatible directly with any other library using the same API.
It makes it even simpler to use Play with Akka, or any upcoming asynchronous datastore driver that will use thsi new API.
In the same time, we worked to simplify the execution context model, and by providing an easy way to choose for each part of your application, the underlying ExecutionContext
used to run your code.
The Play project has been splitted on many subprojects, allowing you to select the minial set of dependency needed for your project.
You have to select the exact set of optional dependencies your application need, in the list of:
-
jdbc
: The JDBC connection pool and the theplay.api.db
API. -
anorm
: The Anorm component. -
javaCore
: The core Java API. -
javaJdbc
: The Java database API. -
javaEbean
: The Ebean plugin for Java. -
javaJpa
: The JPA plugin for Java. -
filters
: A set of build-in filters for Play (such as the CSRF filter)
The play
core project has now a very limited set of external dependencies and can be used as a minimal asynchronous, high performance HTTP server without the other components.
To allow, to compose and reuse components in your own projects further, Play 2.1 supports sub-Router composition.
For example, a sub project can define it's own router component, using its own namespace, such as:
In conf/my.subproject.routes
GET / my.subproject.controllers.Application.index
And then, you can integrate this component into your main application, by wiring the Router, such as:
# The home page
GET / controllers.Application.index
# Include a sub-project
-> /my-subproject my.subproject.Routes
# The static assets
GET /public/*file controllers.Assets.at(file)
In the configuration, at runtime a call to the /my-subproject
URL will eventually invoke the my.subproject.controllers.Application.index
Action.
In Play 2.0, the HTTP context was lost during the asynchonous callback, since these code fragment are run on different thread than the original one handling the HTTP request.
Consider:
public static Result index() {
return async(
aServiceSomewhere.getData().map(new Function<String,Result>(data) {
// Ouch! You try to access the request data in an asynchronous callback
String user = session().get("user");
return ok("Here is the result " + user + ": " + data);
})
);
}
This code wasn't working this way. For really good reason, if you think about the underlying asynchronous architectire, but yet it was really surprising for Java developers.
We eventually found a way to solve this problem an to propagate the Http.Context
over a stack spanning several threads, so this code is now working this way.
While running asynchronous code over mutable data structures, chances are right that you hit some race conditions if you don't synchronize properly your code. Because Play promote highly asynchronous and non-blocking code, and because Java data structure are mistly mutable and not thread-safe, it is the responsability of your code to deal with the synchronization issues.
Consider:
public static Result index() {
final HashMap<String,Integer> result = new HashMap<String,Integer>();
aService.doSomethingAsync().map(new Function<String,String>(key) {
Integer i = result.get(key);
if(i != null) {
result.set(key, i++);
}
return key;
});
aService.doSomethingElse().map(new Function<String,String>(key) {
result.remove(key);
return null;
});
...
}
In this code, chances are really high to hit a race condition if the 2 callbacks are run in the same time on 2 different threads, while accessing each to the share result
HashMap. And the consequence will be probably some pseudo-deadlock in your application because of the implementation of the underlying Java HashMap.
To avoid any of these problems, we decided to manage the callback execution synchronization at the framework level. Play 2.1 will never run concurrently 2 callbacks for the same Http.Context
. In this context, all callback execution will be run sequencially (while there is no guarantees that they will run on the same thread).
By default Play binds URLs to controller methods statically, that is, no Controller instances are created by the framework and the appropriate static method is invoked depending on the given URL. In certain situations, however, you may want to manage controller creation and that’s when the new routing syntax comes handy.
Route definitions starting with @ will be managed by the Global::getControllerInstance
method, so given the following route definition:
GET / @controllers.Application.index()
Play will invoke the getControllerInstance
methid which in return will provide an instance of controllers.Application
(by default this is happening via the default constructor). Therefore, if you want to manage controller class instantiation either via a dependency injection framework or manually you can do so by overriding getControllerInstance in your application’s Global class.
As this example demonstrates it, it allows to wire any dependency injection framework such as Spring into your Play application.
The new Scala JSON API provide great features such as transformation and validation of JSON tree.
http://mandubian.com/2012/09/08/unveiling-play-2-dot-1-json-api-part1-jspath-reads-combinators/
(TODO: integrate into the main documentation)
Play 2.1 provides a new and really powerful filter API allowing to intercept each part of the HTTP request or response, in a fully non-blocking way.
For that, we introduced a new new simpler type replacing the old Action[A]
type, called EssentialAction
which is defined as:
RequestHeader => Iteratee[Array[Byte], Result]
As a result, a filter is simply defined as:
EssentialAction => EssentialAction
Note: The old
Action[A]
type is still available for compatibility.
You can read further about this new action type.
(TODO: Integrate this?)
The filters
project that is part of the standard Play distribution contain a set of standard filter, such as the CSRF
providing automatic token management against the CSRF security issue.
In play 2.0 the default behavior for Javascript was to use google closure's commonJS module support. In 2.1 this was changed to use requireJS instead.
What this means in practice is that by default Play will only minify and combine files in stage, dist, start modes only. In dev mode Play will resolve dependencies client side.
If you wish to use this feature, you will need to add your modules to the settings block of your build file:
requireJs := "main.js"
More information about this feature can be found on the RequireJS documentation page.