Custom querystring parameters in Play

Usually, actions in Play does not receive complex parameters. If you take a look in your project, probably you will see just simple parameters. Integers, Longs etc. Yesterday, trying to find questions to answer in the Play forum, I found one about receiving a java.util.Date parameter in the controller’s action.

    public static Result findByDate(Date date){
    	System.out.println(date);
    	return ok();
    }

When you configure this action in your routes file, an error will be printed in your console.

    No QueryString binder found for type java.util.Date. Try to implement an implicit     QueryStringBindable for this type

By default, Play does not know how to transform a querystring parameter into a Date object. That’s why we have the QueryStringBindable interface. This is like a formatter, but to querystring parameters. The first thing we need to do is to implement our converter.

	public class DateParameter implements QueryStringBindable<DateParameter>{

		private SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
		private Date value;

		@Override
		public Option<DateParameter> bind(String key,
				Map<String, String[]> parameters) {
			if(parameters.containsKey(key)){
				String date = parameters.get(key)[0];
				try {
					this.value = formatter.parse(date);
				} catch (ParseException e) {
					throw new IllegalArgumentException(e);
				}
				return Option.<DateParameter>Some(this);
			}
			return Option.<DateParameter>None();
		}

		public Date getValue() {
			return value;
		}

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

		@Override
		public String unbind(String key) {
			return "key="+formatter.format(value);
		}

	}

Now you need to receive this object as a parameter in your action and change your routes file as well.

    public static Result findByDate(DateParameter date){
    	System.out.println(date.getValue());
    	return ok();
    }

 GET /findByDate	controllers.NewsController.findByDate(date:binders.DateParameter)

A last thing here. In our action, we invoke the getValue method to recover the parsed date. This is why you should keep state in your QueryStringBindable object. Every time a request is made to a method receiving a DateParameter, Play will instantiate this object.

If you have or had this necessity, you can use this interface or the PathBindable, for the cases when the parameter is mixed in the url.

Advertisements

Customizing messages and evolutions in Play, beyond the documentation

Play has a very good forum. Every day a lot of doubts are posted and answered. As a developer who is using Play in almost every project, I follow the forum and I try to help answering as many as questions as I can. Today I bring to the blog two interesting questions that were posted there.

The first question was about how to customize the conversion error in Play. For example, if you have a int field in your class and the user submits a string, for instance, “two”, Play will use a formatter which is responsible for this conversion. If the value is not possible to be converted, a message will be returned. The default message is “Invalid value”.  In order to customize this message you have to override a key defined in Play.

    error.invalid.java.lang.Integer = Value is not a integer

But how to find this key? That is the good part!. It is not explained in the documentation and because of the question, I went to the source code and I found the file messages.default which has all pre defined errors keys in Play.

The second question was about how to run evolutions outside of the web application scope. This one was quite interesting, because I already had this wish and I was not capable to find the solution. Reading the forum, I saw a question about this subject and someone answered with the class OfflineEvolutions. So I gave a try and the code worked like a charm!

   object RunMigrations extends App{

      OfflineEvolutions.applyScript(new File("."),this.getClass().getClassLoader(), "default")
   }

Now, in case you have this necessity, you can run your evolutions in a separated task in sbt, for example. Another case is to run the evolutions every time you need to run a integration test. Again, this is not a case explained in the documentation, but based in a question posted in the forum, I had to find a answer and learned a little more.

Once more, thanks for reading!

 

Changing the registration process in SecureSocial

This is a quick post about a customization that I had to write for a use case with Secure Social. Secure Social, at least in its 2.1.x version, has a very fixed flow in order to register a new user. First you need to register a new email, after that, an email is sent to the user with a generated token embedded in a link. The user has to follow this link in order to finish the registration process, filling the form with a few fields.

