<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" version="2.0">
  <channel>
    <title>Project Automation Experience</title>
    <link>http://projectautomationexperience.com</link>
    <description>The best value in the Java/Open Source conferencing space hands down</description>
    <item>
      <title>Algorithms for collaborative editing</title>
      <link>http://projectautomationexperience.com/blog/guillaume_laforge/2012/07/algorithms_for_collaborative_editing?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description />
      <pubDate>Mon, 09 Jul 2012 13:00:41 CDT</pubDate>
      <guid isPermaLink="true">algorithms-for-collaborative-editing</guid>
      <dc:creator>Guillaume LaForge</dc:creator>
    </item>
    <item>
      <title>We Want You!</title>
      <link>http://projectautomationexperience.com/blog/aaron_gustafson/2012/07/we_want_you_?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>We are looking for two talented folks to join our team here in Chattanooga. If you&amp;rsquo;re the kind of person that thrives on variety and&amp;nbsp;want to live &amp;amp; work in a really awesome city, read on&amp;hellip;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/EasyReader?a=Zqqv4S4e4LQ:XFQh6yrJFjU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EasyReader?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EasyReader?a=Zqqv4S4e4LQ:XFQh6yrJFjU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EasyReader?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EasyReader?a=Zqqv4S4e4LQ:XFQh6yrJFjU:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EasyReader?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EasyReader?a=Zqqv4S4e4LQ:XFQh6yrJFjU:JEwB19i1-c4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EasyReader?i=Zqqv4S4e4LQ:XFQh6yrJFjU:JEwB19i1-c4" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/EasyReader/~4/Zqqv4S4e4LQ" height="1" width="1"/&gt;</description>
      <pubDate>Mon, 09 Jul 2012 11:00:39 CDT</pubDate>
      <guid isPermaLink="true">http://blog.easy-designs.net/archives/2012/07/09/we-want-you/</guid>
      <dc:creator>Aaron Gustafson</dc:creator>
    </item>
    <item>
      <title>Minor new features of Groovy 2.0</title>
      <link>http://projectautomationexperience.com/blog/guillaume_laforge/2012/07/minor_new_features_of_groovy_2_0_1?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description />
      <pubDate>Sat, 07 Jul 2012 13:00:27 CDT</pubDate>
      <guid isPermaLink="true">minor-new-features-of-groovy-2-0</guid>
      <dc:creator>Guillaume LaForge</dc:creator>
    </item>
    <item>
      <title>Adding a license to source files</title>
      <link>http://projectautomationexperience.com/blog/kenneth_kousen/2012/07/adding_a_license_to_source_files?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;A few years ago I remember seeing a blog post by a person interviewing potential new developers. He said that when the prospect featured Java prominently on their resume, he would make sure to give them a programming test that would be easy to solve in a different language but hard in Java, just to see how they handled it. He normally used some sort of file manipulation as an example, because Java makes that particularly challenging while scripting languages often make those problems simple.&lt;/p&gt;
