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.

Integrating HTML5 Boilerplate with Scalate and Play

HTML5 Boilerplate is a project that provides a number of basic files to help you build an HTML5 application. At its core, it's an HTML template that puts CSS at the top, JavaScript at the bottom, installs Chrome Frame for IE6 users and leverages Modernizr for legacy browser support. It also includes jQuery with the download. One of the major benefits of HTML5 Boilerplate is it ships with a build system (powered by Ant) that concatenates and minimizes CSS and JS for maximum performance. From html5boilerplate.com:

Boilerplate is not a framework, nor does it prescribe any philosophy of development, it's just got some tricks to get your project off the ground quickly and right-footed.

I like the idea of its build system to minify and gzip, but I'd probably only use it if I was working on a project that uses Ant. Since I'm using it in a Play project, the whole Ant build system doesn't help me. Besides, I prefer something like wro4j. Wro4j allows you to specify a group of files and then it compiles, minimizes and gzips them all on-the-fly. As far as I know, Play doesn't have any support for Servlet Filters, so using wro4j in Play is not trivial.

The good news is Play has a GreenScript module that contains much of the wro4j functionality. However, since I'm using Scalate in my project, this goodness is unavailable to me. In the future, the Scalate Team is considering adding better wro4j, JavaScript and CSS integration. In the meantime, I'm going to pretend I don't care about concatenation and minimization and trundle along without this feature.