At one of my current projects, I don’t have the necessity to send the email with the generated token, the only need is to redirect the user to the registration form. To accomplish this task, we have to create a controller with a custom handleStartSignup. Basically, we need to copy the method from the Registration controller of Secure Social and delete the line which sends the email.

    import _root_.java.util.UUID
    import play.api.mvc.{RequestHeader, Result, Action, Controller}
    import play.api.data._
    import play.api.data.Forms._
    import play.api.data.validation.Constraints._
    import play.api.Play
    import securesocial.core.providers.UsernamePasswordProvider
    import securesocial.core._
    import com.typesafe.plugin._
    import Play.current
    import securesocial.core.providers.utils._
    import org.joda.time.DateTime
    import play.api.i18n.Messages
    import securesocial.core.providers.Token
    import scala.Some
    import securesocial.core.IdentityId
    import scala.language.reflectiveCalls
    import securesocial.controllers.Registration

    object CustomRegistration extends Controller {

      def handleStartSignUp = Action { implicit request =>
        if (Registration.registrationEnabled) {
          Registration.startForm.bindFromRequest.fold(
            implicit errors => {
              BadRequest(use[securesocial.controllers.TemplatesPlugin].getStartSignUpPage)
            },
            email => {
              // check if there is already an account for this email address
              UserService.findByEmailAndProvider(email, UsernamePasswordProvider.UsernamePassword) match {
                case Some(user) => {
                  // user signed up already, send an email offering to login/recover password
                  Mailer.sendAlreadyRegisteredEmail(user)
                  Redirect(Registration.onHandleStartSignUpGoTo).flashing(Registration.Success -> Messages(Registration.ThankYouCheckEmail), Registration.Email -> email)
                }
                case None => {
                  val token = createToken(email, isSignUp = true)
                  //original line
                  //Mailer.sendSignUpEmail(email, token._1)
                  Redirect(s"/signup/${token._1}")
                }
              }
            })
        } else NotFound(views.html.defaultpages.notFound.render(request, None))
      }

      private def createToken(email: String, isSignUp: Boolean): (String, Token) = {
        val uuid = UUID.randomUUID().toString
        val now = DateTime.now

        val token = Token(
          uuid, email,
          now,
          now.plusMinutes(Registration.TokenDuration),
          isSignUp = isSignUp)
        UserService.save(token)
        (uuid, token)
      }

    }

The better approach would be to write a custom plugin which could handle these steps of the registration process, but Secure Social does not provide this customization. Now, you need to change your file of routes to use the new method.

   //rest of your file
   POST  /signup br.com.celerate.security.CustomRegistration.handleStartSignUp

If you try this code, you will notice that was generated a new problem in your project. The default startSignupView page of SecureSocial uses the old method Registration.handleStartSignUp, we need to customize this view as well. It is not hard, just follow the steps described in the original site. You have to implement all methods from the TemplatesPlugin trait, but we only need to customize the startSignUp,  so let’s keep the others. In order to make this job easier, use as an example the DefaultTemplatesPlugin class.  To do not create the view from scratch, just copy the code from the original, again.

As you can see, it was little bit hard to customize this behavior. Remember that you always can use the source code of the lib as a path to discover something. Of course, it’s easier to start for the documentation and forums but, if you don’t find, don’t stop and try to take a look in the source code. Secure Social has a code that is not hard to understand. See you!.

Login/Password authentication in Secure Social

In another post I wrote about how to configure secure social to log in using a
social network. In this one, I am gonna walk through another common scenario,
setup a login/password based authentication. You need to understand a few things to put
everything in order. Let’s go!

If you don’t know anything about secure social, click in the link above and
spend a few minutes to read the other post about how to setup secure social :).
The first thing you have to change is the provider used in the configuration file,
usually called securesocial.conf. You need to use the userpass
entry in order to configure some aspects of your authentication.

    userpass {
    	withUserNameSupport=false
    	sendWelcomeEmail=false
    	enableGravatarSupport=true
    	signupSkipLogin=true
    	tokenDuration=60
    	tokenDeleteInterval=5
    	minimumPasswordLength=8
    	enableTokenJob=true
    	hasher=bcrypt
    }

The most strange key, at least for me, is the first one. The withUserNameSupport tells to Secure Social to use the user name instead of the email as the login for the
application. Maybe the keys about tokens are not clear right now, but wait a little and everything will be solved.

Another part that must be changed is the plugin’s file. We need to change the provider
to use the UserPass provider instead of some social provider.

    1500:com.typesafe.plugin.CommonsMailerPlugin
    9994:securesocial.core.DefaultAuthenticatorStore
    9995:securesocial.core.DefaultIdGenerator
    9996:securesocial.core.providers.utils.DefaultPasswordValidator
    9997:securesocial.controllers.DefaultTemplatesPlugin
    9998:br.com.celerate.security.CelerateUserService
    9999:securesocial.core.providers.utils.BCryptPasswordHasher
    10001:securesocial.core.providers.UsernamePasswordProvider