&lt;p&gt;About a week ago, someone contacted me about the source code from my book, &lt;a href="http://manning.com/kousen"&gt;Making Java Groovy&lt;/a&gt;. The source code is located at my GitHub repository, &lt;a href="https://github.com/kousen/Making-Java-Groovy"&gt;https://github.com/kousen/Making-Java-Groovy&lt;/a&gt;. The requester noted that I didn&amp;#8217;t have any sort of license file on my code and wondered what the terms were.&lt;/p&gt;
&lt;p&gt;Leaving aside the wonder that (1) somebody found the book code useful (ack! &lt;a href="http://www.urbandictionary.com/define.php?term=humblebrag"&gt;humblebrag&lt;/a&gt; alert!) and (2) he actually asked permission to use it, it occurred to me I really ought to have something in place for that eventuality. I asked my editor at Manning about it and she didn&amp;#8217;t answer right away, so I interpreted that as freedom to do whatever I wanted. &lt;img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt; &lt;/p&gt;
&lt;p&gt;A friend on a mailing list suggested that &lt;a href="http://www.apache.org/licenses/LICENSE-2.0"&gt;the Apache 2 license&lt;/a&gt; is appropriate if I don&amp;#8217;t care too much how the code is used (and I don&amp;#8217;t), so I decided to add that license to each source file. That brings me, at long last, to the original subject of this post: how do I add a license statement to the top of a large number of source files nested in many subdirectories?&lt;/p&gt;
&lt;p&gt;I thought I would solve the problem with the &lt;code&gt;eachFileRecurse&lt;/code&gt; method that Groovy adds to Java&amp;#8217;s &lt;code&gt;java.io.File&lt;/code&gt; class. I quickly realized, though, that there were directories I wanted to skip, and that lead me to the &lt;code&gt;traverse&lt;/code&gt; method, which takes a &lt;code&gt;Map&lt;/code&gt; of parameters.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the result:&lt;br /&gt;
&lt;pre class="brush: groovy;"&gt;
import static groovy.io.FileType.*
import static groovy.io.FileVisitResult.*
String license = '''/* ===================================================
 * Copyright 2012 Kousen IT, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */
'''
dir = '/Users/kousen/mjg'
new File(dir).traverse(
    type       : FILES, 
    nameFilter : ~/.*(java|groovy)$/,
    preDir     : { if (it.name == '.metadata') return SKIP_SUBTREE }) { file -&amp;gt;
    // only add license if not already there
    if (!file.text.contains(license)) {
        def source = file.text
        file.text = &amp;quot;$license$source&amp;quot;
    }
    assert file.text.contains(license)
}
&lt;/pre&gt;&lt;br /&gt;
I used static imports for the &lt;code&gt;FileType&lt;/code&gt; and &lt;code&gt;FileVisitResult&lt;/code&gt; classes. The &lt;code&gt;FILES&lt;/code&gt; constant comes from &lt;code&gt;FileType&lt;/code&gt;, and the &lt;code&gt;SKIP_SUBTREE&lt;/code&gt; constant comes from &lt;code&gt;FileVisitResult&lt;/code&gt;. The parameters I used return only files whose name ends in either &amp;#8216;java&amp;#8217; or &amp;#8216;groovy&amp;#8217; and aren&amp;#8217;t in any directory tree including &amp;#8216;.metadata&amp;#8217;.&lt;/p&gt;
&lt;p&gt;Ultimately everything is based on the &lt;code&gt;getText&lt;/code&gt; and &lt;code&gt;setText&lt;/code&gt; methods that the Groovy JDK adds to the &lt;code&gt;java.io.File&lt;/code&gt; class. Both are called using the &lt;code&gt;text&lt;/code&gt; property. The &lt;code&gt;getText&lt;/code&gt; method returns all the existing source code, and the &lt;code&gt;setText&lt;/code&gt; method acts as an alias for the &lt;code&gt;write&lt;/code&gt; method, which automatically closes (and therefore flushes) the file when finished. I used a multiline string for the license and included the training carriage return, so writing the license followed by the source did the trick.&lt;/p&gt;
&lt;p&gt;The documentation for these methods is, shall we say, a little thin. I therefore did what I normally do in these situations: I found the test case in the Groovy source distribution. The test in question is called &lt;code&gt;FileTest&lt;/code&gt; and can be viewed in the Groovy GitHub repository &lt;a href="https://github.com/groovy/groovy-core/blob/master/src/test/groovy/FileTest.groovy"&gt;here&lt;/a&gt;. The test cases showed how to use all of the methods, including &lt;code&gt;traverse&lt;/code&gt;, so it was just a question of looking for the right example.&lt;/p&gt;
&lt;p&gt;(Incidentally, one of the less publicized but really sweet features of GitHub is the code browser. Just find the project you want and dig into the directories until you find a file, and then GitHub provides syntax highlighting and everything. It&amp;#8217;s a great, great feature, especially if you don&amp;#8217;t want to clone the source of every project you care about onto your own local disk.)&lt;/p&gt;
&lt;p&gt;Since I hadn&amp;#8217;t known about the &lt;code&gt;traverse&lt;/code&gt; method ahead of time, and I messed up the regular expressions for a while (sigh), solving the problem took longer than I expected. Still, it&amp;#8217;s hard to beat a solution that takes less than a dozen lines. Hopefully someone else will find this helpful as well. And regarding the job interview situation described above, to paraphrase &lt;a href="http://en.wikipedia.org/wiki/Let_It_Be_(film)"&gt;John Lennon in the rooftop concert at the end of &lt;em&gt;Let It Be&lt;/em&gt;&lt;/a&gt;, on behalf of Groovy and myself, I hope I passed the audition.&lt;/p&gt;
&lt;br /&gt;  &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/367/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/367/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/367/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/367/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/kousenit.wordpress.com/367/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/kousenit.wordpress.com/367/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/kousenit.wordpress.com/367/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/kousenit.wordpress.com/367/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/367/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/367/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/367/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/367/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/367/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/367/" /&gt;&lt;/a&gt; &lt;img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&amp;#038;blog=186706&amp;#038;post=367&amp;#038;subd=kousenit&amp;#038;ref=&amp;#038;feed=1" width="1" height="1" /&gt;</description>
      <pubDate>Sat, 07 Jul 2012 08:00:37 CDT</pubDate>
      <guid isPermaLink="true">http://kousenit.wordpress.com/?p=367</guid>
      <dc:creator>Kenneth Kousen</dc:creator>
    </item>
    <item>
      <title>Agile and DevOps, A Perfect Match</title>
      <link>http://projectautomationexperience.com/blog/bruce_snyder/2012/07/agile_and_devops_a_perfect_match?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-BWn35N8z4dE/T_cusPlF1iI/AAAAAAAABIk/2rZsLki1C9I/s1600/stones.jpg" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" height="150" width="200" src="http://3.bp.blogspot.com/-BWn35N8z4dE/T_cusPlF1iI/AAAAAAAABIk/2rZsLki1C9I/s200/stones.jpg" /&gt;&lt;/a&gt;&lt;/div&gt; Through the years in my career, I have spent a fair amount of my time advising customers on agile software development. Having practiced various agile software development methodologies since the late 1990s, I've witnessed many implementations of agile, both successful and not so successful. In more recent years, the notion of agile has expanded across organizational boundaries and given way to a newer concept known as DevOps. While these two topics dovetail nicely and my years of past experience are relevant here, interesting questions always arise. Consider the following question that I received recently:  &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Question&lt;/h3&gt;&lt;i&gt;What are the migration milestones in building out a DevOps group?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;I suggest that this question be reframed a bit. For an organization to enter the world of DevOps means that one must adopt a mindset that is focused on agility in the processes and the methods used to execute those processes. It is very important that you identify the best way of carrying out that mindset across your organization and that it include not only software engineering, but also the customer, the business folks, quality engineering, test automation, release management, security, operations, system administration, etc. DevOps is about a fundamental reorientation to provide software in a more effective manner beginning with design and going all the way to production deployment.   &lt;br /&gt;&lt;h3&gt;Remember SOA?&lt;/h3&gt;I will draw an analogy here to a recent trend in software architecture. The concept of a service-oriented architecture (SOA) embodies a set of principles for designing and developing software. It's the 'why', not the 'how' of software architecture (i.e., SOA is a means to an end, not an end in itself). Numerous vendors took the SOA term and twisted this notion into a wrong-headed marketing message that basically said, 'Buy our software and you will be doing SOA'. I spent a lot of time dispelling this myth over the last several years, encountering much resistance along the way. But make no mistake, SOA is not a technology problem.&lt;br /&gt;&lt;br /&gt;If someone asked me about forming a SOA group inside their company, I would tell them that they already have one and it encompasses the customer, the software architects, the software engineers, the quality engineers, the release engineers, the security experts, and the operations folks. There is no need to assemble a brand new group. Would you advocate the formation of an agile group inside a company? I certainly would not because interpreting a methodology in such a literal fashion seems to me like you are already driving the car into the ditch and through the corn field. When I was a kid I learned a term for stuff like this, an Arkansas screwdriver (also known as a hammer). Just because you can doesn't mean you should.&lt;br /&gt;&lt;br /&gt;Over the years, I have worked with many companies to get them on the road toward designing applications by using SOA. When I do this, I lead the customer toward the identification of folks across the organization who can participate in this effort. I was certainly not alone in this effort and this style as there are many others doing the same/similar thing. Although we operated on the idea that we were coaching customers to develop apps using SOA via agile methodologies, I now realize that we were also already leaning toward DevOps. (Based on my research, this is really how the DevOps movement came to be what it is today.)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;A Perfect Match&lt;/h3&gt;Getting back to the original question, I would not approach DevOps any differently than I have approached the coaching of customers into the use of agile methodologies. Continue to coach customers in this manner and you will be successful. Only now, we have even more information and wisdom telling us that this is not just for software engineers. This is a fundamental change for an organization and should be broken down as described on the &lt;a href="http://theagileadmin.com/what-is-devops/"&gt;Agile Admin blog&lt;/a&gt; like so: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Agile principles: The core values that form the agile movement (see the &lt;a href="http://agilemanifesto.org/"&gt;Agile Manifesto&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Agile methods: Methodologies for running an agile approach including Kanban, Lean, SCRUM, XP, etc.&lt;/li&gt;&lt;li&gt;Agile practices: Procedures for executing an agile methodology including &lt;a href="http://guide.agilealliance.org/guide/acceptance.html"&gt;Acceptance Testing&lt;/a&gt;, &lt;a href="http://guide.agilealliance.org/guide/bdd.html"&gt;BDD&lt;/a&gt;, &lt;a href="http://guide.agilealliance.org/guide/tdd.html"&gt;TDD&lt;/a&gt;, &lt;a href="http://guide.agilealliance.org/guide/stories.html"&gt;User Stories&lt;/a&gt;, &lt;a href="http://guide.agilealliance.org/guide/ci.html"&gt;Continuous Integration&lt;/a&gt;, &lt;a href="http://guide.agilealliance.org/guide/cd.html"&gt;Continuous Deployment&lt;/a&gt;, &lt;a href="http://guide.agilealliance.org/guide/daily.html"&gt;Daily Meetings&lt;/a&gt; (aka Standup Meetings), etc. etc.&lt;/li&gt;&lt;/ul&gt;I tend to think about DevOps in the same way that I think about agile or even SOA, but with a bit more reach across the organization. That is, DevOps is a set of principles for designing, developing, testing, deploying and supporting software. Each role will utilize different tools but they will all be involved in the overall software development lifecycle. DevOps is also a means to an end, not an end in itself. Some of it's main differences are that it cuts across an organization even further to include many roles and people, and it considers software development as a full lifecycle instead of only focusing on the software until its a teenager and then throwing it over the wall to operations and hoping it survives. &lt;br /&gt;&lt;h3&gt;The Value of DevOps to the Business&lt;/h3&gt;Finally, the value of DevOps to the business is often misunderstood or not understood at all. Historically, the business side has treated software development as someone else's problem. The perception has often been that the propeller heads down the hall are responsible for the software, not the business side. This has always struck me as terribly short-sighted, especially for a company that would not make money without its software.&lt;br /&gt;&lt;br /&gt;Consider another analogy here to depict this situation appropriately. Businesses love to equate themselves to sports teams and I've heard this one before, so I'll use the idea of a pro cycling race team (please forgive my cycling fever during this Tour de France season). A pro cycling team operates in a smooth, fluid manner handling anomalies as they arise without disruption. Like any good team it has the following characteristics: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;A clear direction with clear support and resources from the business side&lt;/li&gt;&lt;li&gt;Team members have a good relationship with one another and with supporting companies or organizations&lt;/li&gt;&lt;li&gt;The team monitors many external factors that effect their performance and their success&lt;/li&gt;&lt;/ul&gt;Although a pro cycling team has its recognizable personalities in the riders, there are many more people behind the scenes who make them successful. Without the entire team working as one they will not be successful or will be less successful than they planned. The team sponsors, the directors, the managers, the mechanics, the masseuses, the assistants, the domestiques, and the recognized riders all must be in tune and ready for success. They each have well-defined roles and operate in tandem across organizational gaps to be the very best at everything in pro cycling. I don't believe that these teams would be successful if they did not include everyone in the orchestration. There's also certainly a lot of luck that needs to be on their side to be successful, quite like the business world. &lt;br /&gt;&lt;br /&gt;A company that relies on its software to make money is very much the same. Consider the following comparisons: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Just as a pro cycling team has a clearly defined direction, so should a company that relies upon software. This message needs to be tuned appropriately to fit different areas of the business, but the overarching message remains – create a machine to make money.&lt;/li&gt;&lt;li&gt;Just as a pro cycling team has clear support from the business side to stay on top of the technology in its field, so should a company that relies upon software. This means that time must be dedicated to the craft of building software, continued education where necessary, the purchase of materials (books, publications, etc.) and tools, etc. Do you want excellent, highly talented mechanics, masseuses and domestiques or just mediocre ones?&lt;/li&gt;&lt;li&gt;Just as a pro cycling team forms close relationships between team members, so should a company that relies upon software. This doesn't just apply to folks who work in the same department. The most important relationships are those that span boundaries and break down barriers between departments within an organization.&lt;/li&gt;&lt;li&gt;Just as a pro cycling team learns to execute flawlessly together, so should a company that relies upon software. Consider that the software a business relies upon to make money is the bike and the rider that a pro cycling team chooses. Do you think that the pro cycling team just arbitrarily decides how to prepare and train for events? Or do you think the pro cycling team has a strict, regimented formula to its training and preparation? A business that relies upon software to make money should also have a strict, regimented formula for crafting, testing, deploying and supporting it's software. Without this level of capability, the ability of the business to make money on a consistent basis is hamstrung by its own processes or lack thereof.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;The bottom line is this: A business that deems its software to be critical needs the ability to get that software to market in a consistent, repeatable manner every time. Period. How can this be achieved without involving all of the parties who touch that software in some way?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9088482399688345277-8588853824067943036?l=bsnyderblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 06 Jul 2012 16:02:28 CDT</pubDate>
      <guid isPermaLink="true">tag:blogger.com,1999:blog-9088482399688345277.post-8588853824067943036</guid>
      <dc:creator>Bruce Snyder</dc:creator>
    </item>
    <item>
      <title>Updates for the Grails App Info plugin</title>
      <link>http://projectautomationexperience.com/blog/burt_beckwith/2012/07/updates_for_the_grails_app_info_plugin?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;The &lt;a target="_blank" href="http://grails.org/plugin/app-info"&gt;app-info&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; plugin wasn&amp;#8217;t working in Grails 2.0+ because of an incompatibility between the Hibernate Tools jar and the version of Hibernate that Grails uses. So I split out the Hibernate-related functionality from the plugin into a to-be-released app-info-hibernate plugin, and once they release an updated version of Hibernate Tools I&amp;#8217;ll be able to finish and release that. This also affected the &lt;a target="_blank" href="http://grails.org/plugin/db-reverse-engineer"&gt;db-reverse-engineer&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; plugin but I was able to fix that with a hackish solution since that runs as a script (I fork a new process with a separate classpath) but that approach wasn&amp;#8217;t feasible for this plugin.&lt;/p&gt;
&lt;p&gt;The &lt;a target="_blank" href="/blog/?p=344"&gt;original blog post&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; is still mostly valid but I wanted to point out some new features and make an updated test application available.&lt;/p&gt;
&lt;p&gt;You install the plugin like any other, by including a dependency for it in &lt;code&gt;BuildConfig.groovy&lt;/code&gt;, e.g.&lt;/p&gt;
&lt;pre class="brush: java; title: ; notranslate"&gt;
plugins {
   ...

   compile ':app-info:1.0.1'
}
&lt;/pre&gt;
&lt;p&gt;The plugin depends on the &lt;a target="_blank" href="http://grails.org/plugin/dynamic-controller"&gt;dynamic-controller&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; plugin to configure what features are available, so you need to configure the active mixins in &lt;code&gt;Config.groovy&lt;/code&gt; (omit any you don&amp;#8217;t need):&lt;/p&gt;
&lt;pre class="brush: java; title: ; notranslate"&gt;
grails.plugins.dynamicController.mixins = [
   'com.burtbeckwith.grails.plugins.appinfo.IndexControllerMixin':
      'com.burtbeckwith.appinfo_test.AdminManageController',

   'com.burtbeckwith.grails.plugins.appinfo.Log4jControllerMixin' :
      'com.burtbeckwith.appinfo_test.AdminManageController',

   'com.burtbeckwith.grails.plugins.appinfo.SpringControllerMixin' :
      'com.burtbeckwith.appinfo_test.AdminManageController',

   'com.burtbeckwith.grails.plugins.appinfo.MemoryControllerMixin' :
      'com.burtbeckwith.appinfo_test.AdminManageController',

   'com.burtbeckwith.grails.plugins.appinfo.PropertiesControllerMixin' :
      'com.burtbeckwith.appinfo_test.AdminManageController',

   'com.burtbeckwith.grails.plugins.appinfo.ScopesControllerMixin' :
      'com.burtbeckwith.appinfo_test.AdminManageController',

   'com.burtbeckwith.grails.plugins.appinfo.ThreadsControllerMixin' :
      'com.burtbeckwith.appinfo_test.AdminManageController',

   'app.info.custom.example.MyConfigControllerMixin' :
      'com.burtbeckwith.appinfo_test.AdminManageController'
]
&lt;/pre&gt;
&lt;p&gt;This configures a dynamic &lt;code&gt;AdminManagerController&lt;/code&gt; and I like to map its urls to &lt;code&gt;/admin/manage&lt;/code&gt;, so I add these lines to &lt;code&gt;UrlMappings.groovy&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="brush: java; title: ; notranslate"&gt;
&amp;quot;/admin/manage/$action?&amp;quot;(controller: &amp;quot;adminManage&amp;quot;)
&amp;quot;/adminManage/$action?&amp;quot;(controller: &amp;quot;errors&amp;quot;, action: &amp;quot;urlMapping&amp;quot;)

&amp;quot;403&amp;quot;(controller: &amp;quot;errors&amp;quot;, action: &amp;quot;accessDenied&amp;quot;)
&amp;quot;404&amp;quot;(controller: &amp;quot;errors&amp;quot;, action: &amp;quot;notFound&amp;quot;)
&amp;quot;405&amp;quot;(controller: &amp;quot;errors&amp;quot;, action: &amp;quot;notAllowed&amp;quot;)
&amp;quot;500&amp;quot;(controller: &amp;quot;errors&amp;quot;, action: &amp;quot;error&amp;quot;)
&lt;/pre&gt;
&lt;p&gt;The first is the expected mapping, and the second &amp;#8220;un-maps&amp;#8221; the one that gets auto-created by the &lt;code&gt;"/$controller/$action?/$id?"&lt;/code&gt; rule. It does this by using the &lt;code&gt;urlMapping&lt;/code&gt; action in &lt;code&gt;ErrorsController&lt;/code&gt; (see the test app for the source) to send a 404 error code. Since I&amp;#8217;m using a controller for this, I also map the standard error codes to be able to have custom GSPs for each.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re using the &lt;a target="_blank" href="http://grails.org/plugin/spring-security-core"&gt;spring-security-core&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; plugin you can then guard access to all the plugin&amp;#8217;s actions with one mapping:&lt;/p&gt;
&lt;pre class="brush: java; title: ; notranslate"&gt;
grails.plugins.springsecurity.controllerAnnotations.staticRules = [
   '/adminmanage/**': ['ROLE_ADMIN']
]
&lt;/pre&gt;
&lt;p&gt;The plugin also includes a configuration demonstrating the new support for adding extra menu items (see &lt;a target="_blank" href="http://jira.grails.org/browse/GPAPPINFO-19"&gt;GPAPPINFO-19&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt;) so the test app includes the &lt;code&gt;app.info.custom.example.MyConfig&lt;/code&gt; class in &lt;code&gt;src/groovy&lt;/code&gt;, the &lt;code&gt;app.info.custom.example.MyConfigControllerMixin&lt;/code&gt; mixin in &lt;code&gt;grails-app/controllerMixins&lt;/code&gt;, and the &lt;code&gt;views/myconfig/configs.gsp&lt;/code&gt; GSP. This is all plugged in with this configuration in &lt;code&gt;Config.groovy&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="brush: java; title: ; notranslate"&gt;
grails.plugins.appinfo.additional = [
   &amp;quot;My Config&amp;quot;: [
      configs: &amp;quot;Configs&amp;quot;
   ]
]
&lt;/pre&gt;
&lt;p&gt;There&amp;#8217;s also a new thread dump mixin (see &lt;a target="_blank" href="http://jira.grails.org/browse/GPAPPINFO-20"&gt;GPAPPINFO-20&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt;) and this is enabled by configuring &lt;code&gt;ThreadsControllerMixin&lt;/code&gt; (see the &lt;code&gt;grails.plugins.dynamicController.mixins&lt;/code&gt; config map above). The menu item is &amp;#8220;Thread Dump&amp;#8221; in the Info menu.&lt;/p&gt;
&lt;p&gt;You can download the test application (it uses Grails 2.0.4) &lt;a target="_blank" href="/blog/files/1457/appinfodemo.zip"&gt;here&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt;. Once it&amp;#8217;s running navigate to &lt;a target="_blank" href="http://localhost:8080/appinfodemo/admin/manage/"&gt;http://localhost:8080/appinfodemo/admin/manage/&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; and authenticate as admin/password to try it out.&lt;/p&gt;
&lt;p&gt;&lt;a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fburtbeckwith.com%2Fblog%2F%3Fp%3D1457&amp;amp;title=Updates%20for%20the%20Grails%20App%20Info%20plugin" id="wpa2a_2"&gt;&lt;img src="http://burtbeckwith.com/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://burtbeckwith.com/blog/?flattrss_redirect&amp;amp;id=1457&amp;amp;md5=9bd6da7b78e138538dd3fb4e88221257" title="Flattr" target="_blank"&gt;&lt;img src="https://burtbeckwith.com/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Fri, 06 Jul 2012 11:05:54 CDT</pubDate>
      <guid isPermaLink="true">http://burtbeckwith.com/blog/?p=1457</guid>
      <dc:creator>Burt Beckwith</dc:creator>
    </item>
    <item>
      <title>Tiggzi at Bootstrap Week: Lectures for Mobile Devs</title>
      <link>http://projectautomationexperience.com/blog/max_katz/2012/07/tiggzi_at_bootstrap_week_lectures_for_mobile_devs?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;&lt;img src="http://mkblog.exadel.com/wp-content/uploads/2012/07/Selection_752.png" alt="" title="Selection_752" width="600" height="96" class="alignnone size-full wp-image-5087" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bootstrapweek.com/" target="_blank"&gt;Bootstrap Week&lt;/a&gt; is one week in a month were a bunch of really cool companies and services give presentations and provide help on everything mobile related. Definitely check it out, you will find a lot of interesting stuff. &lt;/p&gt;
&lt;p&gt;Tiggzi is part of the Bootstrap Week. You may &lt;a href="http://bootstraptiggzi-w2.eventbrite.com/" target="_blank"&gt;sign up&lt;/a&gt; for the Tiggzi session. Just notice that Tiggzi session is on &lt;strong&gt;Tuesday, July 10, 2012 from 12:00 PM to 1:00 PM (PT)&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;I will be showing how to build HTML5/jQuery Mobile apps as our new and just launched Tiggzi Database. &lt;/p&gt;</description>
      <pubDate>Fri, 06 Jul 2012 08:01:58 CDT</pubDate>
      <guid isPermaLink="true">http://mkblog.exadel.com/?p=5086</guid>
      <dc:creator>Max Katz</dc:creator>
    </item>
    <item>
      <title>Building your Groovy 2.0 projects with Maven</title>
      <link>http://projectautomationexperience.com/blog/guillaume_laforge/2012/07/building_your_groovy_2_0_projects_with_maven?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description />
      <pubDate>Wed, 04 Jul 2012 13:00:21 CDT</pubDate>
      <guid isPermaLink="true">building-your-groovy-2-0-projects-with-maven</guid>
      <dc:creator>Guillaume LaForge</dc:creator>
    </item>
    <item>
      <title>Minor new features of Groovy 2.0</title>
      <link>http://projectautomationexperience.com/blog/guillaume_laforge/2012/07/minor_new_features_of_groovy_2_0?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description />
      <pubDate>Wed, 04 Jul 2012 11:00:53 CDT</pubDate>
      <guid isPermaLink="true">minor-new-features-of-groovy-2-0</guid>
      <dc:creator>Guillaume LaForge</dc:creator>
    </item>
    <item>
      <title>Groovy 2.0 support in Eclipse</title>
      <link>http://projectautomationexperience.com/blog/guillaume_laforge/2012/07/groovy_2_0_support_in_eclipse?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description />
      <pubDate>Wed, 04 Jul 2012 08:00:52 CDT</pubDate>
      <guid isPermaLink="true">groovy-2-0-support-in-eclipse</guid>
      <dc:creator>Guillaume LaForge</dc:creator>
    </item>
    <item>
      <title>Oh the Places You'll Go!</title>
      <link>http://projectautomationexperience.com/blog/rod_johnson/2012/07/oh_the_places_you_ll_go_?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>The last ten years has been an exciting and challenging journey for me and I’m very proud of the technology and community that my SpringSource cofounders and I fostered. However, there always comes a time to make a choice about the places you’ll go, and it’s time for me to leave VMware and pursue other  &lt;a href="http://blog.springsource.org/2012/07/03/oh-the-places-youll-go/"&gt;&lt;em&gt;Read more...&lt;/em&gt;&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/SpringSourceTeamBlog/~4/j3qkpViP3q8" height="1" width="1"/&gt;&lt;img src="http://feeds.feedburner.com/~r/SpringSourceTeamBlog/~4/E_WTetyPfVQ" height="1" width="1"/&gt;&lt;img src="http://feeds.feedburner.com/~r/SpringSourceTeamBlog/~4/NRp4B-O6g8o" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 03 Jul 2012 16:00:26 CDT</pubDate>
      <guid isPermaLink="true">http://blog.springsource.org/?p=11259</guid>
      <dc:creator>Rod Johnson</dc:creator>
    </item>
    <item>
      <title>This Week in Grails (2012-26)</title>
      <link>http://projectautomationexperience.com/blog/burt_beckwith/2012/07/this_week_in_grails_2012_26_?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;My apologies for not doing a post last week; I was traveling (doing two &lt;a target="_blank" href="http://www.springsource.com/training/course?courseID=18353"&gt;Groovy and Grails courses&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; back-to-back) and didn&amp;#8217;t have time.&lt;/p&gt;
&lt;p&gt;The big news of the last two weeks is the &lt;a target="_blank" href="https://glaforge.appspot.com/article/groovy-2-0-released"&gt;Groovy 2.0 release&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt;. Lots of cool stuff there including static type checking, static compilation, modularity, and Invoke Dynamic support. Check out &lt;a target="_blank" href="http://www.jroller.com/melix/entry/groovy_2_0_from_an"&gt;Cédric Champeau&amp;#8217;s &amp;#8220;Groovy 2.0 from an insider&amp;#8221;&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; post, &lt;a target="_blank" href="http://blog.andresteingress.com/2012/06/29/groovy-2-0-love-for-grails-command-objects/"&gt;Andre Steingress&amp;#8217; &amp;#8220;Groovy 2.0: Love for Grails Command Objects&amp;#8221;&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; post, and this older post based on a 2.0 RC, &lt;a target='_blank' href='http://www.intelligrape.com/blog/2012/03/22/writing-sentences-with-groovy-2-0/'&gt;Writing sentences with Groovy 2.0&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Grails 2.1 RC3 &lt;a target="_blank" href="http://grails.org/2.1.0.RC3+Release+Notes"&gt;was released&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; and the 2.1 GA release will be out soon. Test it now to get an early start on your upgrade and to help find any remaining issues.&lt;/p&gt;
&lt;p&gt;Matt Raible and James Ward did a &lt;a target='_blank' href='http://cloud.dzone.com/articles/play-vs-grails-smackdown'&gt;Play vs. Grails Smackdown&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; at ÜberConf. The Grails version of the app did very well, especially considering all of the Play/Scala fanboy hype that we&amp;#8217;ve had to put up with.&lt;/p&gt;
&lt;p&gt;Netflix open sourced their Grails-based Asgard management and deployment app.&lt;br /&gt;
&lt;a target="_blank" href="http://techblog.netflix.com/2012/06/asgard-web-based-cloud-management-and.html"&gt;Asgard&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt;. They&amp;#8217;re also hiring a Grails developer (see the Jobs section for the link and details).&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;If you want to keep up with these &amp;#8220;This Week in Grails&amp;#8221; posts you can access them directly via their &lt;a target="_blank" href="http://burtbeckwith.com/blog/?cat=32"&gt;category link&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; or in an RSS reader with &lt;a target="_blank" href="http://feeds.feedburner.com/this-week-in-grails"&gt;the feed&lt;img src="/blog/images/pop.gif"/&gt;&lt;/a&gt; for just these posts.&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;Translations of this post:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.javahispano.org/groovy-grails/2012/7/2/esta-semana-en-grails-2012-26.html'&gt;Traducción al español&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://groovyq.net/content/grails%E6%AF%8F%E5%91%A8%E8%A7%82%E5%AF%9F%EF%BC%882012-26%EF%BC%89'&gt;Grails每周观察&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://remoteexception.blogspot.pt/2012/07/semana-grails-2012-26.html'&gt;Este artigo em Português&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.jp/news/2012-26.html'&gt;今週のGrails日本語版&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr/&gt;
&lt;div class="toc"&gt;
&lt;img src="/blog/images/folder_go.png"/&gt;&amp;nbsp;&lt;a href="#miscellaneous"&gt;Miscellaneous Items&lt;/a&gt;&lt;br /&gt;
&lt;img src="/blog/images/folder_go.png"/&gt;&amp;nbsp;&lt;a href="#plugins"&gt;Plugins&lt;/a&gt;&lt;br /&gt;
&lt;img src="/blog/images/folder_go.png"/&gt;&amp;nbsp;&lt;a href="#tweets"&gt;Interesting Tweets&lt;/a&gt;&lt;br /&gt;
&lt;img src="/blog/images/folder_go.png"/&gt;&amp;nbsp;&lt;a href="#jobs"&gt;Jobs&lt;/a&gt;&lt;br /&gt;
&lt;img src="/blog/images/folder_go.png"/&gt;&amp;nbsp;&lt;a href="#meetups"&gt;User groups and Conferences&lt;/a&gt;
&lt;/div&gt;
&lt;hr/&gt;
&lt;div id="miscellaneous"&gt;
&lt;h2&gt;Miscellaneous Items&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://freshgroovy.com/2012/06/30/groovy-2-0-0-final-for-ubuntu-based-linux/'&gt;Groovy 2.0.0 Final for Ubuntu based Linux&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://kalikallin.tumblr.com/post/25182657116/setting-grails-content-type-for-a-given-file-extension'&gt;Setting Grails Content-Type for a given file extension&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://arturoherrero.com/2012/06/17/sparky/'&gt;Sparky&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.tomcatexpert.com/blog/2012/06/19/apache-tomcat-7028-released'&gt;Apache Tomcat 7.0.28 released&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails2.spirobyte.com/blog/index.php?entryid=5'&gt;Picture of Roberto Perez Alcolea Combo boxes dinámicos en Grails&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://mrhaki.blogspot.com/2012/06/groovy-goodness-multiple-overloaded.html'&gt;Groovy Goodness: Multiple Overloaded Operator Methods for Nice API&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.intelligrape.com/blog/2012/06/26/integrating-grails-with-weceem-2-creating-custom-content/'&gt;Integrating Grails With Weceem 2 : Creating custom content &lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://jts-blog.com/?p=17324'&gt;Using Spring Integration to Create a Async Service in Grails&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://refactr.com/blog/2012/06/understanding-grails-aliases/'&gt;Understanding Grails Aliases&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://mrhaki.blogspot.com/2012/06/groovy-goodness-partial-matches.html'&gt;Groovy Goodness: Partial Matches&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://gist.github.com/3002724'&gt;match/when implemented with Groovy&amp;#8217;s GEP-3&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://leanjavaengineering.wordpress.com/2012/06/20/grails-mahout-recommenders/'&gt;Using Mahout Recommenders in Grails&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://naleid.com/blog/2012/06/20/unit-testing-grails-services-redis-without-stomping-on-data/'&gt;Unit Testing Grails Services that use Redis Without Stomping on Data&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.springsource.org/node/3582'&gt;SpringSource Tool Suites 3.0.0.M2 released&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.springsource.org/node/3575'&gt;This Week in Spring &amp;#8211; June 19th, 2012&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.springsource.org/node/3579'&gt;This Week in Spring &amp;#8211; June 26th, 2012&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id="plugins"&gt;
&lt;h2&gt;Plugins&lt;/h2&gt;
&lt;p&gt;There were 3 new plugins released:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/federated-grails'&gt;federated-grails&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.2.1. Uses Shiro and Shibboleth to integrate into federated authentication
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/font-awesome-resources'&gt;font-awesome-resources&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.1. Integrates the Font Awesome icon set
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/spring-security-eventlog'&gt;spring-security-eventlog&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.2. Logs Spring Security events
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and 13 updated plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/ajaxflow'&gt;ajaxflow&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.2.3. Enables Ajaxified Webflows
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/bcrypt'&gt;bcrypt&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 1.0. Performs bcrypt hashing
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/cucumber'&gt;cucumber&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.6.0. Test your Grails apps with Cucumber
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/grom'&gt;grom&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.2.4. Sends notifications on Windows, Linux, and Mac
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/gsp-resources'&gt;gsp-resources&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.4. Use the resources plugin to include static files like main.css.gsp, so dynamically built CSS and JS can be served as proper files instead of inlined in a non-cacheable GSP file
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/guard'&gt;guard&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 1.0.6. Provides a way to run integration tests without having to repeatedly bootstrap the environment
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/handlebars-resources'&gt;handlebars-resources&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.3. Supports using Handlebars.js templates with the Grails Resources Plugin
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/infinispan'&gt;infinispan&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 1.0.1. Adds support for the JBoss Infinispan distributed cache
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/kickstart-with-bootstrap'&gt;kickstart-with-bootstrap&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.6.0. Start your project with a good looking frontend, with adapted scaffolding templates for standard CRUD pages using Twitter Bootstrap
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/spring-security-saml'&gt;spring-security-saml&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 1.0.0.M15. SAML 2.x support for the Spring Security Plugin
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/uploadr'&gt;uploadr&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.5.11. HTML5 Drag and Drop file uploader
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/xwiki-rendering'&gt;xwiki-rendering&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 0.6. Convert texts using XWiki Rendering Framework
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://grails.org/plugin/yammer-metrics'&gt;yammer-metrics&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt; version 2.1.2-2. Packages Coda Hale&amp;#8217;s yammer metrics jars
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id="tweets"&gt;
&lt;h2&gt;Interesting Tweets&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/jeffscottbrown/status/219291689066573824'&gt;@jeffscottbrown&lt;/a&gt;: I spent a little time tonight building a Groovy 2 Extension Module for datomic. &lt;a href="https://t.co/Obj4vNk5" target='_blank'&gt;https://t.co/Obj4vNk5&lt;/a&gt; &lt;a href='https://search.twitter.com/search?q=%23groovy' target='_blank'&gt;#groovy&lt;/a&gt; &lt;a href='https://search.twitter.com/search?q=%23datomic' target='_blank'&gt;#datomic&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/dmitrybrin/status/217711050341093376'&gt;@dmitrybrin&lt;/a&gt;: Got a call from JRebel rep asking how we handle our redeployment strategies during development cycle. My answer: &lt;a href='https://search.twitter.com/search?q=%23Grails' target='_blank'&gt;#Grails&lt;/a&gt; &lt;img src='http://burtbeckwith.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt;  ..sorry guys.
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/glaforge/status/214722278011846656'&gt;@glaforge&lt;/a&gt;: Nice to see a proposal for the next &lt;a href='https://search.twitter.com/search?q=%23JavaScript' target='_blank'&gt;#JavaScript&lt;/a&gt; to include &lt;a href='https://search.twitter.com/search?q=%23groovy' target='_blank'&gt;#groovy&lt;/a&gt;&amp;#8216;s safe navigation operator! &lt;a href="http://t.co/frS2q7Ta" target='_blank'&gt;http://t.co/frS2q7Ta&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/burtbeckwith/status/214770856428179457'&gt;@burtbeckwith&lt;/a&gt;: &amp;#8220;The Flying Car of Video Messaging&amp;#8221; a &lt;a href='https://search.twitter.com/search?q=%23boston' target='_blank'&gt;#boston&lt;/a&gt; area &lt;a href='https://search.twitter.com/search?q=%23grails' target='_blank'&gt;#grails&lt;/a&gt; powered social video app
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/pledbrook/status/215061993328099330'&gt;@pledbrook&lt;/a&gt;: First stab at performance tuning for &lt;a href='https://search.twitter.com/search?q=%23grails' target='_blank'&gt;#grails&lt;/a&gt; based on &lt;a href='https://twitter.com/#!/lhotari' target='_blank'&gt;@lhotari&lt;/a&gt; email: &lt;a href="http://t.co/l6NSSqp2" target='_blank'&gt;http://t.co/l6NSSqp2&lt;/a&gt; &amp;#8211; feedback welcome!
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/rfletcherEW/status/215587172030496768'&gt;@rfletcherEW&lt;/a&gt;: Want to automatically have a &amp;#8216;last updated&amp;#8217; timestamp in your &lt;a href='https://search.twitter.com/search?q=%23cloudfoundry' target='_blank'&gt;#cloudfoundry&lt;/a&gt; &lt;a href='https://search.twitter.com/search?q=%23grails' target='_blank'&gt;#grails&lt;/a&gt; app pages? &lt;a href="https://t.co/NFMHyYUp" target='_blank'&gt;https://t.co/NFMHyYUp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/graemerocher/status/216142234616201216'&gt;@graemerocher&lt;/a&gt;: Interesting . Grails smoked Play! in pretty much every performance benchmark. So much for Groovy vs Scala. &lt;a href="http://t.co/LwUC9K9k" target='_blank'&gt;http://t.co/LwUC9K9k&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/divideby0/status/216169358731378688'&gt;@divideby0&lt;/a&gt;: &lt;a href='https://twitter.com/#!/graemerocher' target='_blank'&gt;@graemerocher&lt;/a&gt; i also did a grails submission for the great web framework shootout: &lt;a href="http://t.co/ScJrfBQM" target='_blank'&gt;http://t.co/ScJrfBQM&lt;/a&gt; smoked both django and rails
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/rfletcherEW/status/216397209296576512'&gt;@rfletcherEW&lt;/a&gt;: I&amp;#8217;ve published a snapshot of my &lt;a href='https://search.twitter.com/search?q=%23angularjs' target='_blank'&gt;#angularjs&lt;/a&gt; &lt;a href='https://search.twitter.com/search?q=%23grails' target='_blank'&gt;#grails&lt;/a&gt; scaffolding plugin: &lt;a href="http://t.co/cFHxcjUw" target='_blank'&gt;http://t.co/cFHxcjUw&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/rfletcherEW/status/216555294476611585'&gt;@rfletcherEW&lt;/a&gt;: Had fun TDD&amp;#8217;ing my &lt;a href='https://search.twitter.com/search?q=%23grails' target='_blank'&gt;#grails&lt;/a&gt; &lt;a href='https://search.twitter.com/search?q=%23angularjs' target='_blank'&gt;#angularjs&lt;/a&gt; plugin with &lt;a href='https://twitter.com/#!/casperjs_org' target='_blank'&gt;@casperjs_org&lt;/a&gt;. Good way to learn &lt;a href='https://search.twitter.com/search?q=%23coffeescript' target='_blank'&gt;#coffeescript&lt;/a&gt; too &lt;a href="https://t.co/31anE8sa" target='_blank'&gt;https://t.co/31anE8sa&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/ag1le/status/217599264321318912'&gt;@ag1le&lt;/a&gt;: &lt;a href='https://search.twitter.com/search?q=%23skynews' target='_blank'&gt;#skynews&lt;/a&gt; website &lt;a href="http://t.co/A5gbcX2c" target='_blank'&gt;http://t.co/A5gbcX2c&lt;/a&gt; and cms is now live &amp;#8211; built using &lt;a href='https://search.twitter.com/search?q=%23grails' target='_blank'&gt;#grails&lt;/a&gt; &amp;#8211; phew
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/dhanushgopinath/status/217614488726278145'&gt;@dhanushgopinath&lt;/a&gt;: &lt;a href='https://twitter.com/#!/graemerocher' target='_blank'&gt;@graemerocher&lt;/a&gt; I was previously part of a team which launched &lt;a href="http://t.co/a2A3L6ds" target='_blank'&gt;http://t.co/a2A3L6ds&lt;/a&gt; on &lt;a href='https://search.twitter.com/search?q=%23grails' target='_blank'&gt;#grails&lt;/a&gt;. Developing it was cool and fast.
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/robpatrick/status/217926176323289089'&gt;@robpatrick&lt;/a&gt;: You know you are a &lt;a href='https://search.twitter.com/search?q=%23groovy' target='_blank'&gt;#groovy&lt;/a&gt; developer when,&amp;#8230; you can fix bugs with a shocked elvis ?: 0
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/_cr381ve/status/217958973733736448'&gt;@_cr381ve&lt;/a&gt;: Migrating to the new grails plugin repository &amp;#8211; remember to request access and install release plugin 2.0.3 -&gt; &lt;a href="http://t.co/gmOPUgGJ" target='_blank'&gt;http://t.co/gmOPUgGJ&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/giplugin/status/218104291955703810'&gt;@giplugin&lt;/a&gt;: The Grails Infinispan Plugin has been released as version 1.0.1 and works with Grails version 2.0.4. Questions and comments are welcomed.
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/andy_clement/status/218360140640960514'&gt;@andy_clement&lt;/a&gt;: The &lt;a href='https://search.twitter.com/search?q=%23groovy' target='_blank'&gt;#groovy&lt;/a&gt; &lt;a href='https://search.twitter.com/search?q=%23grails' target='_blank'&gt;#grails&lt;/a&gt; tool suite (GGTS) is available ! Like STS but with groovy/grails built in: &lt;a href="http://t.co/3rGKQScx" target='_blank'&gt;http://t.co/3rGKQScx&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/Frans_van_Buul/status/218647651825102848'&gt;@Frans_van_Buul&lt;/a&gt;: Just migrated my current project to &lt;a href='https://search.twitter.com/search?q=%23groovy' target='_blank'&gt;#groovy&lt;/a&gt; 2.0.0! Thank you &lt;a href='https://twitter.com/#!/glaforge' target='_blank'&gt;@glaforge&lt;/a&gt; and team! rm -r src/main/java &lt;img src='http://burtbeckwith.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id="jobs"&gt;
&lt;h2&gt;Jobs&lt;/h2&gt;
&lt;hr/&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://seeker.dice.com/jobsearch/servlet/JobSearch?op=300&amp;#038;FREE_TEXT=grails&amp;#038;FRMT=0'&gt;Dice keyword search for Grails&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://jobsearch.monster.com/PowerSearch.aspx?q=grails'&gt;Monster keyword search for Grails&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.careerbuilder.com/Jobseeker/Jobs/JobResults.aspx?_ctl0%3A_ctl2%3AucQuickBar%3As_rawwords=grails'&gt;Careerbuilder keyword search for Grails&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/SpringSourceJob'&gt;SpringSourceJob Twitter feed&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://jobs.vmware.com/search?q=springsource'&gt;SpringSource job search at jobs.vmware.com&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr/&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://careers.joelonsoftware.com/jobs/21032/backend-developer-f-m-kaufda-juno-internet-gmbh'&gt;Backend Developer (f/m) &amp;#8211; Berlin&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://job-interview.ru/vacancy/588955'&gt;Java / Grails разработчик &amp;#8211; Москва&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.grailsjobs.com/view-job/446'&gt;Engineering Manager at Taulia in San Francisco, CA&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.grailsjobs.com/view-job/445'&gt;Senior Developer for Groovy Startup (Java &amp;#038; Grails too!) at Taulia in San Francisco, CA&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.grailsjobs.com/view-job/451'&gt;Grails Developer (contract) at Acrede&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.meetup.com/Grails-Boston/boards/view/viewthread?thread=24530192'&gt;Hiring folks with Grails exp at Mobiquity in Boston/Providence&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.grailsjobs.com/view-job/452'&gt;Backend Developer (m/w) &amp;#8211; SuitePad, Berlin (Contract)&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.bullhornreach.com/job/283760_web-developer-kansas-city-mo'&gt;Web Developer in Kansas City, MO &lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.cybercoders.com/jobs/software-architect-backend-development-java-or-groovy-job/vbb-ma-architect-startup/?jobid=VBB-MA-Architect-Startup&amp;#038;ad=recEmail'&gt;Software Architect &amp;#8211; Backend Development &amp;#8211; Java or Grails &amp;#8211; Startup in Cambridge, MA&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://job-interview.ru/vacancy/597411'&gt;Sr. Java / Grails Developer (Web) &amp;#8211; Нижний Новгород&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://jobs.partnersconsulting.com/bcsijobs.nsf/o/18833'&gt;Grails Engineer in Woodland Hills, CA&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://newyork.ebayclassifieds.com/it-software-development/stamford/java-with-groovy-grails/?ad=20571730'&gt;Java with Groovy/Grails (contract) in Stamford, CT&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://emploi.alsacreations.com/offre-481040-Developpeur-java---grails.html'&gt;Développeur java / grails &amp;#8211; Paris (Télétravail)&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.donanza.com/jobs/p5275952-grails_developer_some_remote_work'&gt;Grails Developer (some remote work!) at Gryphon Inc in Riverside, CA&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.twitjobsearch.com/jobbar/aHR0cCUzQSUyRiUyRnd3dy5yZXFpdmEuY29tJTJGam9icyUyRmphdmEtZGV2ZWxvcGVyLWFuZHJvaWQtZ3JhaWxzLXNwcmluZy1oaWJlcm5hdGUtbG9uZG9u'&gt;Java Developer in London: Android, Grails, Spring, Hibernate&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://apply.jobadder.com/155/1030353/5scp2aqbjjyunisnfuvh5rxmx4?show=details'&gt;Grails (Java) Developers at SiteMinder&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://boston.craigslist.org/gbs/sof/3101583693.html'&gt;Fast Growing Profitable Startup- Learn Groovy/Grails in Waltham, MA&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.geekfreelancers.com/projects/java-grails-engineer-position-648444.html'&gt;JAVA / GRAILS Engineer Position&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.geekfreelancers.com/projects/groovy-grails-developer-needed-asap-ft-contract-high-potential-employment-645748.html'&gt;Grails Developer Needed ASAP! (FT, Contract) in NYC&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://jobs.dou.ua/companies/dachis-group/vacancies/1964/'&gt;Java/Grails Developer &amp;#8211; Киев&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://search.clickjobs.com/jobs/preview/921450/developer-grails-job-code-j30588.html'&gt;Developer &amp;#8211; Grails in 	Delhi, Mumbai, Chennai, Kolkata, Bangalore, Hyderabad, Pune, Ahmedabad, Gurgaon, Noida&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://raleigh.craigslist.org/sof/3089347223.html'&gt;Web Application Developer (Java/Groovy/Grails) in Cary, NC&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://jobs.hasgeek.com/view/gxciy'&gt;Enthusiastic, proactive groovy/grails developer in Hyderabad&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://emploidunet.fr/emploi/provence-alpes-cote-d-azur/1526/ingenieur-en-developpement-j2ee-grails-h-f'&gt;Ingénieur en développement J2EE / GRAILS H/F &amp;#8211; Sophia-Antipolis / NICE, Alpes-Maritimes, Provence-Alpes-Côte d&amp;#8217;Azur &lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='https://twitter.com/#!/JeremyCampbell/status/215168187497586689'&gt;@JeremyCampbell&lt;/a&gt;: I&amp;#8217;m on the hunt for a new technical co-founder for my company! If you are an experienced Java and/or Grails developer then get in touch ASAP
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.careerbuilder.ca/CA/JobSeeker/Jobs/JobDetails.aspx?siteid=int_cacareerjetfeed&amp;#038;Job_DID=J3J3NK6FTWYKSRH2SHV'&gt; Programmer/Software Developer – Java/Groovy/Grails in Calgary, Alberta&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.cityjobsstore.com/new-york-jobs/new-york/java-j2ee-restful-webservices-json-groovy-grails-JHS8HD6SCY2DRXDMZP9.html'&gt;Java / J2ee Restful WebServices JSON Groovy Grails in NYC&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.linkedin.com/groups/Grails-opening-Netflix-in-Los-39757.S.128734096?view=&amp;#038;gid=39757&amp;#038;type=member&amp;#038;item=128734096'&gt;Grails opening at Netflix in Los Gatos/San Jose, CA &lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.linkedin.com/jobs?viewJob=&amp;#038;jobId=3273152'&gt;Senior Web Developer at carsales.com.au in Richmond, Victoria (Melbourne Area, Australia)&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.linkedin.com/groupAnswers?viewQuestionAndAnswers=&amp;#038;discussionID=128508669&amp;#038;gid=76751'&gt;Développeur Sénior Java/Groovy. Ville St-Laurent (Montréal)&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.linkedin.com/groups/Direct-Hire-Great-Groovy-Grails-67067.S.128645961?view=&amp;#038;gid=67067&amp;#038;type=member&amp;#038;item=128645961'&gt;Direct Hire/Great Groovy/Grails Developer positions in Phoenix, AZ! &lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id="meetups"&gt;
&lt;h2&gt;User groups and Conferences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://gr8conf.eu/'&gt;GR8Conf US 2012&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
July 29&lt;sup&gt;th&lt;/sup&gt;-31&lt;sup&gt;st&lt;/sup&gt; Minneapolis, MN
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a target='_blank' href='http://www.springone2gx.com/conference/washington/2012/10/home'&gt;SpringOne 2GX 2012&lt;img src='/blog/images/pop.gif'/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
October 15&lt;sup&gt;th&lt;/sup&gt;-18&lt;sup&gt;th&lt;/sup&gt; Washington, DC
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fburtbeckwith.com%2Fblog%2F%3Fp%3D1448&amp;amp;title=This%20Week%20in%20Grails%20%282012-26%29" id="wpa2a_2"&gt;&lt;img src="http://burtbeckwith.com/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://burtbeckwith.com/blog/?flattrss_redirect&amp;amp;id=1448&amp;amp;md5=1eccbd4fe2186778f44bb5db6a351e45" title="Flattr" target="_blank"&gt;&lt;img src="https://burtbeckwith.com/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Tue, 03 Jul 2012 13:00:30 CDT</pubDate>
      <guid isPermaLink="true">http://burtbeckwith.com/blog/?p=1448</guid>
      <dc:creator>Burt Beckwith</dc:creator>
    </item>
    <item>
      <title>Griffon: JavaFX for the Enterprise.</title>
      <link>http://projectautomationexperience.com/blog/andres_almiray/2012/07/griffon_javafx_for_the_enterprise_?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;A few weeks ago I presented a talk on &lt;a href="http://community.ejug.at/networks/events/show_event.55982"&gt;JavaFX and Griffon&lt;/a&gt; in Linz hosted by eJUG. A couple of Griffon (Swing and JavaFX) applications were shown on stage, with two of them going toe to toe in showing how easy is to integrate JPA into a desktop application no matter the UI toolkit of choice. I'm going to reproduce both applications right here in order to show the similarities and differences between choosing Swing or JavaFX when building an application with Griffon. Let's get started.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Create the applications&lt;/strong&gt;&lt;br/&gt;
The first step is to create both applications. Swing being the default toolkit of choice at the moment makes it for a simple command call, like the following one&lt;br/&gt;
&lt;div class="source"&gt;
$ griffon create-app sample1&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;
Good, now creating the JavaFX application requires specifying an additional parameter that marks the application as a JavaFX one&lt;br/&gt;&lt;br/&gt;
&lt;div class="source"&gt;
$ griffon create-app sample2 --archetype=javafx&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;
That wasn't so bad, we know have two fully working Griffon applications although they do nothing more than pop a window with a simple message when run. Let's change that.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Configuring JPA&lt;/strong&gt;&lt;br/&gt;
The following step must be executed in both applications. What we'll do is install the &lt;a href="http://artifacts.griffon-framework.org/plugin/jpa"&gt;JPA&lt;/a&gt; plugin, create a JPA entity, configure the default persistence unit, and bootstrap some data when the application starts.&lt;br/&gt;
Alright, installing the JAP is done in the following way&lt;br/&gt;
&lt;div class="source"&gt;
$ griffon install-plugin jpa&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;
Done. Next create a file named &lt;tt&gt;Person.groovy&lt;/tt&gt; inside &lt;tt&gt;src/main/data&lt;/tt&gt;; you may need to create that directory first.&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="16"&gt;package data

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id

@Entity
class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id

    String name
    String lastname
}&lt;/textArea&gt;
&lt;br/&gt;
This is a standard JPA entity class, the Groovy language makes it easy to keep track of what's important by removing most of the visual cruft and verbosity &lt;img src="http://www.jroller.com/images/smileys/grin.gif" class="smiley" alt=":-D" title=":-D" /&gt;. Now that we have this entity class is time to define the configuration for the default persistence unit the applications will make use of, this task is accomplished by creating a file &lt;tt&gt;persistence.xml&lt;/tt&gt; inside &lt;tt&gt;griffon-app/conf/metainf&lt;/tt&gt;&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="18"&gt;&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;persistence xmlns&lt;img src="http://www.jroller.com/images/smileys/love.gif" class="smiley" alt=":x" title=":x" /&gt;si="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"&gt;
    &lt;persistence-unit name="default" transaction-type="RESOURCE_LOCAL"&gt;
        &lt;provider&gt;org.eclipse.persistence.jpa.PersistenceProvider&lt;/provider&gt;
        &lt;class&gt;data.Person&lt;/class&gt;
        &lt;properties&gt;
            &lt;property name="javax.persistence.jdbc.driver"   value="org.h2.Driver" /&gt;
            &lt;property name="javax.persistence.jdbc.url"      value="jdbc:h2:mem:sample" /&gt;
            &lt;property name="javax.persistence.jdbc.user"     value="sa" /&gt;
            &lt;property name="javax.persistence.jdbc.password" value="" /&gt;
            &lt;!-- EclipseLink should create the database schema automatically --&gt;
            &lt;property name="eclipselink.ddl-generation" value="create-tables" /&gt;
            &lt;property name="eclipselink.ddl-generation.output-mode" value="database" /&gt;
        &lt;/properties&gt;
    &lt;/persistence-unit&gt;
&lt;/persistence&gt;&lt;/textArea&gt;
&lt;br/&gt;The applications make use of H2 and Eclipselink, dependencies that must be configured in &lt;tt&gt;griffon-app/conf/BuildConfig.groovy&lt;/tt&gt; in a block that looks like this one&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="15"&gt;griffon.project.dependency.resolution = {
    inherits "global"
    log "warn"
    repositories {
        griffonHome()
        mavenCentral()
        mavenRepo 'http://download.eclipse.org/rt/eclipselink/maven.repo/'
    }
    dependencies {
        compile('org.eclipse.persistence:eclipselink:2.4.0-RC2') {
            exclude 'javax.persistence'
        }
        compile('com.h2database:h2:1.3.167')
    }
}&lt;/textArea&gt;
&lt;br/&gt;The last task in this step is to define some data that will be used to fill the database. A pair of files were added to &lt;tt&gt;griffon-app/conf&lt;/tt&gt; when the JPA plugin was installed; one of these files is aptly named &lt;tt&gt;BootstrapJpa.groovy&lt;/tt&gt;, which is exactly where we'll place the following code&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="20"&gt;import javax.persistence.EntityManager
import data.Person

class BootstrapJpa {
    def init = { String persistenceUnit, EntityManager em -&gt;
        em.getTransaction().begin()
        [[id: 1, name: 'Jamie',  lastname: 'Hyneman'],
         [id: 2, name: 'Adam',   lastname: 'Savage'],
         [id: 3, name: 'Tori',   lastname: 'Belleci'],
         [id: 4, name: 'Kari',   lastname: 'Byron'],
         [id: 5, name: 'Grant',  lastname: 'Imahara'],
         [id: 6, name: 'Buster', lastname: '']].each { data -&gt;
            em.persist(new Person(data))
        }
        em.getTransaction().commit()
    }

    def destroy = { String persistenceUnit, EntityManager em -&gt;
    }
}&lt;/textArea&gt;
&lt;br/&gt;Alright, these should be enough to take care of the JPA stuff. Time to move on to the next challenge: building the UI.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Adding Swing / JavaFX&lt;/strong&gt;&lt;br/&gt;
The following screenshots show the Swing and JavaFX versions. you can appreciate both have the same set of elements though they look slightly different. Can you guess which is the JavaFX one? That's right, the one with the &lt;i&gt;non-native&lt;/i&gt; look (pay no heed to the title)&lt;br/&gt;&lt;br/&gt;
&lt;center&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td align="center"&gt;&lt;img src="http://www.jroller.com/aalmiray/resource/griffon-sample1.png"/&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align="center"&gt;&lt;img src="http://www.jroller.com/aalmiray/resource/griffon-sample2.png"/&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/center&gt;
So how does the UI of the first application is constructed? Griffon relies on a SwingBuilder DSL to make it easier to write the UI. With this DSL in place is easy to distinguish the component hierarchy and how elements are connected&lt;br/&gt;
&lt;b&gt;griffon-app/views/sample1/Sample1View.groovy&lt;/b&gt;&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="23"&gt;package sample1

application(title: 'Griffon + Swing + JPA',
  preferredSize: [320, 240],
  pack: true,
  locationByPlatform: true,
  iconImage: imageIcon('/griffon-icon-48x48.png').image,
  iconImages: [imageIcon('/griffon-icon-48x48.png').image,
               imageIcon('/griffon-icon-32x32.png').image,
               imageIcon('/griffon-icon-16x16.png').image]) {
    borderLayout()
    toolBar(floatable: false, constraints: NORTH) {
        button('Load',  actionPerformed: controller.load)
        button('Clear', actionPerformed: controller.&amp;clear)
    }
    scrollPane(constraints: CENTER) {
        table {
            tableFormat = defaultTableFormat(columnNames: ['Id', 'Name', 'Lastname'])
            eventTableModel(source: model.people, format: tableFormat)
            installTableComparatorChooser(source: model.people)
        }
    }
}&lt;/textArea&gt;&lt;br/&gt;The JavaFX view relies on a similar trick, that is, make use of a DSL however in this case it's based on SceneGraphBuilder (from the &lt;a href="http://groovyfx.org/"&gt;GroovyFX&lt;/a&gt; project). See if you can spot the real differences between both views&lt;br/&gt;
&lt;b&gt;griffon-app/views/sample2/Sample2View.groovy&lt;/b&gt;&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="27"&gt;package sample2

import javafx.beans.*

stage(title: 'Griffon + JavaFX + JPA', visible: true, centerOnScreen: true) {
    scene(fill: WHITE, width: 352, height: 300) {
        borderPane {
            top {
                toolBar {
                    button('Load',  onAction: controller.load)
                    button('Clear', onAction: controller.&amp;clear)
                }
            }
            tv = tableView(selectionMode: 'single', cellSelectionEnabled: true, items: model.people) {
                tableColumn(property: 'id', text: 'Id', prefWidth: 50)
                tableColumn(property: 'name', text: 'Name', prefWidth: 150)
                tableColumn(property: 'lastname', text: 'Lastname', prefWidth: 150)
            }
        }
        noparent {
            model.people.addListener({
                tv.items.clear()
                tv.items.addAll(model.people)
            } as InvalidationListener)
        }
    }
}&lt;/textArea&gt;&lt;br/&gt;I must confess that binding &lt;tt&gt;model.people&lt;/tt&gt; directly to the tableView's &lt;tt&gt;items&lt;/tt&gt; property was done as a desperate measure as I couldn't get the tableView to be updated automatically whenever &lt;tt&gt;model.people&lt;/tt&gt; (a JavaFX ObservableList) had its contents updated. Oh well, something to review when the next JavaFX release comes out (currently testing with JavaFX 2.2beta15 on OSX and JDK6 for those who care).&lt;/p&gt;
&lt;p&gt;
The views have references to their corresponding models and controllers. The models hold a reference to an observable list that will be used to update the table. In the case of Swing we'll rely on the excellent &lt;a href="http://publicobject.com/glazedlists/"&gt;GlazedLists&lt;/a&gt; project (for which there's a &lt;a href="http://artifacts.griffon-framework.org/plugin/glazedlists"&gt;plugin&lt;/a&gt; of course). Here's how the model looks&lt;br/&gt;
&lt;b&gt;griffon-app/models/sample1/Sample1Model.groovy&lt;/b&gt;&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="11"&gt;package sample1