To add HTML5 Boilerplate to my Play project, I performed the following steps:

  • Downloaded the 2.0 Zipball.
  • Copied all the static files to my project. Below are the commands I used (where $boilerplate-download is the expanded download directory and ~/dev/play-more is my project):
    cd $boilerplate-download
    cp 404.html ~/dev/play-more/app/views/errors/404.html
    cp *.png ~/dev/play-more/public/.
    cp crossdomain.xml ~/dev/play-more/public/.
    cp -r css ~/dev/play-more/public/stylesheets/.
    cp favicon.ico ~/dev/play-more/public/.
    cp humans.txt ~/dev/play-more/public/.
    cp -r js/libs ~/dev/play-more/public/javascripts/.
    cp robots.txt ~/dev/play-more/public/.
    
  • Copied the index.html to ~/dev/play-more/app/templates/layouts/default.jade and modified it to use Jade syntax. Since I downloaded the comments-heavy version, I modified many of them to be hidden in the final output.
    -@ val body: String 
    -@ var title: String = "Play More"
    -@ var header: String = ""
    -@ var footer: String = ""
    !!! 5
    / paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ 
    <!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]-->
    <!--[if IE 7]>    <html class="no-js ie7 oldie" lang="en"> <![endif]-->
    <!--[if IE 8]>    <html class="no-js ie8 oldie" lang="en"> <![endif]-->
    -# Consider adding an manifest.appcache: h5bp.com/d/Offline 
    <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
    head
      meta(charset="utf-8")
    
      -# Use the .htaccess and remove these lines to avoid edge case issues. More info: h5bp.com/b/378 
      meta(http-equiv="X-UA-Compatible" content="IE=edge,chrome=1")
    
      title=title
      meta(name="description" content="")
      meta(name="author" content="Matt Raible ~ [email protected]")
    
      -# Mobile viewport optimized: j.mp/bplateviewport 
      meta(name="viewport" content="width=device-width,initial-scale=1")
    
      -# Place favicon.ico and apple-touch-icon.png in the root directory: mathiasbynens.be/notes/touch-icons
    
      -# CSS: implied media=all
      link(rel="stylesheet" href={uri("/public/stylesheets/style.css")})
      -# end CSS
    
      -# More ideas for your <head> here: h5bp.com/d/head-Tips 
      -#
        All JavaScript at the bottom, except for Modernizr / Respond.
        Modernizr enables HTML5 elements & feature detects; Respond is a polyfill for min/max-width CSS3 Media Queries
        For optimal performance, use a custom Modernizr build: www.modernizr.com/download/ 
    
      script(type="text/javascript" src={uri("/public/javascripts/libs/modernizr-2.0.6.min.js")})
    body
      #container
        header = header
        #main(role="main")
          != body
        footer = footer
    
      -# JavaScript at the bottom for fast page loading 
      
      / Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if offline 
      script(type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js")
      :javascript
        window.jQuery || document.write('<script src={uri("/public/javascripts/libs/jquery-1.6.2.min.js")}><\/script>')
    
      -# Change UA-XXXXX-X to be your site's ID 
      :javascript
        window._gaq = [['_setAccount','UA-25859875-1'],['_trackPageview'],['_trackPageLoadTime']];
        Modernizr.load({
          load: ('https:' == location.protocol ? '//ssl' : '//www') + '.google-analytics.com/ga.js'
        });
    
      -# Prompt IE 6 users to install Chrome Frame. Remove this if you want to support IE 6. 
      -# http://chromium.org/developers/how-tos/chrome-frame-getting-started 
      /[if lt IE 7]
        script(src="//ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js")
        :javascript
          window.attachEvent('onload',function(){CFInstall.check({mode:'overlay'})})
            
    != "</html>"
    
  • Next, I had to add support for layouts to my homegrown Scalate support. I did this by specifying a layoutStrategy when initializing the TemplateEngine. From play-more/app/controllers/ScalateTemplate.scala:
    engine.classLoader = Play.classloader
    engine.layoutStrategy = new DefaultLayoutStrategy(engine, 
      Play.getFile("/app/templates/layouts/default" + scalateType).getAbsolutePath)
    engine
    

That's it! Now I have HTML5 Boilerplate integrated into my Play/Scalate/Jade application. To set the title and header in my index.jade, I simply added the following lines at the top:

- attributes("title") = "Counting"
- attributes("header") = "HTML5 Rocks!"

CoffeeScript Tip
Yesterday, I mentioned that I was having issues getting CoffeeScript to work with Scalate and that I was going to try and get the in-browser compiler working. First of all, reverting to Scalate 1.4.1 didn't work because there is no CoffeeScript support in 1.4.1. So I stayed with 1.5.2 and used PandaWood's Running CoffeeScript In-Browser Tutorial. I copied coffee-script.js to ~/dev/play-more/public/javascripts/libs and added a reference to it in my default.jade layout:

-# JavaScript at the bottom for fast page loading 
script(type="text/javascript" src={uri("/public/javascripts/libs/coffee-script.js")})

Then I was able to write CoffeeScript in a .jade template using the following syntax:

:plain
  <script type="text/coffeescript">
    alert "hello world"
  </script>

Summary
If you've integrated HTML5 Boilerplate into your Play application, I'd love to hear about it. Now that I have all the infrastructure in place (Jade, CoffeeScript, HTML5 Boilerplate), I'm looking forward to getting some development done. Who knows, maybe I'll even come up with my own Play Un-Features That Really Irk My Inner Geek.

Posted in Java at Sep 28 2011, 08:49:35 AM MDT 2 Comments

Trying to make CoffeeScript work with Scalate and Play

A few weeks ago, I wrote about integrating Scalate with Play.

The next steps in my Play Scala adventure will be trying to get the CoffeeScript module to work. I also hope to integrate HTML5 Boilerplate with Jade and Scalate Layouts.

Since my last writing, the Scalate Team has created a new branch for Scala 2.8.x (that's compatible with Play) and released 1.5.2. To upgrade my Play application to use this version, I changed my dependencies.yml to have the following:

  - org.fusesource.scalate -> scalate-core 1.5.2-scala_2.8.1:
      transitive: false
  - org.fusesource.scalate -> scalate-util 1.5.2-scala_2.8.1:
      transitive: false

Unfortunately, this release breaks Scalate's CoffeeScript support because it wraps the code with illegal comments. This has been fixed in the latest snapshot, but no new release has been cut. However, even if it did work, it's not quite what I'm looking for. The 1.5.2 release allows for compiling inline CoffeeScript on-the-fly, but I'd rather store my .coffee files external to the page.

To try and figure out how to do this, I sent a message to the Scalate Google Group asking Does Scalate allow for referencing (and compiling) CoffeeScript files like the plugin for Play? My email prompted the Scalate Team to do some modifications that seemed to do exactly what I was looking for.

FWIW I've just checked in a couple of coffeescript examples. To run it, grab the code & do a local build...

http://scalate.fusesource.org/source.html
http://scalate.fusesource.org/building.html

then run this...
cd samples/scalate-example 
mvn jetty:run
then open http://localhost:8080/coffee/index

there are 2 sample jade files which use embedded coffee or a separate coffee file (using the .js extension in the <script src attribute>

https://github.com/scalate/scalate/tree/master/samples/scalate-exampl...

e.g. here's a jade file references a separate .js file for a coffee script which gets converted to .js on the server...

https://github.com/scalate/scalate/blob/master/samples/scalate-exampl...

To try out the improved CoffeeScript support, I checked out the source and fumbled with Git branches for a bit before I got latest version of Scalate to build. Unfortunately, it didn't work because Play doesn't know how to process the .js and .css files.

@67o8fflce 
Application.foo.js action not found 
Action not found 
Action Application.foo.js could not be found. Error raised is 
Controller controllers.Application.foo not found 
play.exceptions.ActionNotFoundException: Action Application.foo.js not 
found 
        at play.mvc.ActionInvoker.getActionMethod(ActionInvoker.java: 
588) 
        at play.mvc.ActionInvoker.resolve(ActionInvoker.java:85) 
        at Invocation.HTTP Request(Play!) 
Caused by: java.lang.Exception: Controller controllers.Application.foo 
not found 
        ... 3 more 
08:20:21,133 ERROR ~

Based on this error, I assumed I needed a Controller to do receive the .js and .css requests and compile them accordingly with Scalate. I changed my Jade template to have the following:

script(src="/assets/foo.js" type="text/javascript") 

Then I added a new route to my Play application:

  GET     /                           Application.index
  GET     /assets/{template}          ScalateResource.process

My ScalateResource.scala class is as follows:

package controllers 

import play.mvc._ 

object ScalateResource extends Controller { 

  def process(args: (Symbol, Any)*) = { 
    var template = params.get("template") 
    // replace .js with .coffee 
    template = template.replace(".js", ".coffee") 
    // replace .css with .scss 
    template = template.replace(".css", ".scss") 
    ScalateTemplate(template).render(); 
  } 
} 

Unfortunately, when I tried to access http://localhost:9000/assets/foo.js, I received the following error:

TemplateException occured : Not a template file extension (md | markdown | ssp | scaml | mustache | jade), you requested: coffee

At this point, I still haven't figured out how to solve this. I can only assume that the reason this works in the example application is because it uses a TemplateEngineFilter that's mapped to /*.

As I see it, I have a few choices if I want to continue using CoffeeScript and Scalate in my application:

  1. Revert to an older build of Scalate that uses the in-browser CoffeeScript compiler.
  2. Try to get a new version released that fixes the comment bug and use inline CoffeeScript.
  3. Keep trying to figure out how to get external files compiled by Scalate.

Obviously, I'd like to do #3 the most, but with the lack of responses from the Scalate group, this seems like the most challenging. Since #1 is the easiest (and I can complete without anyone's help), I'll be going that route for now. With any luck, the 2nd and third solutions will surface as options before my talk in November.

Update Oct 4, 2011: I was able to get external CoffeeScript files working! It was rather simple actually. I just tried the Play CoffeeScript module again, using Scalate's {uri("/path")} helper. For example, in a Jade template:

script(type="text/javascript" src={uri("/public/javascripts/script.coffee")})

This compiles the CoffeeScript file on the server and returns JavaScript. Sweet!

Posted in Java at Sep 27 2011, 01:59:18 PM MDT 3 Comments

Mahalo Kauai

I've heard great things about Hawaii for most of my life. My Dad was stationed at Barbers Point when he was in the Navy. His sister, my Aunt Mary, was born there. My sister and I sent my parents to Hawaii for their 30th Wedding Anniversary. You can imagine my excitement when Trish sent me an email on January 25th:

It's only 40,000 miles for both of us to fly to Kauai!! I picked the week after Labor Day just for fun :)

My response:

WAHOOOOOO! BOOK IT!!

She booked it that night. For $10.

We left for Kuaui the morning after the disappointing Broncos home opener and a fun sports weekend with Abbie and Jack. Our trip started out great, sneaking into the Red Carpet Club for free at LAX and getting a slew of free drinks from a super-cool flight attendant (Anthony) on our flight from LAX to Kauai.

After landing and marveling at the open-air airport, we picked up our rental Jeep and drove to the north side of the island. A friend recommended we stay at the St. Regis Princeville Resort and we were very impressed when we checked into our room overlooking Hanalei Bay.

The next morning, we vowed to do nothing but relax by the pool. We enjoyed a scrumptious breakfast at the Mekana Terrace, complete with Bloody Mary's. We had to have Bloody's since the St. Regis in NYC claims to have invented them. We spent the rest of the day napping, swimming, sunbathing, snorkeling and sipping on Mai Tai's.

Breakfast From the St. Regis Hanalei Bay The Pool Relaxing

After enjoying a beautiful sunset ...

HDR Sunset next to the palm trees on the beach at Hanalei Bay

... we visited the concierge to book some activities for the rest of our trip. We wanted to take things up a notch and enjoy all the cool stuff Kuai had to offer. So we arranged for Stand Up Paddling and the Mailani Dinner Shown on Thursday, golf on Friday, a doorless helicopter ride on Saturday and a kayak trip along the Na Pali coast on Sunday.

We woke up Thursday refreshed and ready to go. Our view out the window was exceptional.

Aloha in the morning at the St Regis Hanalei Bay

After a delicious room service breakfast in our room, we wandered down to the beach to meet our SUP guide. He warned us that girls were generally better than guys at SUP and we proceeded to prove him correct. Trish never got her hair wet and I had to abandon ship several times.

Ready for SUP! Breakfast with a view
Board Meeting

That afternoon, we headed to the The Kalalau Trail for a hike. Our SUP guide recommended it and said it was "so easy, your grandma could do it". His Grandma must be a lot younger than most, because the trail was not easy, but we certainly enjoyed the challenge.

Beautiful trail to Hanakapi'ai Beach and looking down the Napali Coast An easy 5' x 5' spot to land your helicopter?
Trish at Kalalau Beach Kalalau Beach

We were rewarded with some spectular views at Kalalau Beach.

Kalalau Beach Kalalau Beach

We made it back to the hotel just in time for the dinner show and another marvelous Hanalei sunset.

Hanalei Bay Sunset

At the dinner show, we sat with honeymooners from Houston that worked at NASA. Since they both spoke Russian, we had fun discussing Russia, our trips there and how we learned the language. The dinner show was great and they featured quite a few of the top Hula dancers in Hawaii.

Mailani Dinner show Hula dancer from side Kauai Mailani Dinner show Hula dancer with fire St Regis Kauai
Mailani Dinner show Hula dancers with Kala'au rhythm sticks and Hui'hui feathered rattles St Regis Kauai
Mailani Dinner show male performer St Regis Kauai
Mailani Dinner Show
Polynesian fireknife dancer with a fire knife Mailani Dinner Show
Mailani Dinner show firedancer with poi Kauai 3

The next morning, we grabbed Huevos Rancheros in Princeville and headed to the Makai Golf Club for a one-of-a-kind experience. Not only did they let us bring our full-stocked cooler on the course, but they rented us some fantastic Callaway clubs. We golfed for hours with no one in front, and no one trailing behind.

The famous third tee drop on the Makai Golf Course over looking Hanalei Bay Kauai - Matt's drive was perfect right onto the green below Makai Golf Club my pitch out of the sand is next to the pin.  Matt's is on the edge of the green :) Matt's drive headed toward the ravine on Makai Golf course!
This one is a gonner too! Heaven at Makai Golf Course!

Trish's photo of the Bougainvillia on the back nine is one of my favorites.

Bougainvillia on the Makai Golf course looking across Hanalei Bay

We enjoyed some Blue Hawaii's at the St. Regis afterward, in a cabana that's normally reserved for $1000/day. We snuck in and even got the honeymooner's discount from a hometown waiter.

2 Blue Hawai'i on the beach in Hanalei Bay

On Saturday, I booked a tour at the Ahonui Botanical Gardens. The gardens where amazing, built by Bill and Lucinda Robertson. They converted a jungle of 8 acres into an elaborate garden with trees, flowers and plants from around the world. Since you can grow almost anything on The Garden Isle, they planted many exotic fruit trees that we had the pleasure of snacking on throughout our 3-hour tour. About halfway through, Lucinda treated us to an adventure in making and tasting delicious chocolates.

Heart of Palm - Paul Michell uses this in their products - it's a wonderful clear light lotion and great for hair too! Ahonui Botanical Gardens Ahonui Botanical Gardens Whoa, this is an Apple banana native to Hawai'i and tastes much better than regular Del Monte bananas!

Lucinda Robertson gave us a great Chocolate tasting and history of chocolate.  The chocolate they made was the best of the bunch! Bill Robertson, the owner gave us the tour which they just started doing publically in June 2011.  It was a great experience!

We rushed from the garden tour to the helicopter ride on the other side of the island. The concierge had booked us with Jack Harter Helicopters, because they were the only ones that flew without doors (for better pictures). As soon as we lifted off, I knew it was going to be an experience of a lifetime. We flew over the Waimea Canyon, along the Na Pali Coast, over Hanalei Bay and back into the mountains to the wettest place on earth. It felt like an amusement park ride combined with an IMAX movie. Our pilot was a Hawaii native that knew the whole island and gave us an excellent tour of its features. I cannot recommend this tour enough if you're ever in Kauai.

Bell 500 here we come! Honopu Valley - King Kong was filmed in this area.

Rainbow to Kalalau Valley Napali Coast State Park

Looking back toward Makuaiki Point Wailua Falls - yep from Fantasy Island

The next morning, we had to get up early for our kayak trip. We had a wakeup call at 4:30, breakfast via room service arrived at 5 and we were packed and checked out of the hotel at 5:30. We arrived at Na Pali Kayak at 6 and quickly realized we had our work cut out for us. Both Trish and I expected the kayak trip to be like paddling across a lake and didn't know we were in for the Everest of kayaking - a 17-mile journey that would take most of the day.

Our Put in point for Napali Coast Kayak Tour.  I couldn't bring the D700 on the kayak and the waterproof camera was futile.  I thought they would have gotten better by now? We borrowed some sea-sickness medication, bought some water from our hosts and got ready for a good challenge. Unfortunately, we couldn't take Trish's camera, and the waterproof camera she bought took mediocre pictures. However, we did get to see two schools of dolphins (one even jumped into the air for us) and a couple turtles along the way. Having to paddle in unison turned out to be great couples therapy too.

We enjoyed lunch on a beach along the coast around 1, took a nap and hopped back in the boats for the last 5 miles. We pulled out around 4 and were on the road by 5 for the 2.5 hour drive back to Hanalei Bay. It was country dark when we arrived. We hopped in the Jeep and drove an hour back across the island to stay at the Sheraton Kauai (the St. Regis was full) for our last night.

At the Sheraton, we had one of their best rooms and enjoyed awesome views and a final relaxing day before heading home.

View from The Sheraton Hibiscus!

The Tunnel of Trees on the way to the airport was one last reminder of how beautiful Kauai is.

The Tunnel of Trees Kauai!

Mahalo Kauai. You are one of the most breathtaking places I have ever been too. Your views, your waves, your rainbows - all spectacular. Trish and I will be back, you've made an impression on us that will last forever.

If you'd like to see many of the places we visited in a movie, check out Soul Surfer. It takes place in Hanalei Bay and we recognized many of the locations while watching it. For more pictures, see my Shareholders Meeting in Kauai or Trish's magnificent photos.

Posted in General at Sep 26 2011, 10:19:54 AM MDT 3 Comments

Labor Day Weekend in Grand County

Labor Day is a great time of year in Colorado. It marks a transition from summer to fall, and it's often the last weekend to get good deals on ski passes. This year, we did it up right and spent the weekend at our ski shack in Grand County. My parents and kids joined us, as well as two of Trish and I's best college friends and their families. Normally, I'd just post pictures of this adventure, but we ate such excellent food and had so much fun boating, I figured I'd elaborate to recommend some super-fun (and delicious) activities.

Friday night, we enjoyed a scrumptious dinner at The Cheeky Monk in Winter Park Village and I fell in love with their Pasta Gorgonzola entree. Afterward, we snuggled with hot chocolate and shivered watching Tangled outside at the Family Movie Night.

Saturday, my Dad and I woke up early and headed to the Highland Marina on Lake Granby to pick up a rented fishing boat. We were on the lake by 8 and trolled through the foggy glass-like water for the headwaters of the Colorado river. A few hours later, the girls and kids joined us in a pontoon boat. Jack caught a fish around noon and you couldn't wipe the smile off his face for the rest of the day.

The delicious fish that Jack caught at Lake Granby

A Beautiful Day for Fishing Best Friends Montana Fan Get it Sagan! Happy Girls at Devil's Thumb Ranch

On Sunday, we visited Devil's Thumb Ranch for an afternoon of BBQ, beers, Kids Camp and Hiking. We journeyed from there to Tabernash Tavern for one of the best meals I've had in my entire life. If you like spicy food, you'll love their Twice Cooked Salmon.

My favorite activity of the weekend was fishing on Lake Granby. It was amazing to see how still Jack would sit while fishing and how much he wanted to do it all weekend. I don't think we'll get many more sunny and warm weekends in the mountains this year. Especially since our ski shack is located in the "Icebox of the Nation". But that's OK - I'm ready for the leaves to change, the start of football/hockey season and the snow to fall. Ski season is right around the corner! :)

For more pictures, see my Labor Day in Grand County set on Flickr.

Posted in General at Sep 09 2011, 08:49:01 AM MDT Add a Comment

Integrating Scalate and Jade with Play 1.2.3

At the beginning of this year, I decided I wanted to learn Scala. Since I'm a Web Frameworks Aficionado, I figured the best way to do that would be to learn Lift. I entered these two items on my todo list and let them lie for a couple months. After attending TSSJS 2011 and having a conversation with James Strachan, I added a couple more technologies to my learning list. James had great things to say about both CoffeeScript and Jade and I decided to learn those as well.

In May, Devoxx announced their Call For Papers and I started reminiscing about how awesome last year's trip was. I decided I'd try to get accepted again and started brainstorming about talks I'd like to give. I came up with "Comparing Scala Web Frameworks" and "HTML5 with Play Scala, CoffeeScript and Jade". The reason I chose Play over Lift for the latter talk is because I think it fits a lot more with the MVC mindset I have and the easy-to-learn nature of web frameworks I enjoy using. Both topics sounded very interesting to me, and I figured they'd also inspire me to learn the technologies in a brute-force fashion; where I was under a time constraint and would be embarrassed in front of a large audience if I didn't succeed.

In mid-July, I got an email from Stephan inviting me to speak again at the 10th edition of Devoxx. I smile splashed across my face and I quickly realized I had a lot to learn. Since I was still in vacation mode after summer vacation in Montana, I decided to wait until I returned from Cape Cod to start studying. While on my 2nd summer vacation, I received an email from Devoxx stating that they'd like me present "HTML5 with Play/Scala, CoffeeScript and Jade".

To learn all these technologies, I decided on an In Anger approach - where I would study minimally and learn mostly by doing. I ordered CoffeeScript on August 8th and Programming in Scala, 2nd Edition the following week (August 17th). I started reading both books while traveling the following week (I found CoffeeScript and Scala to be very similar, so I don't know if I'd recommend learning them at the same time). That same week, I started integrating Scalate (Jade) into a new Play Scala application.

Scalate advertises on their homepage that it works with Play via the play-scalate module. They neglect to mention that this module hasn't been updated in over a year or what version of Play it works with. I tried to use the scalate-0.7.2 version and quickly ran into issues. I posted a message to the Scalate Google Group explaining my compilation issues and stacktraces. The response? Crickets.

Next, I tried posting to the Play Google Group and got a much better response. Here's what they said:

Looking at the Scalate module code, I don't think it can work as is with Play Scala 0.9.1. The latest version is more than 1 year old, and we have made a lot of changes in the API.
...
The integration of Scalate is pretty difficult if you plan to get the same kind of experience than the native Play scala template regarding auto-reload and error reports.

You can try to port the module to 0.9.1, basically all it has to do is to provide a plugin that detect changes to scaml file, and recompile them. No special integration with the Play API is needed.

After learning that play-scalate was out-of-date, I contacted the project owner via GitHub and tried to get everything working with Play 1.2.3 and Scalate 1.5.1. I updated the dependencies in the project, fixed compilation issues and tried to build. No dice:

build: 
    [mkdir] Created dir: /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] Compiling 7 source files to /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] error: class file needed by Binding is missing. 
   [scalac] reference type Serializable of package scala refers to nonexisting symbol. 
   [scalac] one error found

I posted this error to the Play Group, discovered it was caused by Scalate 1.5.1 requiring Scala 2.9. I downgraded to Scalate 2.4.1 and got another nice cryptic error:

build: 
    [mkdir] Created dir: /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] Compiling 7 source files to /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] error: class file needed by ScalaController is missing. 
   [scalac] reference value dispatch of package <root> refers to nonexisting symbol. 
   [scalac] one error found

Apparently, this was caused by another Scala versioning issue and I was offered a much simpler solution for integrating Scalate. Below are the steps I performed to integrate Scalate 1.4.1 with Play 1.2.3.

  1. Updated dependencies.yml to references Scala and Scalate dependencies.
    require:
        - play
        - play -> scala 0.9.1
        - org.fusesource.scalate -> scalate-core 1.4.1:
            transitive: false
        - org.fusesource.scalate -> scalate-util 1.4.1:
            transitive: false
    
  2. Added Scalate configuration elements to application.conf.
    scalate=jade
    jvm.memory=-Xmx256M
    
  3. Created a ScalateTemplate class to contain the Scalate Engine and render the template.
    package controllers
    
    import play.Play
    
    object ScalateTemplate {
    
      import org.fusesource.scalate._
      import org.fusesource.scalate.util._
    
      lazy val scalateEngine = {
        val engine = new TemplateEngine
        engine.resourceLoader = new FileResourceLoader(Some(Play.getFile("/app/views")))
        engine.classpath = Play.getFile("/tmp/classes").getAbsolutePath
        engine.workingDirectory = Play.getFile("tmp")
        engine.combinedClassPath = true
        engine.classLoader = Play.classloader
        engine
      }
    
      case class Template(name: String) {
        val scalateType = "." + Play.configuration.get("scalate");
    
        def render(args: (Symbol, Any)*) = {
          scalateEngine.layout(name + scalateType, args.map {
            case (k, v) => k.name -> v
          } toMap)
        }
      }
    
      def apply(template: String) = Template(template)
    }
    
  4. Created a Scalate trait to override the render() method in Play's Controller class.
    package controllers
    
    import play.mvc.Http
    
    trait Scalate {
    
      def render(args: (Symbol, Any)*) = {
        def defaultTemplate = Http.Request.current().action.replace(".", "/")
        ScalateTemplate(defaultTemplate).render(args: _*);
      }
    }
    
  5. Created an Application.scala controller with a default index method.
    package controllers
    
    import play.mvc._
    import models._
    
    object Application extends Controller with Scalate {
    
      def index = {
        render('user -> User("Raible"))
      }
    }
    
    The models/User.scala class is very simple:
    package models
    
    case class User(name:String)
    
  6. Lastly, I created an index.jade file in views/Application.
    -@ var user: models.User
    p Hi #{user.name},
    - for(i <- 1 to 3)
      p= i
    p See, I can count!
    

After getting all this working, I decided it was time to get it into production. As luck would have it, Heroku had just announced Play support a few days earlier. I heard through the grapevine that Play Scala would work, so I gave it a try. It was amazingly easy. All I had to do was create an account, create a "Procfile" in my application's root directory and run a heroku command followed by a git push. It all looked great until Play tried to compile my Jade templates as Groovy templates:

Cannot start in PROD mode with errors 
Template compilation error (In /app/views/Application/index.jade around line 2) 
The template /app/views/Application/index.jade does not compile : #{user.name} is not closed. 
play.exceptions.TemplateCompilationException: #{user.name} is not closed. 
       at play.templates.TemplateCompiler.generate(TemplateCompiler.java:102) 
       at play.templates.TemplateCompiler.compile(TemplateCompiler.java:15) 
       at play.templates.GroovyTemplateCompiler.compile(GroovyTemplateCompiler.java:4 1)

The solution from Guillaume was simple enough and I renamed my "views" directory to "templates" and updated ScalateTemplate.scala accordingly. You can see the deployed application at http://play-more.herokuapp.com.

The next steps in my Play Scala adventure will be trying to get the CoffeeScript module to work. I also hope to integrate HTML5 Boilerplate with Jade and Scalate Layouts. I'll be doing this with the mindset that HTML and JavaScript aren't that bad. I expect a lot from CoffeeScript and Jade and hope I enjoy them as much as Strachan. ;-)

In the meantime, here's some interesting links I've seen recently encountered that discuss Scala and/or Play. I dig the passion and activity that exists in these communities.

Posted in Java at Sep 07 2011, 01:21:41 PM MDT 10 Comments

The Digital Diet

Digital Diet I don't remember the exact cause of my desire to throw the boy in the lake, but I remember the aftermath well. He did something that inspired me to rip off my shirt, empty my pockets and rush after him to give him a good solid dunking in the cold Montana water. It was obvious he deserved it and there was lots of laughs afterward that proved it was a good idea on my part. Shortly after getting dressed and refilling my pockets, I walked to my car to grab something out of the back. As I pulled my keys out to unlock it with the remote, I realized my keys were wet. This made me double-check the contents of my pockets and realize my iPhone was wet too. Apparently, when I emptied my pockets, all I'd removed was my wallet. The date was July 2nd, 2011.

It took me a couple days to confirm my iPhone was hosed. It was an iPhone 4 that I got on the day it was released, on the night before I left for my Montana Summer Vacation last year. It was also the night I met the lovely Trish McGinity. Since I knew the iPhone 5 was coming out in the next couple of months, I decided that if Apple wouldn't replace it, I'd go without a phone until the new iPhone came out. When I arrived back in Denver, I took it to the Apple Store and they confirmed it had "liquid damage." They said they'd replace it for $200. This was $200 less than I expected, but I decided to stay firm with my no-phone plan.

On that same trip in Montana, I decided to leave my car at The Cabin since I ride my bike to work everyday.

So I spent the last 2 months without a phone and without a car. I know, it's definitely a First World Problem. Poor me, I had to live without my Cadillac and iPhone for a whole 60 days. Regardless, I believe it was an interesting experiment and one that many technologists like myself might enjoy (or find it impossible to do).

It was interesting reverting to "old times" (the 90s) where you had to setup meeting times/places with friends and hope everyone met up on time. It was awesome that no one could contact me immediately and I could go about my day with little interruption. I found I had a lot more time because I wasn't constantly checking my Twitter or Facebook for updates. I found I had less stress because I never felt the urge to check for new emails.

Other than that, my life didn't change a whole lot. I rode my bike a lot more because of the no-car situation, logging 251 miles in July (with 2 weeks off for vacation) and 461 miles in August. I used Gmail to make phone calls, and checked my voice mail once a week to see if I was missing anything. I was able to plug in my water-logged phone and retrieve text messages every week or two (it'd stay on for about 30 seconds before dying again).

My parents arrived from Montana with my truck last night and I re-activated my iPhone 3G before driving to meet them in the mountains. I'm thankful for having my luxury items back, but I also realize that I shouldn't check my phone as much as I used to.

It wasn't until after I started this experiment that I discovered The Digital Diet and connected with the idea that Technology Is The New Smoking. I hope to stop being that guy that brings out his phone and checks for updates at family gatherings, when talking to my kids or when having lunch with friends. If you're addicted to your smart phone, I encourage you to try The Digital Diet. It's not that hard and there seems to be far more benefits than consequences.

Posted in General at Sep 02 2011, 04:14:46 PM MDT 1 Comment