We used the UsernamePasswordProvider class to handle the authentication
part for us and we had to configure other plugins which do other things. For example,
we need to hash the password(BCryptPasswordHasher), maybe send a email(CommonsMailerPlugin) and validate the password sent by the user(DefaultPasswordValidator). These plugins are not necessary when you are dealing with social authentication.

Maybe you have noticed that there is a plugin which is not from SecureSocial. It is
the CelerateUserService. You need to create a class to handle the process
of create a new user in the system, verify the existence of a user in your system, etc.
We created this same class in the other post, but now it will be a little bit different.

    public class CelerateUserService extends BaseUserService {

    	public CelerateUserService(Application application) {
    		super(application);
    		// TODO Auto-generated constructor stub
    	}

    	@Override
    	public Identity doSave(Identity user) {
    		final SystemUser systemUser = new SystemUser();
    		newSystemUser(user, systemUser);
    		Identity foundUser = doFind(user.identityId());
    		if (foundUser == null) {
    			return TransactionHelper.run(new Function0<WrapIdentity>() {

    				@Override
    				public WrapIdentity apply() throws Throwable {
    					JPA.em().persist(systemUser);
    					return new WrapIdentity(systemUser);
    				}
    			});
    		}
    		return foundUser;
    	}

    	private void newSystemUser(Identity user, final SystemUser systemUser) {
    		systemUser.setEmail(user.email().get());
    		systemUser.setLastName(user.lastName());
    		systemUser.setPassword(user.passwordInfo().get().password());
    		systemUser.setFirstName(user.firstName());
    		systemUser.setProvider(user.identityId().providerId());
    		PasswordInfo passwordInfo = user.passwordInfo().get();
    		String salt = passwordInfo.salt().isDefined() ? passwordInfo
    				.salt().get() : null;
    		systemUser.setPasswordInfo(new SystemPasswordInfo(passwordInfo
    				.hasher(), salt));
    	}

    	@Override
    	public void doSave(Token token) {
    		final SignupToken newToken = SignupToken.from(token);
    		TransactionHelper.run(new Runnable() {

    			@Override
    			public void run() {
    				JPA.em().persist(newToken);
    			}
    		});
    	}

    	@Override
    	public Identity doFind(final IdentityId identityId) {
    		return TransactionHelper.run(new Function0<WrapIdentity>() {

    			@Override
    			public WrapIdentity apply() throws Throwable {
    				Option<SystemUser> user = SystemUsers
    						.findByEmail(identityId.userId());
    				return user.isDefined() ? new WrapIdentity(user.get())
    						: null;
    			}
    		});
    	}

    	@Override
    	public Token doFindToken(final String tokenId) {
    		return TransactionHelper.run(new Function0<Token>() {

    			@Override
    			public Token apply() throws Throwable {
    				return JPA.em().find(SignupToken.class, tokenId)
    						.toSecureSocialToken();
    			}
    		});
    	}

    	@Override
    	public Identity doFindByEmailAndProvider(String email,
    			String providerId) {
    		return doFind(new IdentityId(email, providerId));
    	}

    	@Override
    	public void doDeleteToken(String uuid) {
    		// TODO Auto-generated method stub

    	}

    	@Override
    	public void doDeleteExpiredTokens() {
    		// TODO Auto-generated method stub

    	}

    }

There is a lot going on in this class. Let’s start with all methods that have
token as part of the name or receive a Token as a parameter. When you
want to save a new user, Secure Social uses a two step registration process.
First the new user need to register a email. After that Secure Social will send
an email with the generated token, that is why you need to use the Typesafe
mailer plugin. Here is an example of url:(exemplo aqui) When a user tries to
follow this url, Secure Social will try to validate this token and that is why
you need to override the methods doFindToken and doSave(Token token).
You have to find a way to store this information and query it later. I opted for
save the token in my database.

Other very important method is the doFindByEmailAndProvider(String email,String providerId) method. Every time a user tries to log in your application, this method will be invoked. Now you are probably asking to yourself: where is the password? You
don’t need to worry about. Instead of leave the responsibility of checking the
hashed password in your hands, Secure Social just asks for you to load a user
based on his email. With this user loaded(Identity interface), Secure Social will
use the method passwordInfo to compare the password passed as argument
with the password loaded from the database.