import data.Person
import ca.odell.glazedlists.EventList
import ca.odell.glazedlists.BasicEventList
import ca.odell.glazedlists.SortedList

class Sample1Model {
   EventList people = new SortedList(new BasicEventList(),
     {a, b -&gt; a.id &lt;=&gt; b.id} as Comparator)
}&lt;/textArea&gt;&lt;br/&gt;For the JavaFX version the code turns out to be much simpler as observable lists are baked right into the JavaFX APIs. The JavaFX model looks like this&lt;br/&gt;
&lt;b&gt;griffon-app/models/sample2/Sample2Model.groovy&lt;/b&gt;&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="7"&gt;package sample2

import javafx.collections.FXCollections

class Sample2Model {
    List people = FXCollections.observableList([])
}&lt;/textArea&gt;&lt;br/&gt;Now for the final piece, we must provide a suitable implementation for the controller actions. You may recall from the views that there are 2 actions in the controller: one to load the data in the table, the second to clear the table. And here's where things get really interesting as the code I'm about to show is practically the same, no matter if you're dealing with Swing or JavaFX&lt;br/&gt;
&lt;b&gt;griffon-app/controllers/sample1/Sample1Controller.groovy&lt;/b&gt;&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="23"&gt;package sample1

import data.Person
import griffon.transform.Threading
import javax.persistence.EntityManager
import javax.persistence.Query

