Matt RaibleMatt Raible is a Web Developer and Java Champion. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

10 Years Ago...

Wouldn't you know it, I missed my 10-year blogiversary. 10 years ago yesterday, I wrote my first blog post. This was shortly after reading Dave Johnson's article about Roller. I originally started this blog to share a bunch of tips and tricks I'd learn while doing web development, particularly with Java and Struts. Since then, I've written 3,086 entries and received 13,462 comments.

I found that writing technical blog posts was a great way to remember things and share knowledge. According to Google Analytics (which doesn't track my RSS/Atom feeds), here's my most-visited blog posts since 2006.

I also started it to document my life, so I could remember the details of significant life events and fun family vacations. I wrote about Abbie's and Jack's arrival. I penned a story about growing up at the cabin, twice. In April 2004, I wrote about buying a 1966 21-window VW Bus. Yes, I'm still restoring it. No, I don't know when it'll be done. This year I hope.

I blogged about Abbie and Jack's first day of school, I wrote about almost all of Abbie's birthdays; Jack's 5th, 4th, 3rd and 1st. Some of my favorite comments are on Jack's got a bead stuck in his nose! I blogged about getting a divorce 5 years ago. I wrote about visiting the real Oktoberfest the next year.

I wrote about my Dad's retirement, my sister's wedding and my Mom's retirement.

I met Trish in June of 2010 and mentioned her name for the first time in September 2010. I introduced her to the kids in November and we started traveling the world together. We journeyed to Antwerp/Amsterdam, Fort Lauderdale/Key West, Crested Butte, Alta, Las Vegas, a hut trip in the Rockies and Kraków. And that was just in the first 6 months! We got engaged last November.

I summarized the years several times, in 2005, 2006, 2008, 2009, 2010 and 2011.

Last, but certainly not least, I'd like to thank the ones that made the last 10 years possible:

  • Keith at KGB Internet. Hosted here since day 1, for $20 month*.
  • Dave Johnson, for creating Roller and continuing to maintain it all these years.
  • Java and Tomcat, for your rock-solid stability through the years.
  • The Open Source Movement, for providing so much to write about.
  • My Family, for giving me with so many adventures and memories.

* Thank goodness he doesn't charge me for bandwidth. It's a little heavy on the bits.

Update: As part of this 10-year celebration, I've updated the look-and-feel with help from Gillen's Army.

Posted in Roller at Aug 02 2012, 12:47:19 PM MDT 3 Comments

Summer Vacation 2012 in Montana and Maui

I started writing about my summer vacations in Montana as soon as this blog gave me an opportunity: July 2003. In July 2004, I didn't travel to the cabin for the 4th, but I did in 2005. Then, 5 years ago, I started writing longer blog posts about our trips. 2008 was Raible Road Trip #12. In 2009, I spent a whole month in Montana. In 2010, I visited after my parents moved there full-time. Last year, I took Trish for the first time.

I don't know what Raible Road Trip number this year's trip was, but I'm going to go ahead and assume #17. This year wasn't exactly a vacation for me. It was what I like to call a workation. I tried to take the whole month off, but my current client needed my services. As a compromise, they agreed to let me work 20 hours per week during July. While I didn't get a chance to fully unplug, I did enjoy the reduced workload and time to spend with friends and family. And the views from The Cabin and Sugar Beach weren't bad either. ;)

Below is our trip itinerary in condensed form, complete with photos from my incredibly talented fiancé.

We embarked on our drive to Montana on June 30th, stopped for fireworks in Wyoming and spent the night in Yellowstone park. Arrived at the cabin, got to sleep in the new house for the first time, built a cabin float, drove it in the parade, went boating at Holland Lake, played golf. Journeyed to West Glacier to celebrate Dr. Barton's PhD at his sister's house. Rafted the Middlefork of the Flathead all weekend. Played some more golf and went waterskiing.

Abbie at The Cabin My Dad Happy 4th! Raible Homestead in the Swan Valley Parade
Holland Lake Patio The Girls at Double Arrow Hard to believe I caused this guy to move to Montana in 1997 Holland Lake Sunset Soy Fields in Montana
→ Trish's Montana Summer 2012 Album