It is a little bit boring, I know, but we need to configure an extra file, the router.
There we need to put all actions that are needed to handle the login/password
based authentication.

    #secure social
    GET     /login                      securesocial.controllers.LoginPage.login
    GET     /logout                     securesocial.controllers.LoginPage.logout

    # User Registration and password handling
    GET     /signup                     securesocial.controllers.Registration.startSignUp
    POST    /signup                    securesocial.controllers.Registration.handleStartSignUp
    GET     /signup/:token              securesocial.controllers.Registration.signUp(token)
    POST    /signup/:token              securesocial.controllers.Registration.handleSignUp(token)

    GET     /authenticate/:provider     securesocial.controllers.ProviderController.authenticate(provider)
    POST    /authenticate/:provider     securesocial.controllers.ProviderController.authenticateByPost(provider)
    GET     /not-authorized             securesocial.controllers.ProviderController.notAuthorized

Notice that all routes are provided by Secure Social. For example, all signup process can be handle out of the box by the framework. Secure social comes with a few predefined templates that you  can start using as your login and signup views. Even if you do not want to use these templates,  you will still want to use all controllers to handle the process.

That is it! Now you can use this Secure Social to handle both social or login/password
authentication process. In another post, I will back showing how to customize the templates and how to override the defaut behavior of the controller. Thanks for reading!

 

Play, Server Sent Events and AngularJS

I am currently involved in a project that uses a lot of server push notification. I could use Web Sockets but, as I only need of one-way of communication is being used SSE to implement all features that need push notifications. In its Scala version, Play has a nice support to SSE, let’s see an example:

	object UpdateCurrentAllocationController extends Controller {

	  val (chatOut, chatChannel) = Concurrent.broadcast[JsValue]

	  def attempts = Action {
	    implicit req =>
	      {
	        Ok.feed(chatOut &>  EventSource()).as("text/event-stream")
	      }
	  }
	}

In the view layer, it is easy to use the SSE support offered by all browsers. Let’s see one more example of code:

	var feed = new EventSource('@br.com.celerate.controllers.routes.UpdateCurrentAllocationController.attempts');
	var handler = function(event){
		//code to update the view
	};
	feed.addEventListener('message', handler, false);

After each notification, we need to update our view with the new data. A common way to accomplish this task is, for example, use JQuery to manipulate the DOM elements from your template. In a Javascript centric application, update all parts of the page becomes really annoying. Take a look in this example:

	var feed = new EventSource('@controllers.routes.UpdateCurrentAllocationController.attempts');
	var handler = function(event){
		var tbody = $("#solution").empty();;
		var solution = JSON.parse(event.data);

		var classes = solution.data.classRooms;
		$.each(classes,function(index,room){
			var tr = $("<tr>").append(
					$("<td>").text(room.course.code),
					$("<td>").text(room.number),
					$("<td>").text(room.interval.begin),
					$("<td>").text(room.interval.end),
					$("<td>").text(room.formatedIntervalOfDay),
					$("<td>").text(room.instructor.name)
					);

			tr.hide().appendTo(tbody).fadeIn(1000);
		});

	};
	feed.addEventListener('message', handler, false);

You end with a javascript code highly coupled with the page elements! Every change you make in a page element, you have to update your javascript code.  This is the scenario where AngularJS better fits. You leave the code necessary to update the elements in your page directly in the html and the code necessary to retrieve the data in other part. Let’s see how it works.  Let’s pick the same table that was updated using JQuery and change to use the AngularJS syntax.

	<tbody id="solution" ng-app="celerateApp" ng-controller="InstructorsController">
		<tr ng-repeat="room in rooms">
	    	<td>{{room.course.code}}</td>
	        <td>{{room.number}}</td>
	        <td>{{room.interval.begin}}</td>
	        <td>{{room.interval.end}}</td>
	        <td>{{room.formatedIntervalOfDay}}</td>
	    	<td>{{room.instructor.name}}</td>
		</tr>
	</tbody>