class Sample1Controller {
    def model

    def load = {
        withJpa { String persistenceUnit, EntityManager em -&gt;
            List&lt;Person&gt; tmpList = []
            tmpList.addAll em.createQuery('select p from Person p order by p.id').resultList
            execInsideUIAsync { model.people.addAll tmpList }
        }
    }

    @Threading(Threading.Policy.SKIP)
    void clear(evt) {
        model.people.clear()
    }
}&lt;/textArea&gt;&lt;br/&gt;Don't be fooled by the apparent lack of UI code found in the controller actions, as Griffon controllers follow &lt;a href="http://griffon.codehaus.org/guide/latest/guide/8.%20Controllers%20and%20Services.html#8.1.1%20Threads%20and%20Actions"&gt;some rules&lt;/a&gt; regarding how threading should work. For starters all controller actions are executed outside of the UI thread (whether that's the EDT in Swing or the JavaFX UI thread in JavaFX only the specific toolkit plugin cares). It's then safe to query the database using the JPA APIs inside the &lt;tt&gt;load&lt;/tt&gt; action, however once the data has been computed we must update the model inside the UI thread as that change will trigger an update on the visual components bound to the &lt;tt&gt;people&lt;/tt&gt; list (the JTable and the TableView respectively). The second action, &lt;tt&gt;clear&lt;/tt&gt;, updates the contents of the model directly, and as such it should be done in the UI thread already, no need to jump to another thread just to come back immediately to the UI thread; this is why we applied an annotation that instructs the compiler to leave this action untouched in terms of &lt;a href="http://griffon.codehaus.org/guide/latest/guide/9.%20Threading.html#9.3%20Annotation%20Based%20Threading"&gt;thread management code injection&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If the usage of an application framework like Griffon was dubious at first I hope you think differently now. Apart from some toolkit specifics found in the View and Model, the application remains the same no matter the toolkit you're targeting. This proves to be of great advantage for developers willing to give JavaFX a try, as starting with Swing today doesn't mean rewriting the whole application with JavaFX later. Compound the growing &lt;a href="http://artifacts.griffon-framework.org/category/all/plugins"&gt;list of plugins&lt;/a&gt; available to Griffon applications and you're up for a fun ride when developing desktop applications for the JVM.
&lt;/p&gt;
&lt;p&gt;
In terms of numbers both applications are very close. These are the stats for the Swing version&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="13"&gt;+----------------------+-------+-------+
| Name                 | Files |  LOC  |
+----------------------+-------+-------+
| Models               |     1 |     9 | 
| Views                |     1 |    22 | 
| Controllers          |     1 |    19 | 
| Lifecycle            |     5 |     3 | 
| Groovy/Java Sources  |     1 |    13 | 
| Unit Tests           |     1 |    13 | 
| Configuration        |     2 |    38 | 
+----------------------+-------+-------+
| Totals               |    12 |   117 | 
+----------------------+-------+-------+&lt;/textArea&gt;&lt;br/&gt;Whereas the JavaFX version sports these numbers
&lt;br/&gt;&lt;textArea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="13"&gt;+----------------------+-------+-------+
| Name                 | Files |  LOC  |
+----------------------+-------+-------+
| Models               |     1 |     5 | 
| Views                |     1 |    25 | 
| Controllers          |     1 |    19 | 
| Lifecycle            |     5 |     0 | 
| Groovy/Java Sources  |     1 |    13 | 
| Unit Tests           |     1 |    13 | 
| Configuration        |     2 |    38 | 
+----------------------+-------+-------+
| Totals               |    12 |   113 | 
+----------------------+-------+-------+&lt;/textArea&gt;&lt;br/&gt;Not bad, huh? Full source code for both applications can be obtained from &lt;a href="https://github.com/aalmiray/Presentations/tree/master/ejug"&gt;this link&lt;/a&gt;.
&lt;/p&gt;</description>
      <pubDate>Tue, 03 Jul 2012 11:00:30 CDT</pubDate>
      <guid isPermaLink="true">http://www.jroller.com/aalmiray/entry/griffon_javafx_for_the_enterprise</guid>
      <dc:creator>Andres Almiray</dc:creator>
    </item>
    <item>
      <title>Denver Salesforce.com Developer Meetup TONIGHT!</title>
      <link>http://projectautomationexperience.com/blog/james_ward2/2012/07/denver_salesforce_com_developer_meetup_tonight_?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;Hey Denver Salesforce.com and Heroku developers!  Tonight we are doing a developer meetup at Wynkoop.  Come on down for free food, drinks, and networking from 6 &amp;#8211; 8.  &lt;a href="http://www.developerforce.com/events/denver_developer_meetup_july2012/registration.php?d=70130000000sgbM"&gt;RSVP&lt;/a&gt; and hopefully I&amp;#8217;ll see you tonight!&lt;/p&gt;</description>
      <pubDate>Mon, 02 Jul 2012 13:00:35 CDT</pubDate>
      <guid isPermaLink="true">http://www.jamesward.com/?p=3402</guid>
      <dc:creator>James Ward</dc:creator>
    </item>
    <item>
      <title>Choices [Flickr]</title>
      <link>http://projectautomationexperience.com/blog/aaron_gustafson/2012/06/choices_flickr_?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;&lt;a href="http://www.flickr.com/people/aarongustafson/"&gt;Aaron Gustafson&lt;/a&gt; posted a photo:&lt;/p&gt;
	
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/aarongustafson/7473641024/" title="Choices"&gt;&lt;img src="http://farm8.staticflickr.com/7127/7473641024_ae599d5964_m.jpg" width="240" height="240" alt="Choices" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/EasyReader/~4/JK4axQMir7s" height="1" width="1"/&gt;</description>
      <pubDate>Sat, 30 Jun 2012 16:02:24 CDT</pubDate>
      <guid isPermaLink="true">tag:flickr.com,2005:/photo/7473641024</guid>
      <dc:creator>Aaron Gustafson</dc:creator>
    </item>
    <item>
      <title>Play vs. Grails Smackdown at ?berConf</title>
      <link>http://projectautomationexperience.com/blog/matt_raible/2012/06/play_vs_grails_smackdown_at_berconf?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>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 &lt;a href="http://jamesward.com"&gt;James Ward&lt;/a&gt; and I decided to do a presentation at &lt;a href="http://uberconf.com"&gt;ÜberConf&lt;/a&gt; comparing the two. In April, we proposed the talk to Jay Zimmerman, got accepted and went to work.
