Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Tuesday, June 03, 2014

Proper build.sbt Settings for Play 2.2 and IntelliJ

I came across a bug today that cause IntelliJ 13.1 to act strangely when passing Java objects to Scala templates.










For example the snippet:
public static Result login() {
 ok(login.render(Form.form(Login.class)));
}

will compile and run, but IntelliJ will flag it as an error because it says that it found a play.data.Form object when the Scala template was expecting a play.api.data.Form object. Now that's just the tip of the iceberg, I even found that in some cases my routes (for redirects within the controller) were flagged as unresolvable objects.

Fear not, for the solution is simple. Your build.sbt file will look like this when Play generates the project:
name := "testapp"

version := "1.0-SNAPSHOT"

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache
)  

play.Project.playJavaSettings

Simply change it as follows:

import play.Project._

name := "testapp2"

version := "1.0-SNAPSHOT"

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache
)     

playJavaSettings

Run the following commands:
play clean
play compile

And voila! Those nasty red squiggly lines are gone.

Bug notes


This bug was present in the following software and their versions:

IntelliJ IDEA version: 13.1 IU-135.475
Play Framework version: 2.2.1 - 2.2.3
Play 2.0 plugin version: 0.33.404
Scala plugin version: 0.33.403

Wednesday, October 16, 2013

Scheduling Jobs In Play 2

In this tutorial, I'll show you how to schedule asynchronous jobs in the Play! Framework version 2.1.3.

The Play! Framework has moved away from using Job classes with Crontab-like annotations for application level task scheduling. In place of the old model we find heavy use of the Akka system, which operates a bit differently and can take some getting used to if you're accustomed to the CRON/Quartz way of doing things.

Let's get started!

After creating our application, we need to create a Global.java file in the app/ directory. Place the following in the file:

import play.Application;
import play.GlobalSettings;
import play.libs.Akka;
import scala.concurrent.duration.FiniteDuration;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class Global extends GlobalSettings {
    @Override
    public void onStart(Application app) {
      //Magic goes here
   }
       
}

The above is nothing too complex. It's a file that contains code that will be executed upon starting the application. The important piece is the onStart method that has the @Override annotation. That's where we're going to place our scheduling code.

Before continuing, you should probably take a look at what the Play devs have to say about the use of their Akka scheduler before I give my personal explanation.

Place the following in the onStart method of the Global.java file we just created.

FiniteDuration delay = FiniteDuration.create(0, TimeUnit.SECONDS);
FiniteDuration frequency = FiniteDuration.create(5, TimeUnit.SECONDS);

Runnable showTime = new Runnable() {
   @Override
   public void run() {
      System.out.println("Time is now: " + new Date());
   }
};

Akka.system().scheduler().schedule(delay, frequency, showTime, Akka.system().dispatcher());

The above simply allows us to log the current time to the console ever 5 seconds. Not very useful, but it's a start. Run the application and see for yourself.

schedule() Arguments Explained

Before we continue we should probably get a firm grip of the schedule(...) method signature.

delay - How long after the application starts should I wait before running my code?
frequency - After I've run my code the first time, how often should I repeat it?
showTime - A runnable containing the code that is to be run after the delay and at the defined frequency.
Akka.system.dispatcher() - Not entirely sure what this is, but it's needed as the last argument.

Neither of the first two arguments can be changed from within the Runnable body. The delay (and frequency) must be calculated on application start correctly and in such a way that the timing of the job is not affected by application restarts.

Defining a Proper Schedule

Now that we've covered the basics, let's move on to creating a useful schedule. The schedule that we'll create will run a task at 4PM every day.

The first step is to determine the delay i.e. how long the scheduler should wait to execute our task once the application has started. The challenge here is that the calculation of the delay must accommodate random application restarts. Say, for example, we start our application at 8AM, the job should wait roughly 6 hours before it starts, but if at 3PM the need arises for us to restart the application, the delay should be recalculated to 1 hour. We will calculate this delay in seconds for better precision.

I'll be using the Calendar class, but feel free to use JodaTime if you're more comfortable. So let's augment our previous code snippet to calculate this delay:
Long delayInSeconds;

Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 16);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
Date plannedStart = c.getTime();
Date now = new Date();
Date nextRun;
if(now.after(plannedStart)) {
   c.add(Calendar.DAY_OF_WEEK, 1);
   nextRun = c.getTime();
} else {
   nextRun = c.getTime();
  }
 delayinSeconds = (nextRun.getTime() - now.getTime()) / 1000; //To convert milliseconds to seconds.

Code explanation:
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 16);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
Date plannedStart = c.getTime();

Use a Calendar object and set it's time to 4PM of the current day, then create a date object to store the current date and the intended start time based on the modified Calendar object.
Date now = new Date();
Date nextRun;
if(now.after(plannedStart)) {
   c.add(Calendar.DAY_OF_WEEK, 1);
   nextRun = c.getTime();
} else {
   nextRun = c.getTime();
  }

Find out the current date and time (now) and create a new Date object (nextRun) that will store the date and time of the next code execute.If the time now is after the time we planned to start the job, then we'll set the time that the job should execute to be tomorrow at 4PM. If not then we're on schedule and the nextRun will be today at 4PM.
delayInSeconds = (nextRun.getTime() - now.getTime()) / 1000; //To convert milliseconds to seconds.