The ng directives is the way you bind your elements with AngularJS. For example, room in rooms is a Angular syntax to repeat a element in your page. And the {{variable}} is the syntax to use some variables that were defined elsewhere. Now you should be asking yourself, where these variables were created? That is why we are using the ng-controller. The controller class is responsible for updating all variables bound with the elements and this is the biggest difference with the older approach, your js code is bound with variables and not with html elements. Let’s see the controller code:

	var celerateApp = angular.module('celerateApp', []);

	celerateApp.controller('InstructorsController', function($scope) {

	  var feed = new EventSource('/newSolutionListener');
	  var handler = function(event){
			var solution = JSON.parse(event.data);
			$scope.$apply(function () {
				$scope.rooms = solution.data.classRooms;
			});

	  }
	  feed.addEventListener('message', handler, false);
	});

Here we have a lot of things happening. The first thing you have to do is to declare a module. The number of modules will depend on the size of your app. After that, we can configure ours controllers. You need to provide a name and a function that will be executed when the element bound with this controller is found. Now, every time that a new notification is sent from the server, we update the room variable inside the controller scope. We had to use the $apply function to notify Angular listeners which are responsible to update all variables bound with page elements. This method is needed, only if you are trying to update a scope outside from AngularJS callback, which is our case here.

So, if you are planning to build a app that has a lot of ajax or push notifications, I advise you to take a look in Angular.  You can combine the power of this framework with features like REST and push notifications provided by Play.  Enjoy it!

Accessing url parameters as get parameters in Play

A few weeks ago, I published here a post explaining my approach to implement a multi tenant strategy in my application. My main problem was that I did not have access to the url parameters in order to extract the tenant id. Play does not provide any easy way to access this information. So I kept searching and I found one solution, not to pretty, but functional! Just to remember, here I have my action.

	public class TenantResourceAction extends Action{

		@Override
		public Promise call(Context ctx) throws Throwable {
			Long id = Long.parseLong(ctx.request().
					  getQueryString("clientId"));
			//do your stuff here
			return delegate.call(ctx);
		}

	}

The getQueryString(“clientd”) method does not return the value because, as explained here, Play’s team decided do not insert url parameters into the querystring parameters map. So I need to extract the client id from almost every url. For example, http://localhost:9000/user/3/photos. It’s mandatory to check if the current logged user owns the requested resource. To solve this issue was necessary to use some classes from Play core, what was nice to learn more about the tool that I use a lot :). The first part of the job was to extend GlobalSettings and override the Play’s default behavior.

	import play.GlobalSettings
	import play.api.{ GlobalSettings => ScalaGlobalSettings }
	import play.api.mvc.RequestHeader
	import play.api.mvc.Handler

	object Global extends GlobalSettings with ScalaGlobalSettings {

	  //overrided because it was generating a conflict
	  override def getControllerInstance[A](controllerClass: Class[A]) = controllerClass.newInstance();

	  override def onRequestReceived(request: RequestHeader): (RequestHeader, Handler) = {
	    val (rh, handler) = super.onRequestReceived(request)
	    val route = rh.tags("ROUTE_PATTERN")
		...
	  }

	}

Here I had too choose Scala because was necessary the usage of the tags method from Scala version of RequestHeader. This method contains some meta information created by Play during the processing of parsing a request. This is the case of ROUTE_PATTERN key. This key returns the configure value from your routes file that was used to handle the current request. Now that we have the route, for a given uri we have to be able to retrieve all dynamic and static part from this uri. This is the hardest part, because we have to deal with some hidden parts of Play :). When you download the source code of the project, you will see that there are a several projects. One of them is the Routes-Compiler, which is responsible for create the object that represents a parsed route. The class of this object is play.router.PathPattern.  Take a look at the code needed to build this object.

	package play.router

	import play.router.RoutesCompiler._

	object RoutesCompilerHack {

		lazy val parser = new RouteFileParser

		def transform(verb:String,path:String):PathPattern =
				parser.parse(s"$verb $path  fakepackage.fakecontroller.fakemethod")
				.get.head.asInstanceOf[Route].path
	}