&lt;/p&gt;
&lt;p id="how"&gt;&lt;strong&gt;How we did it&lt;/strong&gt;&lt;br/&gt;
In the beginning of May, we met at a &lt;a href="http://www.wynkoop.com/"&gt;brewery in LoDo&lt;/a&gt; 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. 
&lt;/p&gt;
&lt;p&gt;
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 &lt;a href="https://github.com/jamesward/happytrails"&gt;source code on GitHub&lt;/a&gt;, continuously tested on &lt;a href="http://www.cloudbees.com/"&gt;CloudBees&lt;/a&gt; and deployed to &lt;a href="http://heroku.com"&gt;Heroku&lt;/a&gt;. Two weeks ago, when we were finishing up our apps, we hired a friend (&lt;a href="http://www.linkedin.com/pub/linsay-shirley/1/5a0/b4"&gt;Linsay Shirley&lt;/a&gt;) to do QA. 
&lt;/p&gt;
&lt;p&gt;
After fixing bugs, I emailed &lt;a href="http://blog.lightbody.net/"&gt;Patrick Lightbody&lt;/a&gt;, got some “cloud dollars” for &lt;a href="https://browsermob.com/performance-testing"&gt;Neustar Web Performance&lt;/a&gt; and started running load tests. The Wednesday before last, at 2 in the morning, I recorded &lt;a href="https://wm2-testscripts-scripts-prod.s3.amazonaws.com/script/b1b78d4286054d159888bc4135379b86/script.js?versionId=J4E28EFR5PzDNnAgPPPfoelw3AhMqI9A"&gt;a simple browsing regions and routes script&lt;/a&gt; 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. 
&lt;/p&gt;
&lt;p&gt;
We took our development experience, the load/performance testing data, and a bunch of ecosystem stats and built &lt;a href="http://www.ubertracks.com/preso/"&gt;our smackdown presentation&lt;/a&gt;. We used &lt;a href="http://lab.hakim.se/reveal-js/"&gt;reveal.js&lt;/a&gt;, &lt;a href="http://www.jamesward.com/2012/06/15/dynamically-rendering-github-files-in-web-pages"&gt;GitHub Files&lt;/a&gt; and &lt;a href="https://developers.google.com/chart/"&gt;Google Charts&lt;/a&gt; to make things more dynamic.
&lt;/p&gt;
&lt;p id="conclusions"&gt;&lt;strong&gt;What we found&lt;/strong&gt;&lt;br/&gt;
We arrived at a number of &lt;a href="http://www.ubertracks.com/preso/#/10"&gt;conclusions&lt;/a&gt; after doing our research:
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;From a code perspective, Play 2 and Grails 2 are very similar frameworks.&lt;/li&gt;
&lt;li&gt;Code authoring was good in both, but lacking IDE support for Play 2's Scala Templates.&lt;/li&gt;
&lt;li&gt;Grails Plugin Ecosystem is excellent.&lt;/li&gt;
&lt;li&gt;TDD-Style Development is easy with both.&lt;/li&gt;
&lt;li&gt;Type-safety in Play 2 was really useful, especially routes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Statistical Analysis&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Grails has better support for FEO (YSlow, PageSpeed)&lt;/li&gt;
&lt;li&gt;Grails has less LOC! (6 lines less, but 40% more files)&lt;/li&gt;
&lt;li&gt;1 Dyno - Grails had 2x transactions!
&lt;ul style="margin-bottom: 0"&gt;
&lt;li&gt;Grails experienced OOM about halfway through.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Apache Benchmark with 10K requests:
&lt;ul style="margin-bottom: 0"&gt;
&lt;li style="text-decoration:line-through"&gt;Play: ~10% failed requests, Grails: 0&lt;/li&gt;
&lt;li style="text-decoration:line-through"&gt;Requests per second: {Play: 170, Grails: 198}&lt;/li&gt;
&lt;li&gt;Requests per second: {Play: 251, Grails: 198}&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Load Test with 100 Real Users:
&lt;ul style="margin-bottom: 0"&gt;
&lt;li&gt;Grails: 10% more transactions, 0 errors&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ecosystem Analysis&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;"Play" is difficult to search for.&lt;/li&gt;
&lt;li&gt;Grails is more mature.&lt;/li&gt;
&lt;li&gt;Play has momentum issues.&lt;/li&gt;
&lt;li&gt;LinkedIn: more people know Grails than Spring MVC.&lt;/li&gt;
&lt;li&gt;Play has 3x user mailing list traffic.&lt;/li&gt;
&lt;li&gt;We had similar experiences with documentation and questions.&lt;/li&gt;
&lt;li&gt;Outdated documentation is a problem for both.&lt;/li&gt;
&lt;li&gt;Play has &lt;em&gt;way&lt;/em&gt; more hype!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
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 &lt;a href="https://github.com/jamesward/happytrails"&gt;clone the project on GitHub&lt;/a&gt; (Grails is in the &lt;em&gt;grails2&lt;/em&gt; branch, Play is in the &lt;em&gt;play2_java&lt;/em&gt; branch) and help us improve it. The presentation is in the master branch in the &lt;em&gt;preso&lt;/em&gt; directory. 
&lt;/p&gt;
&lt;p&gt;
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 &lt;a href="http://twitter.com/pk11/status/216186997126070272"&gt;discover an issue&lt;/a&gt; and &lt;a href="https://gist.github.com/2973705"&gt;provide a fix&lt;/a&gt; for Play that increases its throughput from 170 req/second to 252 req/second!
&lt;/p&gt;
&lt;p&gt;
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.</description>
      <pubDate>Sat, 30 Jun 2012 13:00:29 CDT</pubDate>
      <guid isPermaLink="true">http://raibledesigns.com/rd/entry/play_vs_grails_smackdown_at</guid>
      <dc:creator>Matt Raible</dc:creator>
    </item>
    <item>
      <title>Upgrading to Play 2: Anorm and Testing</title>
      <link>http://projectautomationexperience.com/blog/matt_raible/2012/06/upgrading_to_play_2_anorm_and_testing?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;a href="http://playframework.org"&gt;&lt;img src="http://farm8.staticflickr.com/7234/7158522999_066b0e26a1_t.jpg" width="100" height="33" class="picture" style="border: 0"/&gt;&lt;/a&gt;