Next we do some simple subtraction to find out how many seconds between now and the next time the code should run. This is our delay... In seconds, of course.

From here on it's gravy. Simply substitute the delayInSeconds value for the integer value in the FiniteDuration delay variable and change the frequency to 1 day as follows:


FiniteDuration delay = FiniteDuration.create(delayInSeconds, TimeUnit.SECONDS);
FiniteDuration frequency = FiniteDuration.create(1, TimeUnit.DAYS);
Runnable showTime ...
Altogether Now!

Long delayInSeconds;

Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 16);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
Date plannedStart = c.getTime();
Date now = new Date();
Date nextRun;
if(now.after(plannedStart)) {
   c.add(Calendar.DAY_OF_WEEK, 1);
   nextRun = c.getTime();
} else {
   nextRun = c.getTime();
  }
 delayInSeconds = (nextRun.getTime() - now.getTime()) / 1000; //To convert milliseconds to seconds.

FiniteDuration delay = FiniteDuration.create(delayInSeconds, TimeUnit.SECONDS);
FiniteDuration frequency = FiniteDuration.create(1, TimeUnit.DAYS);
Runnable showTime = new Runnable() {
            @Override
            public void run() {
                System.out.println("Time is now: " + new Date());
            }
        };

Akka.system().scheduler().schedule(delay, frequency, showTime, Akka.system().dispatcher());

Now every day at 4PM your application will remind you of the time. Awesome.

Thanks very much to +James Ward and this magnificent post for helping me wrap my head around this tricky concept. Thanks to the +Typesafe folks for all their hard work with the +Play Framework , and as always thank you for reading.








Sunday, August 25, 2013

Play Framework 2.x - Taking the Plunge


So after many months of kicking and screaming against being forced into the new 2.x.x branch of the Play! Framework I finally decided to take a weekend and learn the damn thing and get it over with.





Pros

Much more powerful and feature packed than the 1.x branch
In addition to some serious code optimizations and refactorings, things like an interactive console, built in H2 in-memory database browser and a built-in LESS and CoffeeScript compiler are just a few of the bells and whistles added on that really add to the development experience.

The Scala templating language is not as scary as it sounds
...And that's coming from a Java developer. Yes, I really enjoyed using this templating system even though some things took a couple minutes to really sink in. Parameter groups? What's that?

The new ebean ORM 
Though I've only used it to complete the Zen Tasks tutorial, i'm seeing that it requires a lot less hand-holding in the JPA annotation department. Give it a @ManyToOne annotation in one class and you don't need to go to the related class and set up the mappings. It's something I haven't seen done anywhere else (except Rails, I think) and it's nice to see it available here in sweet ol' Java. 


Cons

Not as friendly, free form an "playful" as the 1.x branch. 
Doing the simplest of things requires a lot more typing, planning and thought now. Gone are the days when I could have just done this:

public static void updateUser(User user) {
 user.save();
 render();
}

Now I have to do:

public static void updateUser() {
 Form userForm = form(User.class).bindFromRequest();
 User u = userForm.get();
 u.save();
 ok(views.html.users.updateUser.html);
}

This approach provides certain advantages, but it really takes away from the appeal and fun I had with the 1.x approach.

Documentation is a bit lacking
I wish the documentation could have been organized better and be more detailed a la 1.x. Certain sections like Forms and Action Composition could use a little attention.

Searching for help turns into a hunt
Searching for help online usually returns 1.x or 2.x Scala results. This is not helpful to a 2.x Java developer.

Other Thoughts

I've been a big fan of the +Play Framework since I walked away from Rails over a year ago. I haven't looked back since. Part of what made me fall so madly in love with it was it's power without being verbose; elegant simplicity without the need for me to get embroiled in XML files and the like. I could have hardly believed it was Java I was using!

As of late though, it's become a bit heavier and less of a tool that I could use to knock out a prototype in no time flat. Don't get me wrong, it's still miles better than Spring or Struts (shudder), but it's just not as free form and delightful as it was when it was younger. I do understand, though, that some of its "agility" was sacrificed to introduce better optimized code and more powerful technologies, so I guess I'll just file this under the price of progress.


For those of you wondering why I took a weekend, this included getting comfortable with +IntelliJ IDEA and wrangling with the many technical issues that came up with the Scala and Play2 plugins. IntelliJ is a marvelous IDE and has proved me wrong in believing that Eclipse was the be all and end all of Java IDEs, but I think the Play 2 plugin could use some work. It won't, for example, let me reference a template via index.render(...), so I have to do views.html.index.render(...) or import views.html.index before I can call the render method. It's a minor issue, but majorly annoying when I'm trying to dance my way across the keyboard to project completion.

Conclusion

In closing I'd like to say that Play 2 is not the horrid, complex mess I thought it was. Sure it's a bit different and sure i'll have to wave goodbye to some of my old habits, but the framework has been made better and future proofed for tomorrows web application developers. I really appreciate all the hard work that +James Ward and the team at Typesafe have been doing. 

Here's hoping that Play 3.0 will be backwards compatible!