In order to have this code working, I had to put it in a package called play.router. The RouteFileParser is a private package class and can’t be accessed outside. Essentially, it is hack :(. After that, is necessary to convert the current PathPattern object to a play.core.PathPattern, which has a method that receives a uri and returns the bound parts with their respective values.

	import play.router.RoutesCompilerHack
	import play.core.{ PathPattern => PlayCorePathPattern }
	import play.router.PathPart
	import play.router.DynamicPart
	import play.router.StaticPart
	import play.core.{DynamicPart => CoreDynamicPart}
	import play.core.{StaticPart => CoreStaticPart}

	object TentantIdExtractor {

	  def apply(confRoute:String,uri:String):String = {
            //here could be used some cache 🙂
	    val pathPattern:play.router.PathPattern	 = RoutesCompilerHack.transform("GET", confRoute)

		//Dynamic and Static objects used inside the Router compiler project
	    val routerCompilerParts = pathPattern.parts

		//Transforming them to play.core.Part(Dynamic and Static)
	    val coreParts = routerCompilerParts.map { part =>
	      part match {
	        case DynamicPart(name, constraint, _) => CoreDynamicPart(name,constraint,true)
	        case StaticPart(name) => {
	          //the first slash("/") was not being generated
	          if(name.startsWith("/")) CoreStaticPart(name) else CoreStaticPart(s"/$name")
	        }
	      }
	    }

		//build the play.core.PathPattern
	    val corePathPattern = PlayCorePathPattern(coreParts)

The objects DynamicPart and StaticPart are used internally in Play to represent the url parts. Now, that we built the play.core.PathPattern object, it is possible to query this object with a requested uri and to retrieve a Option object with the values.

     val result:Option[Map[String,Either[Throwable,String]]] = corePathPattern(uri)

This monster object, that could be encapsulated in some class, has all the dynamic values passed by client. Now we can search for some variable and get the value!

	result.get("clientId") match {
	    case Right(value) => value
	    case Left(e) => throw e
	}

To finish our job, we now can get this value and push into query parameters!

	override def onRequestReceived(request: RequestHeader): (RequestHeader, Handler) = {
	  val (rh, handler) = super.onRequestReceived(request)
	  val route = rh.tags("ROUTE_PATTERN")
	  val tenantId = TentantIdExtractor(route,request.uri)
	  val newParams = rh.queryString.+("clientId" -> List(tenantId))

	  val newRequestHeader = rh.copy(rh.id,rh.tags,rh.uri,rh.path,rh.method,rh.version,newParams,rh.headers,rh.remoteAddress)
	 (newRequestHeader, handler)
	}

We pushed the id and rebuilt the RequestHeader to make this new parameter available to be accessed through request.getQueryString(“clientId”). The code is available here and you can use in your multi tenants projects! That is it folks. I hope this has helped you to understand a little bit more about Play internals and how important is to know the tool that you are using. And please, if there is an easier way, let me know. I enjoyed to hack the framework but I prefer an easier code 🙂

Playframework, how to protect against Mass Assignment

Form data handling is one of the most used feature in every MVC framework, in Play is not different. Documentation on website is very good, but leaves outside a couple of important situations. Let’s see a first case to better understanding about this feature.

Imagine a simple html form to register a user. Here is the user class and template which contains html form:

      public class User {

      	private String id;
      	private String email;
      	private String password;
      	private RoleType roleType = RoleType.CUSTOMER;

      	public void setRoleType(RoleType roleType) {
      		this.roleType = roleType;
      	}

      	public RoleType getRoleType() {
      		return roleType;
      	}

        //getters and setters for other fields
      }

Now we have to write a controller to handle the client submission. Here is an example:

    public class UsersController extends Controller{
	
    	private static Form<User> newUserForm = Form.form(User.class); 

    	public static Result form(){
    		return ok(views.html.new_user_form.render(newUserForm));
    	}
	
    	public static Result create(){
    		Form<User> filledForm = newUserForm.bindFromRequest();
    		if(filledForm.hasErrors()){
    			return badRequest(views.html.new_user_form.render(filledForm));
    		}
    		User user = filledForm.get();
    		Logger.info("RoleType {}",user.getRoleType());
    		Ebean.save(user);
    		return TODO;
    	}
    }

The problem is that we are believing that our user will simply fill the inputs in form and submit the information. What if an extra parameter appear in our Form object? For example, “user.roleType“. There are all kinds of user in this world, and maybe one of them likes to test your application trying to submit extra parameters, using chrome tools for example :).

editiing_html_chrome

When you invoke form.bindFromRequest().get, Play’s underlying binder will get all parameters and try to set in your User object. Every field that has a setter can be set with a form parameter. So the first solution would be drop setRoleType() method from your class. But in our case that is impossible, we need this setter there to allow admin changes roleTypes of other users.

One other solution is configure Form object to accept only some fields, and this feature is implemented already in Play Framework.

    public static Result create(){
    	Form<User> filledForm = newUserForm.bindFromRequest("email","password");
    	if(filledForm.hasErrors()){
    	    return badRequest(views.html.new_user_form.render(filledForm));
    	}
    	User user = filledForm.get();
    	Logger.info("RoleType {}",user.getRoleType());
    	Ebean.save(user);
    	return TODO;
    }

Usage of this technique is a nice way to protect your system against Mass Assignment attack. For instance, Github already suffered with this kind of attack. Stay connected, next week I will write how to handle different types of validations from the same model!

Your Play project is Java and Scala, at the same time

In the moment of creation a Play application, we are obliged to choose between Java and Scala as the base of our code, which is good because you can prefer one or another. The problem with this choice is that the programmers, basically Java programmers, they think that is a final choice. It is not unusual see some doubts in Play’s user forum about how to do something in Java version which is already well know in Scala version. For example, how to implement Web Sockets.

Of course, if there is a Java way to accomplish the task, go ahead and use it but, if there is not a Java way or this way is worst than the Scala version, still go ahead and use Scala. This is the point of this post, Play is possibly the only framework thought to be used with Scala and Java together, and not separated. Another example, all view templates are written in Scala. You still have the router file :).

Let’s see some examples! The first one is if you need to receive a Option in your template. You can try to pass a Option from play.libs.F.Option to your template.

    @(maybeTag:JavaOption[Hashtag])

    @maybeTag.map { tag:Hashtag =>
          @tag
    }.getOrElse {
          tagless
    }

The problem is that template, that becomes a Scala class after compilation, does not have any conversion from play.libs.F.Option to scala.Option. So code showed above will not work. There is no problem at all, instead of pass Play’s wrapper as argument, you can create a new Scala Option and solve your problem.

    ok(views.html.index.render(scala.Option.apply(hashtag)));

Another situation. Sometimes you have a class that simply holds a value. For example, in one of my current projects, I have a class called ImportStat.

    public class ImportStat {

    	private Number count;
    	private PhotoStatus photoStatus;

    	public ImportStat(Number count, PhotoStatus photoStatus) {
    		super();
    		this.count = count;
    		this.photoStatus = photoStatus;
    	}

    	public Number getCount(){
    		return this.count;
    	}

    	public PhotoStatus photoStatus() {
    		return photoStatus;
    	}

    }

I need to print the count value to give some information about a task that is being done by some Actor in my system. One way to do this is:

    @for(stat <- stats) {
     	  @stat.photoStatus():@stat.getCount()
    }

But, with a minor change you can take advantage of Scala syntax sugar to return values of your objects. You can use the apply() method. So let’s change our class.

    public class ImportStat {

    	private Number count;
    	private PhotoStatus photoStatus;

    	public ImportStat(Number count, PhotoStatus photoStatus) {
    		super();
    		this.count = count;
    		this.photoStatus = photoStatus;
    	}

    	public Number apply(){
    		return this.count;
    	}

    	public PhotoStatus photoStatus() {
    		return photoStatus;
    	}

    }

Now, in your template, you can write something like this.

    @for(stat <- stats) {
     	  @stat.photoStatus():@stat()
    }

The last one is the better, at least for me. I needed to use SSE to push notifications to browser. I googled about it and found this link, there was not a Java version! So I kept looking for and I found this blog post, which showed to me that Scala version was already implemented and it is much better than Java way, even if you use the pull request that brings SSE to Java version. So, for this case, I preferred to write the controller in Scala. Let’s just take a look in how you can open a SSE connection.

    package controllers

    //imports

    object UpdatePhotosController extends Controller {

      val (chatOut, chatChannel) = Concurrent.broadcast[JsValue]

      def newPhotos() = Action {
        implicit req =>
          {
            Ok.feed(chatOut &> EventSource()).as("text/event-stream")
          }
      }
    }

Now, let’s look how you can push information through the channel. And we will make this from an Actor written in Java!

    public class UpdatePhotoPanelActor extends UntypedActor{

    	@Override
    	public void onReceive(Object message) throws Exception {
    		final String id = (String) message;
    		Photo photo;
    		try {
    			photo = JPA.withTransaction(new Function0() {

    				@Override
    				public Photo apply() throws Throwable {
    					return Photos.byId(id);
    				}
    			});
    		} catch (Throwable e) {
    			throw new Exception(e);
    		}

    		UpdatePhotosController.chatChannel()
    		    .push(PanelPhotosJson.toScalaJsValue(0,photo));
    	}

    }

That is it! Don’t be afraid to mix both languages. If you are in Java project, your code will be 90% in Java and just 10% in Scala, not a big problem. The important part of Play written in Scala is the core, to build real world application is not important which one you gonna pick :). Choose the option that better fits to your team.