This time last year, I decided I wanted to learn Scala. I chose the &lt;a href="http://www.playframework.org/"&gt;Play Framework&lt;/a&gt; as my vehicle for learning and I added &lt;a href="http://coffeescript.org/"&gt;CoffeeScript&lt;/a&gt; and &lt;a href="http://scalate.fusesource.org/documentation/jade.html"&gt;Jade&lt;/a&gt; to the mix. I packaged it all up, learned a bunch and &lt;a href="http://raibledesigns.com/rd/entry/my_html5_with_play_scala"&gt;presented it at Devoxx 2011&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;In January, I added SecureSocial, JSON Services and worked a bit on the mobile client. I presented my findings &lt;a href="http://raibledesigns.com/rd/entry/comparing_web_frameworks_and_html5"&gt;at Jfokus&lt;/a&gt; shortly after. As part of my aforementioned post, I wrote:&lt;/p&gt;
&lt;p class="quote" style="color: #666"&gt;
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.
&lt;/p&gt;
&lt;p&gt;I had some complications (a.k.a. too much &lt;a href="http://raibledesigns.com/rd/entry/cruising_around_the_western_caribbean"&gt;vacation&lt;/a&gt;) with Devoxx France and wasn't able to attend. To make up for it, I submitted the talk to &lt;a href="http://uberconf.com/conference/denver/2012/06/home"&gt;ÜberConf&lt;/a&gt;. 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 &lt;a href="http://incubator.apache.org/cordova/"&gt;Cordova&lt;/a&gt;, &lt;a href="http://www.jqtouch.com/"&gt;jQTouch&lt;/a&gt; and releasing it in the App Store sometime this month.
&lt;/p&gt;
&lt;p&gt;
&lt;p id="upgrading-to-play2"&gt;&lt;strong&gt;Upgrading to Play 2&lt;/strong&gt;&lt;br/&gt;
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 &lt;em&gt;Run&lt;/em&gt; instead of &lt;em&gt;Play&lt;/em&gt;, leaving the old framework that everyone loves intact." 
&lt;/p&gt;
&lt;p&gt;However, after hearing about it at &lt;a href="http://raibledesigns.com/rd/entry/play_2_0_a_web"&gt;Devoxx&lt;/a&gt; and &lt;a href="http://raibledesigns.com/rd/entry/play_framework_2_0_with"&gt;Jfokus&lt;/a&gt;, I figured I should at least &lt;em&gt;try&lt;/em&gt; to migrate. I downloaded Play 2.0.1, created a new project and went to work.
&lt;/p&gt;
&lt;p&gt;The first thing I learned about &lt;em&gt;upgrading&lt;/em&gt; from Play 1.x to Play 2.x is &lt;em&gt;there's no such thing&lt;/em&gt;. 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.
&lt;/p&gt;
&lt;p id="evolutions"&gt;&lt;strong&gt;Evolutions&lt;/strong&gt;&lt;br/&gt;
I started by looking around to see if anyone had documented a similar migration. I found two very useful resources right off the bat:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://janhelwich.wordpress.com/2012/03/13/play-2-0-with-scala-and-scaml-part1-setup-of-test-infrastructure-model-and-persistence-with-anorm/"&gt;Play 2.0 with Scala and Scaml, Part1: Setup of test infrastructure, model and persistence with Anorm&lt;/a&gt; by Jan Helwich&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.jamesward.com/2012/02/21/play-framework-2-with-scala-anorm-json-coffeescript-jquery-heroku"&gt;Tutorial: Play Framework 2 with Scala, Anorm, JSON, CoffeeScript, jQuery &amp;amp; Heroku&lt;/a&gt; by James Ward&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From Jan's Blog, I learned to copy my evolutions from my Play 1.x project into &lt;em&gt;conf/evolutions/default&lt;/em&gt;. I changed my &lt;em&gt;application.conf&lt;/em&gt; to use PostgreSQL and wrote an EvolutionsTest.scala to verify creating the tables worked.
&lt;/p&gt;
&lt;pre class="brush: scala"&gt;
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 =&gt;
            SQL("select count(1) from athlete").execute()
            SQL("select count(1) from workout").execute()
            SQL("select count(1) from comment").execute()
        }
      }
      success
    }
  }
}
&lt;/pre&gt;
&lt;p&gt;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.
&lt;/p&gt;
&lt;pre class="brush: scala"&gt;
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 =&gt; Athlete.create(a)
          case w: Workout =&gt; Workout.create(w)
          case c: Comment =&gt; Comment.create(c)
        }
      }
    }
  }
}
&lt;/pre&gt;
&lt;p&gt;This is no longer a recommended practice in Play 2. Instead, they &lt;a href="https://groups.google.com/d/msg/play-framework/4pVUPZIRFFM/vh4nVQ-v9UcJ"&gt;recommend you turn your YAML into code&lt;/a&gt;. 10 minutes later, I had a Global.scala that loaded seed data.
  &lt;/p&gt;