On July 14th, we flew to Maui and continued to explore. Our good friend's parents have a timeshare on Sugar Beach and got us a screaming deal on lodging. We had beachfront accommodations with a pool, hot tub and sauna. We played golf on my birthday (July 16th). Visited the Old Lahaina Luau, Maui Aquarium and Coconut Festival at Grand Wailea. Drove to the summit of Haleakala. Sipped cold handcrafted ales while watched the kids boogie board. Embarked on a sunset cruise, hiked in Iao Valley, did some horseback riding along the beach, sea kayaked and snorkeled with sea turtles. Savored Shawn's excellent cooking. Flew back to Missoula (Montana), slept for 6 hours and drove 12.5 hours back to Denver on July 27th.

Api, Makao and Keaka. My Hawaiin name is Pualani I'm going to call him Honu! Abbie with the Stingray Wahoo! We did it!
Sunset sail from a catamaran in Maui. Epic! Where we stayed for 2 weeks! Epic Maui Ride Kayaking with Turtles
→ Trish's Maui Summer 2012 Album

Mahalo Montana and Maui. Thank you to our awesome friends: Mom, Dad, Owen, Jason, Ryan and Shawn. It was an incredible adventure.

Posted in General at Aug 01 2012, 09:30:27 AM MDT Add a Comment

Father's Day Weekend at The Oregon Coast

For the 5-year anniversary of our Father's Day Camping Trip, we decided to mix things up a bit. My parents were in Oregon for a friend's wedding, so we decided to fly to meet them there instead of flying them to Colorado. My sister hopped on "Buttercup" (her Harley) and drove to meet us from Washington. We also invited our good friends Clint and Autumn (who you might remember from Costa Rica) and had a great time staying at Gearhart Cottages.

We didn't feel too bad about skipping camping since Trish held a "Boot Camp" with the kids and their friends at Stillwater Campground the week before. You might remember Stillwater from last year's Father's Day trip.

Trish's Uncle John drove out to the coast to meet us and we did a really fun hike along Indian Beach to Ecola State Park. It was a real treat! It was also really fun to meet Clint and Autumn's 9 month old Brodie. As usual, Trish snapped some incredible photos.

View from Ecola State Park Oregon

Raible Family on the Oregon coast Abbie and Jack frolicking in the waves Kalin and Joe on the beach

That was two weeks ago. We returned to Colorado, had some fun at ÜberConf, rocked out at a Def Leppard concert then enjoyed a few Rockies games before hopping in the car and heading to Montana. We spent the night at Roosevelt Lodge Cabins in Yellowstone and saw a plethora of buffalo, a couple bears and even a beaver while driving through.

This morning, we woke up at the cabin I was born in.

The Cabin 2012

We'll be working on my parent's retirement cabin, getting a float ready for the Swan Valley Parade and having a good ol' time with great friends for the next two weeks. After that, we're taking the kids to Hawaii for the first time.

Here's to summer vacations. I hope yours is spent with great people in beautiful places too.

Posted in General at Jul 02 2012, 09:44:00 AM MDT Add a Comment

Play vs. Grails Smackdown at ÜberConf

Play and Grails have been hyped as the most productive JVM Web Frameworks for the last couple of years. That hype has recently grown thanks to both frameworks' 2.0 releases. That's why James Ward and I decided to do a presentation at ÜberConf comparing the two. In April, we proposed the talk to Jay Zimmerman, got accepted and went to work.

How we did it
In the beginning of May, we met at a brewery in LoDo and sketched out the app we wanted to build. We also came up with a schedule for development and a plan for the presentation. We decided to build two different webapps, each with little-to-no Ajax functionality and a few features that we could use to load test and compare the applications.

We started out with the name “Happy Trails” since we both liked trails and happy hours. Later, James found that www.ubertracks.com was available and purchased the domain. We setup the Grails app to be on bike.ubertracks.com and Play/Java to be on hike.ubertracks.com. We managed our source code on GitHub, continuously tested on CloudBees and deployed to Heroku. Two weeks ago, when we were finishing up our apps, we hired a friend (Linsay Shirley) to do QA.

After fixing bugs, I emailed Patrick Lightbody, got some “cloud dollars” for Neustar Web Performance and started running load tests. The Wednesday before last, at 2 in the morning, I recorded a simple browsing regions and routes script and set it to go to 50 users over a 5 minute period and then sustain 50 for another 5 minutes. It was fun to watch the log messages whiz through my console so fast they got blurry. About halfway through testing the Grails app, there was an OOM issue, but it eventually recovered. Limiting db connections to 4 and scaling to 5 Dynos in future tests helped alleviate any issues.

We took our development experience, the load/performance testing data, and a bunch of ecosystem stats and built our smackdown presentation. We used reveal.js, GitHub Files and Google Charts to make things more dynamic.

What we found
We arrived at a number of conclusions after doing our research:

Code

  • From a code perspective, Play 2 and Grails 2 are very similar frameworks.
  • Code authoring was good in both, but lacking IDE support for Play 2's Scala Templates.
  • Grails Plugin Ecosystem is excellent.
  • TDD-Style Development is easy with both.
  • Type-safety in Play 2 was really useful, especially routes.

Statistical Analysis

  • Grails has better support for FEO (YSlow, PageSpeed)
  • Grails has less LOC! (6 lines less, but 40% more files)
  • 1 Dyno - Grails had 2x transactions!
    • Grails experienced OOM about halfway through.
  • Apache Benchmark with 10K requests:
    • Play: ~10% failed requests, Grails: 0
    • Requests per second: {Play: 170, Grails: 198}
    • Requests per second: {Play: 251, Grails: 198}
  • Load Test with 100 Real Users:
    • Grails: 10% more transactions, 0 errors

Ecosystem Analysis

  • "Play" is difficult to search for.
  • Grails is more mature.
  • Play has momentum issues.
  • LinkedIn: more people know Grails than Spring MVC.
  • Play has 3x user mailing list traffic.
  • We had similar experiences with documentation and questions.
  • Outdated documentation is a problem for both.
  • Play has way more hype!

We figured we spent around 100 hours developing the apps, gathering data and creating the presentation. The good news is it's all open source! This means you can clone the project on GitHub (Grails is in the grails2 branch, Play is in the play2_java branch) and help us improve it. The presentation is in the master branch in the preso directory.

All the data we gathered is open for debate and we’d love to tune our apps to handle more requests per second. In fact, we already had a contributor discover an issue and provide a fix for Play that increases its throughput from 170 req/second to 252 req/second!

Regardless of what the stats and pretty graphs say, we both enjoyed our experiences with Play 2 and Grails 2. If you haven't tried them yourself, we encourage you to do so.

Posted in Java at Jun 25 2012, 07:10:57 AM MDT 19 Comments

Migrating to Play 2 and My ÜberConf Presentation

In my last post about migrating to Play 2, I said I'd write another post on the rest of my experience. While I'm not completely finished with migrating to Play 2, I feel like I've done enough to talk about the issues I encountered.

Validation and Displaying Errors
With Play 1, I can't help but think validation was a bit more intuitive. For example, here's how I populated an object from request parameters, converted a value and validated its data was fit to put in a database.

var workout = params.get("workout", classOf[Workout])

// change duration to time
var duration = params.get("workout.duration")
workout.duration = convertWatchToTime(duration)

Validation.valid("workout", workout)