Strategies for testing static calls in Play projects

Play forum is a place with a lot of healthy doubts. Other day, an interesting topic popped there: How to test static methods. So, let’s talk about a little bit about this subject.

For example, if you have this piece of code:

    public void save(final RecentPhotosURL photosURL,
    		final Function2<String, Integer, Void> callback) {
    	WSRequestHolder holder = WS.url(photosURL.getEndpoint());
    	photosURL.fill(holder);
    	Promise promise = holder.get();
    	promise.map(savePhotosFunction);
    }

How can you test it? You are using WS class and making a static call. Libs like Mockito, only can test instance methods. One way to workaround things here is the usage of a lib which instruments your code and is able to mock some static calls :). This powerful tool is PowerMock. So, to test your method you could use something like this.

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({ WS.class })
    public class NewPhotosSaverTest {

    	@Test
    	public void shouldGetJsonResponseAndSaveIt() {
    		mockStatic(WS.class);
    		Mockito.when(WS.url(url).thenReturn(new MyRequestHolder(url));
    		new NewPhotosSaver(...).save(photosURL,callback)
    	}

    	static class MyRequestHolder extends WSRequestHolder{

    		public MyRequestHolder(String url) {
    			super(url);
    		}

    		public  Promise get(){...}

    	}

    }

Voilà, you can unit test a lot of methods that use static approach. This could be used to test legacy system too :). I have no doubts that use static methods are easier than use a lot of instance methods. The main reason is that you can invoke these methods from everywhere. But oops, this can be your big problem too :(.

Now, if someone has to add some logic in this method, there is a big chance that a new class with some static methods be created. The complexity of this method would be increased because it would be responsible for creating and using objects instead of just use them and, even worst, static calls can be made from every piece of your code. I am not sure if you have seen something like this, but imagine a code inside a template:

    for(photo       code here
    }

So you have to know really well your team before start using static methods everywhere. Another strategy can be used to prevent maintainability problems like this. Instead of using Play API’s directly, you could wrap some of them and force your code to instantiate some objects.

    public class ServiceRequester {
      private String endpoint;

      public ServiceRequester(String enpoint){
        ...
      }

      public Promise get(Map<String,String> params){
        WSRequestHolder holder = WS.url(endpoint);
    		Set<Entry<String, String>> entries = params.entrySet();
    		for (Entry<String, String> entry : entries) {
    			holder.setQueryParameter(entry.getKey(),entry.getValue());
    		}
    		return holder.get();

      }
    }

    //using this code

    public class NewPhotosSaver {
        public void save(final RecentPhotosURL photosURL,
        		final Function2<String, Integer, Void> callback) {
        	ServiceRequester requester = new ServiceRequester(photosURL.getEndpoint());
        	Promise promise = requester.get(photosURL.getParams());
        	promise.map(savePhotosFunction);
        }
    }

Now you can refactor a little more and receive these dependencies as constructor args.

    public class NewPhotosSaver {

        public NewPhotosSaver(ServiceRequester requester){
          ...
        }

        public void save(final RecentPhotosURL photosURL,
        		final Function2<String, Integer, Void> callback) {
        	Promise promise = requester.get(photosURL.getParams());
        	promise.map(savePhotosFunction);
        }
    }

It is easy to test now! Just mock this parameter and test your code without problems.

    @Test
    public void shouldGetJsonResponseAndSaveIt() {
      ServiceRequester requester = mock(ServiceRequester.class);
      when(requester.get(params)).thenReturn(somePromiseHere)
      new NewPhotosSaver(requester).save(photosURL,callback);
      //asserts here
    }

Now you have, at least, two options of approach to your code. You can use this same strategy with your DAO. Instead of create static methods that use JPA.em() or Ebean.something, create instance methods and pass DAO’s instances as arguments to other classes.

Of course you have to think about what kind of approach you prefer, it is possible to mix them too. Your tests send signals about your code, pay attention :). Thanks to Rafael Ponte who talked about this situation with me and inspired me to write this post :).