&lt;pre class="brush: scala"&gt;
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), "mraible@gmail.com", "beer", "Matt", "Raible"),
        Athlete(Id(2), "trishmcginity@gmail.com", "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)
    }
  }
}
&lt;/pre&gt;
&lt;p id="anorm"&gt;&lt;strong&gt;Anorm's Missing Magic&lt;/strong&gt;&lt;br/&gt;
Before starting with Play 2, I knew it had lost some of its magic. After all, the developers had mentioned they &lt;em&gt;wanted&lt;/em&gt; to get ride of the magic and moving to Scala allowed them to do that. However, I didn't think I'd miss &lt;a href="http://www.playframework.org/modules/scala-0.9.1/anorm#AddingsomeMagicT"&gt;Magic[T]&lt;/a&gt; as much as I do. Like &lt;a href="http://martinfowler.com/bliki/OrmHate.html"&gt;Martin Fowler&lt;/a&gt;, 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 &lt;a href="http://squeryl.org"&gt;Squery&lt;/a&gt;, but I wanted to do a side-by-side comparison as part of my migration.
&lt;/p&gt;
&lt;p&gt;Using the aforementioned tutorial from James and Jan's blog posts, as well as Guillaume's &lt;a href="https://gist.github.com/2788715"&gt;Play 2.0/Anorm&lt;/a&gt;, I set about creating new model objects. I wrote a bunch of SQL, typed up some &lt;a href="http://stackoverflow.com/questions/9371227/there-are-many-similar-dao-methods-in-anorm-is-it-right"&gt;new finders&lt;/a&gt; and migrated my tests from ScalaTest to the new default, &lt;a href="http://etorreborre.github.com/specs2/"&gt;specs2&lt;/a&gt;. The Mosh Pit's &lt;a href="http://tech.mindcandy.com/2012/05/migrating-a-play-1-2-website-to-play-2-0/"&gt;Migrating a Play 1.2 website to Play 2.0&lt;/a&gt; was a great help in migrating tests.&lt;/p&gt;

&lt;p&gt;That's when I started &lt;a href="https://groups.google.com/d/topic/play-framework/-oJrmLWYGcg/discussion"&gt;having issues&lt;/a&gt; with Anorm and figuring out how its parser syntax works. After struggling for a few days, I finally found &lt;a href="https://github.com/kenichiro22/yabe-play20-scala"&gt;yabe-play20-scala&lt;/a&gt;. Since I'd used the &lt;a href="http://www.playframework.org/documentation/1.2.3/guide1"&gt;yabe tutorial from Play 1.x&lt;/a&gt;, 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.
&lt;/p&gt;
&lt;p&gt;To illustrate how little code was required for Anorm 1.x, checkout &lt;a href="https://gist.github.com/2879214"&gt;Workout.scala in Play 1.x vs. Play 2.x&lt;/a&gt;. 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.&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;I was pleasantly surprised by specs2. First of all, it was an easy migration from ScalaTest. Secondly, &lt;a href="http://www.playframework.org/documentation/2.0/ScalaTest"&gt;Play's FakeApplication&lt;/a&gt; made it very easy to write unit tests. The line count on my &lt;a href="https://gist.github.com/2879222"&gt;UnitTests.scala in Play 1.x vs. Play 2.x&lt;/a&gt; is almost identical.
&lt;/p&gt;
&lt;p&gt;&lt;a name="summary"&gt;&lt;/a&gt;
&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
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 &lt;a href="https://groups.google.com/d/msg/play-framework/J3lXeRyti4M/UjzzYJnMAuQJ"&gt;rendering validation errors&lt;/a&gt;, but I hope to figure that out soon. The last 2 hours have been &lt;em&gt;much&lt;/em&gt; 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.
&lt;/p&gt;
&lt;p&gt;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 &lt;a href="https://github.com/jaliss/securesocial"&gt;SecureSocial&lt;/a&gt; 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 &lt;a href="http://uberconf.com/conference/denver/2012/06/session?id=25584"&gt;Grails vs. Play Smackdown&lt;/a&gt;.</description>
      <pubDate>Sat, 30 Jun 2012 11:00:29 CDT</pubDate>
      <guid isPermaLink="true">http://raibledesigns.com/rd/entry/upgrading_to_play_2_anorm</guid>
      <dc:creator>Matt Raible</dc:creator>
    </item>
    <item>
      <title>How Web APIs Unlock Value in the Cloud</title>
      <link>http://projectautomationexperience.com/blog/max_katz/2012/06/how_web_apis_unlock_value_in_the_cloud?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;&lt;a href="http://mashable.com/2012/06/29/web-api-cloud/" target="_blank"&gt;How Web APIs Unlock Value in the Cloud&lt;/a&gt; by David Schoenbach, Vice President of product management at &lt;a href="http://exadel.com" target="_blank"&gt;Exadel&lt;/a&gt;. &lt;/p&gt;</description>
      <pubDate>Sat, 30 Jun 2012 08:00:36 CDT</pubDate>
      <guid isPermaLink="true">http://mkblog.exadel.com/?p=5081</guid>
      <dc:creator>Max Katz</dc:creator>
    </item>
    <item>
      <title>Secure JSON Services with Play Scala and SecureSocial</title>
      <link>http://projectautomationexperience.com/blog/matt_raible/2012/06/secure_json_services_with_play_scala_and_securesocial?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;a href="http://www.flickr.com/photos/mcginityphoto/6716294395/" title="AntwerpTownSquare by McGinityPhoto, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7002/6716294395_28ce2c5f5b_t.jpg" width="100" height="66" alt="AntwerpTownSquare" class="picture"&gt;&lt;/a&gt;
Last November, I &lt;a href="http://raibledesigns.com/rd/entry/my_html5_with_play_scala"&gt;traveled to Antwerp to speak at Devoxx&lt;/a&gt;. After my talk on HTML5 with Play Scala, &lt;a href="http://twitter.com/matkar"&gt;Mattias Karlsson&lt;/a&gt; approached me and we had a chat about doing the same talk at &lt;a href="http://www.jfokus.se/"&gt;Jfokus&lt;/a&gt; in Stockholm. I agreed and we began talking details after Trish and I returned to the US. 
&lt;p style="text-align: center"&gt;
&lt;a href="http://jfokus.se"&gt;
&lt;img width="450" style="border-radius: 10px" height="200" src="http://www.jfokus.se/jfokus/images/banners/Jfokus2012_450x200.jpg" alt="Jfokus"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I wrote this article on a plane between Denver and Seattle and will be hopping over the North Pole to Stockholm via Iceland tonight. For the past couple of weeks, I've been updating my &lt;em&gt;Play More!&lt;/em&gt; HTML5/mobile app to add some new features. Most notably, I wanted to upgrade to Play 2.0, create JSON services and add authentication. 
&lt;/p&gt;
&lt;p id="play2"&gt;&lt;strong&gt;Upgrading to Play 2.0&lt;/strong&gt;&lt;br/&gt;
My attempt to upgrade to Play 2.0 involved &lt;a href="https://github.com/playframework/play20"&gt;checking out the source from GitHub&lt;/a&gt;, building and installing the RC1 snapshot. As I tried to upgrade my app and started getting failed imports, I turned to the internet (specifically StackOverflow) to &lt;a href="http://stackoverflow.com/questions/8264010/todays-options-for-an-easier-migration-path-to-play-2"&gt;see if it was a good idea&lt;/a&gt;. The first answer for that question suggested I stay with 1.x.
  &lt;/p&gt;
&lt;p class="quote" style="color: #666"&gt;
If it's a critical project, to be finished before next March 2012, I would go with Play 1.x. If it's a less important project, which could be delayed, and that in any case won't be released before March 2012, try Play 2.0.&lt;/p&gt;
&lt;p&gt;While I didn't plan on releasing &lt;em&gt;Play More!&lt;/em&gt; before Jfokus, I decided upgrading didn't add a whole lot to the talk. Also, I couldn't find a Play Scala 0.9.1 to Play 2.0 upgrade guide and I didn't have enough time to create one. So I decided to stick with Play 1.2.4 and add some JSON services for my iPhone client. 
&lt;/p&gt;
&lt;p id="play-json"&gt;&lt;strong&gt;JSON Servers&lt;/strong&gt;&lt;br/&gt;
I found Manuel Bernhardt's &lt;a href="http://logician.free.fr/index.php/2011/09/16/play-scala-and-json/"&gt;Play! Scala and JSON&lt;/a&gt;. This led me to &lt;a href="https://github.com/codahale/jerkson"&gt;Jerkson&lt;/a&gt;, built by the &lt;a href="http://codahale.com/the-rest-of-the-story/"&gt;now infamous&lt;/a&gt; &lt;a href="https://twitter.com/coda"&gt;@coda&lt;/a&gt;.  
I was able to easily get things working fairly quickly and wrote the following WorkoutService.scala:
&lt;/p&gt;
&lt;pre class="brush: scala"&gt;
package controllers.api

import play.mvc.Controller
import models._
import com.codahale.jerkson.Json._

object WorkoutService extends Controller {

  def workouts = {
    response.setContentTypeIfNotSet("application/json")
    generate(Workout.find().list())
  }
  def edit(id: Long) = {
    generate(Workout.byIdWithAthleteAndComments(id))
  }

  def create() = {
    var workout = params.get("workout", classOf[Workout])
    Workout.create(workout)
  }

  def save(id: Option[Long]) = {
    var workout = params.get("workout", classOf[Workout])
    Workout.update(workout)
  }

  def delete(id: Long) = {
    Workout.delete("id={id}").on("id" -&gt; id).executeUpdate()
  }
}
&lt;/pre&gt;
&lt;p&gt;Next, I added routes for my new API to &lt;em&gt;conf/routes&lt;/em&gt;:
&lt;/p&gt;
&lt;pre&gt;
GET     /api/workouts               api.WorkoutService.workouts
GET     /api/workout/{id}           api.WorkoutService.edit
POST    /api/workout                api.WorkoutService.create
PUT     /api/workout/{id}           api.WorkoutService.save
DELETE  /api/workout/{id}           api.WorkoutService.delete
&lt;/pre&gt;
&lt;p&gt;
Then I created an ApiTest.scala class that verifies the first method works as expected.&lt;/p&gt;
&lt;pre class="brush: scala"&gt;
import play.test.FunctionalTest
import play.test.FunctionalTest._
import org.junit._

class ApiTests extends FunctionalTest {
  
    @Test
    def testGetWorkouts() {
        var response = GET("/api/workouts");
        assertStatus(200, response);
        assertContentType("application/json", response)
        println(response.out)
    }
}
&lt;/pre&gt;
&lt;p&gt;
I ran "play test", opened my browser to http://localhost:9000/@tests and clicked ApiTests -&gt; Start to verify it worked. All the green made me happy.
&lt;/p&gt;
&lt;p style="text-align: center"&gt;
&lt;a href="http://farm8.staticflickr.com/7180/6869080391_5a163cb28e.jpg" title="Play More API Tests" rel="lightbox[playmore-json]"&gt;&lt;img src="http://farm8.staticflickr.com/7180/6869080391_5a163cb28e_m.jpg" width="240" height="184" alt="Play More API Tests"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Finally, I wrote some CoffeeScript and jQuery to allow users to delete workouts and make sure delete functionality worked.&lt;/p&gt;
&lt;pre class="brush: js"&gt;
$('#delete').click -&gt;
  $.ajax
    type: 'POST'
    url: $(this).attr('rel')
    error: -&gt;
      alert('Delete failed, please try again.')
    success: (data) -&gt;
      location.href = "/more"