if (Validation.hasErrors) {
  renderArgs.put("template", "Profile/edit")
  edit(id);
  ...
} else { // put into db

With Play Scala 2, you have to define a Form structure and bind it from the request. Based on what I was able to conjure up, I ended up writing the following code to accomplish the same thing:

val workoutForm = Form(
  mapping(
    "id" -> ignored(NotAssigned: anorm.Pk[Long]),
    "title" -> text,
    "description" -> text,
    "duration" -> nonEmptyText,
    "distance" -> nonEmptyText,
    "postedAt" -> optional(date),
    "athleteId" -> optional(longNumber)
  )((id, title, description, duration, distance, postedAt, athleteId) =>
    Workout(id, title, description, convertWatchToTime(duration), distance.toDouble, null, 0))
    ((w: Workout) =>
      Some((w.id, w.title, w.description, w.duration.toString, w.distance.toString, null, Some(0))))
)
...
workoutForm.bindFromRequest.fold(
  form => {
    Ok(Scalate("/Profile/edit.jade").render(request, 'errors -> form.errors))
  },
  workout => { // put into db

First of all, the Play 2 version is quite a bit more verbose, but most of that comes from the re-defining of my model object as a form. It seems strange that the Java API allows you to do it in one line whereas the Scala version does not. Also, I was unable to figure out how to get the data from my "form" back into the request so I could refill input fields. I'll admit, I didn't spend a lot of time trying to figure it out, but it did fail the 10 minute test. Note to self: use HTML5's required attribute to reduce the need for server-side validation on modern browsers.

On a more positive note, I did like the way I was able to use routes in my Jade templates. It was as simple as importing the routes class and using it as you would in Play's Scala Templates:

-import controllers._

form(method="post" class="form-stacked" id="workoutForm"
  action={routes.Profile.postWorkout(workout.map(_.id.get))})
  input(type="hidden" name="id" value="#{workout.map(_.id)}")

Secure Social
After getting most of my UI working, I started looking at the Secure Social Module for Play 2. Below are the steps I had to go through to install it:

  1. Cloned GitHub project to my hard drive.
  2. Copied module-code/* into my projects' modules/securesocial directory.
  3. Modified project/Build.scala to add secureSocial and dependsOn to my project.
    val secureSocial = PlayProject(
      appName + "-securesocial", appVersion, mainLang = SCALA, path = file("modules/securesocial")
    )
    
    val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
      // Add your own project settings here
    ).dependsOn(secureSocial).aggregate(secureSocial)
    
  4. Added a conf/securesocial.conf and included it in my application.conf with the following line:
    include "securesocial.conf"
    
  5. Added a conf/play.plugins with the following to get Twitter to load as a provider:
    10000:securesocial.core.providers.TwitterProvider
    
  6. Created an InMemoryUserService.scala and referenced it in my play.plugins file:
    9999:services.InMemoryUserService
    
  7. Added Secure Social's routes to my conf/routes file.

Once I'd finished all these steps, I fired up my app and was pleasantly surprised to find I could navigate to /login and successfully authenticate via Twitter. Installing Secure Social in a Play 2 app is quite a bit harder than adding it as a dependency in Play 1, but I was thankful that I got it to work in under 10 minutes.

Heroku
The next thing I did was attempt to deploy my app to Heroku. I knew there might be some issues with Scalate after reading Jan Helwich's blog post about Scalate on Heroku. The first things I encountered were 1) a successful startup and 2) an error in my browser.

Action not found

I was able to reproduce this issue locally by running "play clean stage" and starting the app with "target/start". After 30 minutes of banging my head against the wall, I guessed it might be caused by Secure Social. Removing Secure Social solved the problem and I was back in business. However, this time when I deployed, I received the error that Jan had mentioned might happen.

2012-06-21T07:07:12+00:00 app[web.1]: [error] o.f.s.l.DefaultLayoutStrategy - Unhandled: org.fusesource.scalate.TemplateException: target/../tmp/src/app/target/../app/views/layouts/default.jade.scala (No such file or directory)
2012-06-21T07:07:12+00:00 app[web.1]: [error] application - 
2012-06-21T07:07:12+00:00 app[web.1]: 
2012-06-21T07:07:12+00:00 app[web.1]: ! @6amfgf02h - Internal server error, for request [GET /] ->
2012-06-21T07:07:12+00:00 app[web.1]: 
2012-06-21T07:07:12+00:00 app[web.1]: play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[TemplateException: target/../tmp/src/app/target/../app/views/layouts/default.jade.scala (No such file or directory)]]
2012-06-21T07:07:12+00:00 app[web.1]:   at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:134) [play_2.9.1-2.0.1.jar:2.0.1]
2012-06-21T07:07:12+00:00 app[web.1]:   at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:115) [play_2.9.1-2.0.1.jar:2.0.1]
2012-06-21T07:07:12+00:00 app[web.1]:   at akka.actor.Actor$class.apply(Actor.scala:311) [akka-actor-2.0.1.jar:2.0.1]
2012-06-21T07:07:12+00:00 app[web.1]:   at play.core.ActionInvoker.apply(Invoker.scala:113) [play_2.9.1-2.0.1.jar:2.0.1]
2012-06-21T07:07:12+00:00 app[web.1]:   at akka.actor.ActorCell.invoke(ActorCell.scala:619) [akka-actor-2.0.1.jar:2.0.1]
2012-06-21T07:07:12+00:00 app[web.1]:   at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:196) [akka-actor-2.0.1.jar:2.0.1]
2012-06-21T07:07:12+00:00 app[web.1]: Caused by: org.fusesource.scalate.TemplateException: target/../tmp/src/app/target/../app/views/layouts/default.jade.scala (No such file or directory)
2012-06-21T07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.TemplateEngine.compileAndLoad(TemplateEngine.scala:834) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21T07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.TemplateEngine.compileAndLoadEntry(TemplateEngine.scala:691) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21T07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.TemplateEngine.liftedTree1$1(TemplateEngine.scala:411) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21T07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.TemplateEngine.load(TemplateEngine.scala:405) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21T07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.TemplateEngine.load(TemplateEngine.scala:475) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21T07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.layout.DefaultLayoutStrategy.org$fusesource$scalate$layout$DefaultLayoutStrategy$$tryLayout(DefaultLayoutStrategy.scala:77) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21T07:07:12+00:00 app[web.1]: Caused by: java.io.FileNotFoundException: target/../tmp/src/app/target/../app/views/layouts/default.jade.scala (No such file or directory)
2012-06-21T07:07:12+00:00 app[web.1]:   at java.io.FileOutputStream.open(Native Method) ~[na:1.6.0_20]
2012-06-21T07:07:12+00:00 app[web.1]:   at java.io.FileOutputStream.(FileOutputStream.java:209) ~[na:1.6.0_20]
2012-06-21T07:07:12+00:00 app[web.1]:   at java.io.FileOutputStream.(FileOutputStream.java:160) ~[na:1.6.0_20]
2012-06-21T07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.util.IOUtil$.writeBinaryFile(IOUtil.scala:111) ~[scalate-util-1.5.3.jar:1.5.3]
2012-06-21T07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.TemplateEngine.compileAndLoad(TemplateEngine.scala:747) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21T07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.TemplateEngine.compileAndLoadEntry(TemplateEngine.scala:691) ~[scalate-core-1.5.3.jar:1.5.3]

I tried his suggestion (removing the first slash on my Scalate paths) but it didn't work. I tried adding in Scalate pre-compilation, but that didn't solve the problem either. The good news is I did solve it this afternoon by changing my Scalate object to use a canonical path instead of an absolute one.

iPhone App
In addition to the changes mentioned here, I re-wrote the iPhone app for Play More. I upgraded it to PhoneGap 1.8.1, used jQTouch, developed with AppCode (instead of Xcode) and had a pretty good experience. The only issue I ran into was with the jqt.bars extension from DataZombies. I briefly tried to integrate it and then decided not to. However, I left all its JS and CSS in my page and this caused scrolling to not work and made the app sluggish. Removing the files solved the problem. The other big improvement I made was moving all the static assets (JS, CSS, images) into the mobile app instead of referencing them from http://play-more.com. This reduced the startup time from 30-40 seconds to 3-4 seconds!

Presentation and Source Code
I presented all of these findings and told my story at ÜberConf this morning. In addition, I announced that the code is now open source and available on GitHub. You can view my presentation below or on Slideshare.

Conclusion
Would I do it again? Learning Scala was my primary motivator for digging into Play. When Play 2 was announced, I thought migrating my app to the new version would be easy. Unfortunately, the Play Developers decided to break backwards-compatibility and wrote a whole new framework that still seems to be in its infancy. I think you can see from my last couple of posts that migrating from Play 1.x to 2.x was not an easy task. It's been nice to learn more about Play and Scala in the process, but living on the bleeding edge was also quite frustrating at times. Play Scala 1.x seemed to be quite a bit more productive than Play 2, especially because of the Magic[T] in Anorm, but also because it required less code in Controllers.

I found Anorm and Scalate to be huge time sinks and don't know if I'd recommend using either one in a Play 2 project. I'm sure Scalate will be easier to use as its Play 2 integration gets more refined, but I don't know if there's any hope for a JDBC abstraction that doesn't produce error messages when things go south.

On the upside, my experience with HTML5 and CoffeeScript was wonderful. They did what I asked them to do and didn't cause much pain. When a browser-based webapp couldn't handle geo running in the background, PhoneGap came to the rescue.

I plan on continuing to develop Play More! If you'd like to help, checkout the open issues and viva la open source!

Posted in Java at Jun 21 2012, 04:09:22 PM MDT 1 Comment

Upgrading to Play 2: Anorm and Testing

This time last year, I decided I wanted to learn Scala. I chose the Play Framework as my vehicle for learning and I added CoffeeScript and Jade to the mix. I packaged it all up, learned a bunch and presented it at Devoxx 2011.

In January, I added SecureSocial, JSON Services and worked a bit on the mobile client. I presented my findings at Jfokus shortly after. As part of my aforementioned post, I wrote:

Right before we left for Jfokus, I was able to get everything to work, but didn't spend as much time as I'd like working on the mobile client. If this talk gets accepted for Devoxx France, I plan on spending most of my time enhancing the mobile client.

I had some complications (a.k.a. too much vacation) with Devoxx France and wasn't able to attend. To make up for it, I submitted the talk to ÜberConf. It got accepted and I started working on my app a couple weeks ago. So far, I've spent about 8 hours upgrading it to Play 2 and I hope to start re-writing the mobile client later this week. I plan on using Cordova, jQTouch and releasing it in the App Store sometime this month.

Upgrading to Play 2
When I heard about Play 2, I thought it was a great thing. The developers were re-writing the framework to use Scala at the core and I was already using Scala in my app. Then I learned they were going to throw backwards compatibility out the window and I groaned. "Really? Another web framework (like Tapestry of old) screwing its users and making them learn everything again?!", I thought. "Maybe they should call it Run instead of Play, leaving the old framework that everyone loves intact."

However, after hearing about it at Devoxx and Jfokus, I figured I should at least try to migrate. I downloaded Play 2.0.1, created a new project and went to work.

The first thing I learned about upgrading from Play 1.x to Play 2.x is there's no such thing. It's like saying you upgraded from Struts 1 to Struts 2 or Tapestry 4 to Tapestry 5. It's a migration, with a whole new project.

Evolutions
I started by looking around to see if anyone had documented a similar migration. I found two very useful resources right off the bat:

From Jan's Blog, I learned to copy my evolutions from my Play 1.x project into conf/evolutions/default. I changed my application.conf to use PostgreSQL and wrote an EvolutionsTest.scala to verify creating the tables worked.

import org.specs2.mutable._

import play.api.db.DB
import play.api.Play.current

import anorm._

import play.api.test._
import play.api.test.Helpers._

class EvolutionsTest extends Specification {

  "Evolutions" should {
    "be applied without errors" in {
      evolutionFor("default")
      running(FakeApplication()) {
        DB.withConnection {
          implicit connection =>
            SQL("select count(1) from athlete").execute()
            SQL("select count(1) from workout").execute()
            SQL("select count(1) from comment").execute()
        }
      }
      success
    }
  }
}

Then I began looking for how to load seed data with Play 2.x. In Play 1.x, you could use a BootStrap job that would load sample data with YAML.

import play.jobs._
import play.Play

@OnApplicationStart
class BootStrap extends Job {

  override def doJob() {

    import models._
    import play.test._

    // Import initial data if the database is empty
    if (Athlete.count().single() == 0) {
      Yaml[List[Any]]("initial-data.yml").foreach {
        _ match {
          case a: Athlete => Athlete.create(a)
          case w: Workout => Workout.create(w)
          case c: Comment => Comment.create(c)
        }
      }
    }
  }
}

This is no longer a recommended practice in Play 2. Instead, they recommend you turn your YAML into code. 10 minutes later, I had a Global.scala that loaded seed data.

import models._
import play.api._
import play.api.Play.current

import anorm._

object Global extends GlobalSettings {

  override def onStart(app: Application) {
    InitialData.insert()
  }
}

/**
 * Initial set of data to be loaded
 */
object InitialData {

  def date(str: String) = new java.text.SimpleDateFormat("yyyy-MM-dd").parse(str)

  def insert() {

    if (Athlete.count() == 0) {

      Seq(
        Athlete(Id(1), "[email protected]", "beer", "Matt", "Raible"),
        Athlete(Id(2), "[email protected]", "whiskey", "Trish", "McGinity")
      ).foreach(Athlete.create)

      Seq(
        Workout(Id(1), "Chainsaw Trail",
          """
            A beautiful fall ride: cool breezes, awesome views and yellow leaves.

            Would do it again in a heartbeat.
          """, 7, 90, date("2011-10-13"), 1),
        Workout(Id(2), "Monarch Lake Trail",
          "Awesome morning ride through falling yellow leaves and cool fall breezes.",
          4, 90, date("2011-10-15"), 1),
        Workout(Id(3), "Creekside to Flume to Chainsaw",
          "Awesome morning ride through falling yellow leaves and cool fall breezes.",
          12, 150, date("2011-10-16"), 2)
      ).foreach(Workout.create)

      Seq(
        Comment(1, "Jim", "Nice day for it!"),
        Comment(2, "Joe", "Love that trail."),
        Comment(2, "Jack", "Where there any kittens there?")
      ).foreach(Comment.create)
    }
  }
}

Anorm's Missing Magic
Before starting with Play 2, I knew it had lost some of its magic. After all, the developers had mentioned they wanted to get ride of the magic and moving to Scala allowed them to do that. However, I didn't think I'd miss Magic[T] as much as I do. Like Martin Fowler, I like ORMs and having to use SQL again seems painful. It seems like a strange shift for Play to reduce type-safety on the backend, but increase it in its templates. Oh well, to each their own. I may eventually move to Squery, but I wanted to do a side-by-side comparison as part of my migration.

Using the aforementioned tutorial from James and Jan's blog posts, as well as Guillaume's Play 2.0/Anorm, I set about creating new model objects. I wrote a bunch of SQL, typed up some new finders and migrated my tests from ScalaTest to the new default, specs2. The Mosh Pit's Migrating a Play 1.2 website to Play 2.0 was a great help in migrating tests.

That's when I started having issues with Anorm and figuring out how its parser syntax works. After struggling for a few days, I finally found yabe-play20-scala. Since I'd used the yabe tutorial from Play 1.x, it was familiar and helped me get past my problems. Now, things aren't perfect (Workouts aren't ordered by their posted date), but everything compiles and tests pass.

To illustrate how little code was required for Anorm 1.x, checkout Workout.scala in Play 1.x vs. Play 2.x. The Play 1.x version is 66 lines; Play 2.x requires 193 lines. I don't know about you, but I kinda like a little magic in my frameworks to reduce the amount of code I have to maintain.

I was pleasantly surprised by specs2. First of all, it was an easy migration from ScalaTest. Secondly, Play's FakeApplication made it very easy to write unit tests. The line count on my UnitTests.scala in Play 1.x vs. Play 2.x is almost identical.

Summary
The first few hours of developing with Play 2 were frustrating, mostly because I felt like I had to learn everything over again. However, I was pleased to find good references on migrating from Play 1.x. Last night, I migrated all my Controllers, integrated Scalate and got most of my views rendering. I still have issues rendering validation errors, but I hope to figure that out soon. The last 2 hours have been much more fun and I feel like my Scala skills are coming along. I think if the Play Team could eliminate those first few hours of struggling (and provide almost instant joy like Play 1.x) they'd really be onto something.

As soon as I figure out how to validation and how to add a body class based on the URL, I'll write another post on the rest of my migration. A Play 2-compatible version of SecureSocial just came out this evening, so I may integrate that as well. In the meantime, I'll be working on the iPhone app and finishing up a Grails 2 application for James Ward and my Grails vs. Play Smackdown.

Posted in Java at Jun 05 2012, 08:55:40 PM MDT 7 Comments

School's Out for Summer!

One of the main reasons I started this blog was to document my life. I like writing technical blog posts because it allows me to save knowledge in my brain and open up space for new stuff. It's been a couple months since I wrote any tech posts, but rest assured there will be a flurry in the near future. In the meantime, I'd like to reflect on my kids and how proud I am of them.

They both finished school two weeks ago today and I made sure and played Alice Cooper's School's Out several times that day.

Loudly.

I love how the song tries to capture the "greatest three minutes of your life".

Abbie and Jack had an athletic spring; both participating in their sport of choice. Jack chose lacrosse and learned how to play some mean defense. Abbie chose basketball and scored her first hoop in a game. I think I was in 5th grade before I scored in a game, so she's one up on me. Below are their team pictures. Lookin' good kids!

Jack's loves Lacrosse Abbie loves Basketball

Jack's Lacrosse Team Abbie's Basketball Team

In addition to sports, both kids were involved with Cub/Girl Scouts and performed in the school's talent show. I guess they like to be in front of an audience. I wonder where they get that from? ;)

Posted in General at Jun 05 2012, 10:25:54 AM MDT Add a Comment

Wine Tasting in Napa Valley

Earlier this month, I had the pleasure of traveling to California for the monthly commute to my current client. It was a fun week, mostly because my partner in crime started working with me again. We kicked off a new mobile project and I helped finish up a UI refresh that I've been working on for the last few months. While the happy hours and late night chats were fun, it didn't hold a candle to Trish and my journey to Napa Valley over Mother's Day weekend.

Before heading to Napa, I started by emailing some local friends to get some recommendations. We got some really detailed responses, especially from Dusty and Mrs. Crazy Bob. We took their recommendations, setup some appointments, made some reservations and booked a room at Harvest Inn.

After settling in the first night, we drove to Round Pond Estate to have a glass of wine with the sunset. The sunset was great, but Trish made it look even better with a little HDR.

Napa Country Sunset Napa Sunset with Windmill

That evening, we dined at Ad Hoc. We couldn't get a reservation until 9:30, but the food was fantastic and the pairings even better.

On Saturday, we slept in a bit and started our first tasting at Orin Swift in St. Helena. It was a private tasting in a hard-to-find area. We didn't recognize the name when we first made the appointment, but were impressed to find they made The Prisoner and Papillon. We enjoyed hearing the story of the winery and how all the labels came to be. We liked it so much, we bought a bunch and send it to our Moms for Mother's Day.

Orin Swift Collection

From Orin Swift, we went to Cade Winery. This was perched on the top of a mountain and had a terrific view. Trish had booked our tasting and tour online and we someone got into a release party, complete with oysters, exotic cheeses and lots of wine for everyone. We also got a tour of their underground cave.

Cade Vineyard Cave Table Cade Vineyard Cask Row Cade Flowers next to infinity pool

Cade Winery

Darth Vader Plumpjack Couple looking at the view at Cade Winery

While Orin Swift had our favorite wines of the day, Cade was our favorite winery. Not only that, but we discovered they made PlumpJack, which is one of Trish's favorite brands.

The last place we visited that afternoon was Anomaly, a very small winery that was in the owner's backyard. The winery itself was like a tall garage with the tasting room downstairs.

Anomaly Vineyard and house

That evening, we dined at Auberge. It was incredible. The Nuggets losing to the Lakers in Game 7 was not.

Auberge

Thanks to Dusty and Mrs. Crazy Bob for all the excellent recommendations. We thoroughly enjoyed ourselves.

California Chevy in Wine Country

You can check out of Trish's pictures in her Napa Valley Gallery. I especially dig her California Chevy photo shown above.

Posted in General at May 22 2012, 10:53:48 AM MDT Add a Comment

How to build a Shot-Ski

At this year's Java Posse Roundup, James Ward, Trish McGinity, Brad Kizzort and I embarked upon a mission to build a Shot-Ski. Actually, we decided to build two. We wanted to show all the things we learned at the Roundup into a 5-minute Lightning Talk and building Shot-Skis seemed like an excellent mechanism. As Skiing Magazine says:

Everyone should have a shot-ski at their disposal. They're versatile, classy, and always appropriate. And, best of all, easy to make.

We spent about 3 hours researching, building, testing and deploying our shot-skis on a quiet afternoon in the town of Crested Butte. Below is a picture of our finished products, complete with stickers to demonstrate modern webapp design, a.k.a. sex sells.

Shot-Skis!

We developed two different types of shot-skis, one that had the shot glasses top-mounted and the 2nd with the glasses mounted in the skis. We A/B tested them and decided we liked the top-mounted ones better. However, the in-ski version has the benefit of built-in brakes, in case you're using it on the mountain.

The whole crew was proud of what we were able to create in an afternoon. You can almost feel our pride as we strolled to that evening's lightning talks.

Strolling through Crested Butte

And now, thanks to The Java Posse, we actually have video footage of our lightning talk!

If you're ever in the town of Crested Butte, we donated these skis to The Secret Stash and Montanya Distillers. We encourage you to stop by and try them out. You can also checkout Trish's photos of our development process.

Posted in Java at May 03 2012, 04:02:41 PM MDT 1 Comment

Bus Project Update

I bought my '66 21-window VW Bus way back in April of 2004. I purchased it on eBay minutes after DU Won the National Championship in NCAA Hockey. It was a day I still remember very well. Several weeks later, my Dad and I flew to San Diego to pick it up and drive it back to Denver. It was a great adventure. I remember fondly 2-year old Abbie calling it "Daddy Bus". Jack was still a couple months away from his birthday.

Fast forward 8 years and The Bus is still in the shop. It's been there since July 2008. However, it's closer than ever to being finish. In fact, I drove to Colorado Springs last Thursday and met with Jeremy and Ben to finalize what it'll take to get 'er done. In other words, the end is in sight! It's been a long time coming, but this isn't your normal bus project. Not only are we restoring every nut and bolt, but we're converting it to have have a Porsche infrastructure so it can really get up and go. 911 engine (3.0 SC), Weber 46 IDA carbs, 5-speed 915 transmission, custom air-bag suspension (by Franklin's VW Werks), Porsche wheels, iPads for TVs, Porsche gauges and a sweet sound system.

Looking at the pictures below, it might not look like it's close to being done, but we've got most of the parts and now it's just a matter of time.

Porsche 5-speed Tranny Paint Me Please The '66 is ready to be a '12

Ready for paint!

All the used parts have been found and I'm negotiating with sellers now. The rear suspension has been paid for and it should be done in a few weeks. The interior has been picked out and ordered. With any luck, I'll have a kick-ass new ride arriving sometime in June. In July, I hope to drive it in the Swan Valley 4th of July parade.

If you live in Colorado and would like to see it at a local event, I plan on showing (and racing!) it at the Colorado Bug-In at Bandimere Speedway. That's on Sunday, July 29th. In the meantime, it's gonna be pretty cool watching it come alive!

Posted in The Bus at Apr 30 2012, 07:59:52 AM MDT Add a Comment