&lt;/pre&gt;
&lt;p&gt;I was very impressed with how easy Play made it to create JSON services and I smiled as my CoffeeScript skills got a refresher.&lt;/p&gt;
&lt;p&gt;The Friday before we left for Devoxx, I saw the &lt;a href="http://groups.google.com/group/play-framework/browse_thread/thread/1cdebc6f54ec3e6f"&gt;module registration request for SecureSocial&lt;/a&gt;.
&lt;p id="securesocial"&gt;&lt;strong&gt;SecureSocial with Play Scala&lt;/strong&gt;&lt;br/&gt;
From SecureSocial's &lt;a href="https://github.com/jaliss/securesocial"&gt;README&lt;/a&gt;:&lt;/p&gt;
&lt;div class="quote" style="color: #666; margin-left: 0; margin-bottom: 10px"&gt;
&lt;p&gt;SecureSocial allows you to add an authentication UI to your app that works with services based on OAuth1, OAuth2, OpenID and OpenID+OAuth hybrid protocols.
&lt;/p&gt;
&lt;p&gt;
It also provides a Username and Password mechanism for users that do not wish to use existing accounts in other networks.
&lt;/p&gt;
&lt;p&gt;
The following services are supported in this release:
&lt;/p&gt;
&lt;ul style="margin-bottom: 0"&gt;
&lt;li&gt;Twitter (OAuth1)&lt;/li&gt;
	&lt;li&gt;Facebook (OAuth2)&lt;/li&gt;
	&lt;li&gt;Google (OpenID + OAuth Hybrid)&lt;/li&gt;
	&lt;li&gt;Yahoo (OpenID + OAuth Hybrid)&lt;/li&gt;
	&lt;li&gt;LinkedIn (OAuth1)&lt;/li&gt;
	&lt;li&gt;Foursquare (OAuth2)&lt;/li&gt;
	&lt;li&gt;MyOpenID (OpenID)&lt;/li&gt;
	&lt;li&gt;Wordpress (OpenID)&lt;/li&gt;
	&lt;li&gt;Username and Password&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;In other words, it sounded like a dream come true and I resolved to try it once I found the time. That time found me last Monday evening and I sent a direct message to &lt;a href="http://twitter.com/jaliss"&gt;@jaliss&lt;/a&gt; (the module's author) via Twitter.
&lt;/p&gt;
&lt;p class="quote" style="color: #666"&gt;
Does Secure Social work with Play Scala? I'd like to use it in my Play More! project.
&lt;/p&gt;
&lt;p&gt;Jorge responded 16 minutes later saying that he hadn't used Play Scala and he'd need to do some research. At 8 o'clock that night (1.5 hours after my original DM), Jorge had a sample working and emailed it to me. 10 minutes later I was adding a Secure trait to my project.
&lt;/p&gt;
&lt;pre class="brush: scala"&gt;
package controllers

import play.mvc._
import controllers.securesocial.SecureSocial

/*
 * @author Jorge Aliss &amp;lt;jaliss@gmail.com&gt; of Secure Social fame.
 */
trait Secure {
  self: Controller =&gt;

  @Before def checkAccess() {
    SecureSocial.DeadboltHelper.beforeRoleCheck()
  }

  def currentUser = {
    SecureSocial.getCurrentUser
  }
}
&lt;/pre&gt;
&lt;p&gt;I configured Twitter and Username + Password as my providers by adding the following to &lt;em&gt;conf/application.conf&lt;/em&gt;.
&lt;/p&gt;
&lt;pre&gt;
securesocial.providers=twitter,userpass
&lt;/pre&gt;
&lt;p&gt;I also had to configure a number of securesocial.twitter.* properties. Next, I made sure my routes were aware of SecureSocial by adding the following to the top of &lt;em&gt;conf/routes&lt;/em&gt;:
&lt;pre&gt;
  *       /auth               module:securesocial
&lt;/pre&gt;
&lt;p&gt;Then I specified it as a dependency in &lt;em&gt;conf/dependencies.yml&lt;/em&gt; and ran "play deps".
&lt;/p&gt;
&lt;pre&gt;
    - play -&gt; securesocial 0.2.4
&lt;/pre&gt;
&lt;p&gt;After adding "with Secure" to my Profile.scala controller, I tried to access its route and was prompted to login. Right off the bat, I was shown an error about a missing jQuery 1.5.2 file in my "javascripts" folder, so I added it and rejoiced when I was presented with a login screen. I had to add the app on Twitter to use its OAuth servers, but I was pumped when both username/password authentication worked (complete with signup!) as well as Twitter. 
&lt;/p&gt;
&lt;p&gt;
The only issue I ran into with SecureSocial was that it didn't find the default implementation of SecureSocial's UserService.Service when running in prod mode. I was able to workaround this by adding a SecureService.scala implementation to my project and coding it to talk to my Athlete model. I didn't bother to hook in creating a new user when they logged in from Twitter, but that's something I'll want to do in the future. I was also pleased to find out customizing SecureSocial's views was a breeze. I simply copied them from the module into my app's views and &lt;em&gt;voila!&lt;/em&gt;
&lt;/p&gt;
&lt;pre class="brush: scala"&gt;
package services

import play.db.anorm.NotAssigned
import play.libs.Codec
import collection.mutable.{SynchronizedMap, HashMap}
import models.Athlete
import securesocial.provider.{ProviderType, UserService, SocialUser, UserId}

class SecureService extends UserService.Service {
  val activations = new HashMap[String, SocialUser] with SynchronizedMap[String, SocialUser]

  def find(userId: UserId): SocialUser = {
    val user = Athlete.find("email={email}").on("email" -&gt; userId.id).first()

    user match {
      case Some(user) =&gt; {
        val socialUser = new SocialUser
        socialUser.id = userId
        socialUser.displayName = user.firstName
        socialUser.email = user.email
        socialUser.isEmailVerified = true
        socialUser.password = user.password
        socialUser
      }
      case None =&gt; {
        if (!userId.provider.eq(ProviderType.userpass)) {
          var socialUser = new SocialUser
          socialUser.id = userId
          socialUser
        } else {
          null
        }
      }
    }
  }

  def save(user: SocialUser) {
    if (find(user.id) == null) {
      val firstName = user.displayName
      val lastName = user.displayName
      Athlete.create(Athlete(NotAssigned, user.email, user.password, firstName, lastName))
    }
  }

  def createActivation(user: SocialUser): String = {
    val uuid: String = Codec.UUID()
    activations.put(uuid, user)
    uuid
  }

  def activate(uuid: String): Boolean = {
    val user: SocialUser = activations.get(uuid).asInstanceOf[SocialUser]
    var result = false

    if (user != null) {
      user.isEmailVerified = true
      save(user)
      activations.remove(uuid)
      result = true
    }

    result
  }

  def deletePendingActivations() {
    activations.clear()
  }
}
&lt;/pre&gt;
&lt;p&gt;Jorge was a great help in getting my authentication needs met and he even wrote a BasicAuth.scala trait to implement Basic Authentication on my JSON services.
&lt;/p&gt;
&lt;pre class="brush: scala"&gt;
package controllers

import _root_.securesocial.provider.{UserService, ProviderType, UserId}
import play._
import play.mvc._
import play.libs.Crypto

import controllers.securesocial.SecureSocial

/*
 * @author Jorge Aliss &amp;lt;jaliss@gmail.com&gt; of Secure Social fame.
 */
trait BasicAuth {
  self: Controller =&gt;

  @Before def checkAccess = {
    if (currentUser != null) {
      // this allows SecureSocial.getCurrentUser() to work.
      renderArgs.put("user", currentUser)
      Continue
    }

    val realm =
      Play.configuration.getProperty("securesocial.basicAuth.realm", "Unauthorized")

    if (request.user == null || request.password == null) {
      Unauthorized(realm)
    } else {
      val userId = new UserId
      userId.id = request.user
      userId.provider = ProviderType.userpass
      val user = UserService.find(userId)

      if (user == null ||
        !Crypto.passwordHash(request.password).equals(user.password)) {
        Unauthorized(realm)
      } else {
        // this allows SecureSocial.getCurrentUser() to work.
        renderArgs.put("user", user)
        Continue
      }
    }
  }

  def currentUser = {
    SecureSocial.getCurrentUser()
  }
}
&lt;/pre&gt;
&lt;p id="summary"&gt;
&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
My latest pass at developing with Scala and leveraging Play to build my app was a lot of fun. While there were issues with class reloading every-so-often and &lt;a href="http://groups.google.com/group/scalate/browse_thread/thread/ddf455ec8676abf1"&gt;Scala versions with Scalate&lt;/a&gt;, I was able to add the features I wanted. I wasn't able to upgrade to Play 2.0, but I didn't try that hard and figured it's best to wait until its upgrade guide has been published. 
&lt;/p&gt;
&lt;p&gt;
I'm excited to describe my latest experience to the developers at Jfokus this week. In addition, the conference has talks on &lt;a href="http://www.jfokus.se/jfokus/talks.jsp#Play%20Framework%202.0"&gt;Play 2.0&lt;/a&gt;, &lt;a href="http://www.jfokus.se/jfokus/talks.jsp#CoffeeScript%3A%20JavaScript%20without%20the%20Fail"&gt;CoffeeScript&lt;/a&gt;, &lt;a href="http://www.jfokus.se/jfokus/talks.jsp#Client-side%20Storage%3A%20When%20%26%20How"&gt;HTML5&lt;/a&gt;, &lt;a href="http://www.jfokus.se/jfokus/talks.jsp#Scala%20in%20Action"&gt;Scala&lt;/a&gt; and &lt;a href="http://www.jfokus.se/jfokus/talks.jsp#Introducing%20Scalate%2C%20the%20Scala%20Template%20Engine"&gt;Scalate&lt;/a&gt;. I hope to attend many of these and learn some new tricks to improve my skills and my app. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; The Delving developers have written an article on &lt;a href="http://delving.eu/node/27"&gt;Migration to Play 2&lt;/a&gt;. While it doesn't provide specific details on what they needed to change, it does have good information on how long it took and things to watch for.</description>
      <pubDate>Fri, 29 Jun 2012 16:00:52 CDT</pubDate>
      <guid isPermaLink="true">http://raibledesigns.com/rd/entry/secure_json_services_with_play</guid>
      <dc:creator>Matt Raible</dc:creator>
    </item>
    <item>
      <title>My HTML5 with Play Scala, CoffeeScript and Jade Presentation from Devoxx 2011</title>
      <link>http://projectautomationexperience.com/blog/matt_raible/2012/06/my_html5_with_play_scala_coffeescript_and_jade_presentation_from_devoxx_2011?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>This week, I had the pleasure of traveling to one of my favorite places in the world: Antwerp, Belgium. Like &lt;a href="http://raibledesigns.com/rd/entry/an_awesome_trip_to_amsterdam"&gt;last year&lt;/a&gt;, I traveled with the lovely &lt;a href="http://mcginityphoto.com"&gt;Trish McGinity&lt;/a&gt; and spoke at &lt;a href="http://www.devoxx.com/display/DV11/Home"&gt;Devoxx 2011&lt;/a&gt;. This year, my talk was on developing a web/mobile app with HTML5, Play, Scala, CoffeeScript and Jade. I was inspired to learn Scala at the beginning of this year and added CoffeeScript and Jade to my learning list after talking to James Strachan at TSSJS 2011. You can read more about how my journey began in my &lt;a href="http://raibledesigns.com/rd/entry/integrating_scalate_and_jade_with"&gt;first post about learning these technologies&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;I started developing with these technologies in August and wrote about my learnings throughout the process. Last week, while writing my presentation, I decided it'd be fun to make my presentation into more of a story-telling-session than a learn-about-new-technologies session. To do this, I focused on talking a bit about the technologies, but more about my experience learning them. I also came up with a challenging idea: create a video that showed the development process, how hard it was to test the app and (hopefully) my success in getting it to work.&lt;/p&gt;
&lt;p&gt;It was all a very close call, but I'm happy to say I pulled it off! I got the app to work on an iPhone (&lt;a href="http://raibledesigns.com/rd/entry/phonegap_to_the_rescue"&gt;thanks to PhoneGap&lt;/a&gt;) last Saturday, finished the first draft of my presentation on Sunday night (after pulling an all-nighter) and finished editing the demo video on Wednesday night. My talk was on Thursday afternoon and I had a blast talking about my experience to such a large, enthusiastic audience. You can see the presentation below, &lt;a href="http://www.slideshare.net/mraible/html5-with-play-scala-coffeescript-and-jade-devoxx-2011"&gt;on Slideshare&lt;/a&gt; or &lt;a href="http://static.raibledesigns.com/repository/presentations/HTML5_with_Play_Scala_CoffeeScript_and_Jade_Devoxx2011.pdf"&gt;download the PDF&lt;/a&gt;.&lt;/p&gt;
&lt;p style="text-align: center"&gt;
&lt;iframe src="http://www.slideshare.net/slideshow/embed_code/10204272?rel=0" width="510" height="426" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;You can find the "demo" for this talk &lt;a href="http://www.youtube.com/watch?v=bBqtPPfM2xQ"&gt;on YouTube&lt;/a&gt; or watch it below.
&lt;/p&gt;
&lt;p style="text-align: center"&gt;
&lt;iframe width="510" height="289" src="http://www.youtube.com/embed/bBqtPPfM2xQ?rel=0&amp;amp;hd=1" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;One of the reasons I really enjoyed this talk is it only represents one milestone in my learning process. I plan on continuing to develop this application and learning more about HTML5, Scala, Play and CoffeeScript and Scalate/Jade. Now that &lt;a href="http://raibledesigns.com/rd/entry/play_2_0_a_web"&gt;Play 2.0 Beta has been released&lt;/a&gt;, I plan on upgrading to it and leveraging its native CoffeeScript and LESS support. I hope to continue using &lt;a href="http://scalate.fusesource.org/"&gt;Scalate&lt;/a&gt; and its &lt;a href="http://scalate.fusesource.org/documentation/jade.html"&gt;Jade&lt;/a&gt; format. And it's very likely &lt;a href="http://phonegap.com/"&gt;PhoneGap&lt;/a&gt; will continue to be &lt;em&gt;the bridge&lt;/em&gt; that allows everything to run in the background.&lt;/p&gt;
&lt;p&gt;I've been talking with the &lt;a href="www.jfokus.se/"&gt;Jfokus&lt;/a&gt; folks about doing this talk in Sweden in Feburary and &lt;a href="http://devoxx.fr"&gt;Devoxx France&lt;/a&gt; about presenting there in April. 
&lt;/p&gt;
&lt;p&gt;Learning all these technologies has been a challenging, but fun experience so far. As the last slide in my presentation says, I encourage you to do something similar. Pick something new to learn, have fun doing it, but more importantly - get out there and &lt;em&gt;Play!&lt;/em&gt;
&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Update Dec. 20th:&lt;/strong&gt; A video of this presentation is &lt;a href="http://parleys.com/d/2925"&gt;now available on Parleys.com&lt;/a&gt;.</description>
      <pubDate>Fri, 29 Jun 2012 13:01:10 CDT</pubDate>
      <guid isPermaLink="true">http://raibledesigns.com/rd/entry/my_html5_with_play_scala</guid>
      <dc:creator>Matt Raible</dc:creator>
    </item>
  </channel>
</rss>

