<?xml version="1.0" encoding='utf-8'?>
<?xml-stylesheet type="text/xsl" href="https://raibledesigns.com/roller-ui/styles/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:app="http://www.w3.org/2007/app"
      xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">

    <title type="html">Search for [mvc] in weblog rd</title>
    <subtitle type="html">Search results for [mvc] within weblog Raible Designs</subtitle>
    <id>https://raibledesigns.com/rd/feed/entries/atom?q=mvc</id>

    <link rel="self" type="application/atom+xml" 
        href="https://raibledesigns.com/rd/feed/entries/atom?q=mvc" />

    <link rel="alternate" type="text/html" 
        href="https://raibledesigns.com/rd/search?q=mvc" />

    <link rel="search" type="application/opensearchdescription+xml" 
        href="https://raibledesigns.com/roller-services/opensearch/rd" />
    <opensearch:Query role="request" searchTerms="mvc" startPage="1" />

    <link rel="first" type="application/atom+xml" href="https://raibledesigns.com/rd/feed/entries/atom?q=mvc" />
    <link rel="next" type="application/atom+xml" href="https://raibledesigns.com/rd/feed/entries/atom?q=mvc&amp;page=1" />
    <updated>2026-05-19T22:36:52-06:00</updated>
    <generator uri="http://roller.apache.org" version="5.0.3 (1388864191739:dave)">Apache Roller</generator>

        <entry>
        <id>https://raibledesigns.com/rd/entry/2018_a_year_in_review</id>
        <title type="html">2018 - A Year in Review</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/2018_a_year_in_review"/>
        <published>2019-01-29T13:25:24-07:00</published>
        <updated>2024-05-21T21:21:22-06:00</updated> 
        <category term="/General" label="General" />
        <category term="family" scheme="http://roller.apache.org/ns/tags/" />
        <category term="roller" scheme="http://roller.apache.org/ns/tags/" />
        <category term="hefethebus" scheme="http://roller.apache.org/ns/tags/" />
        <category term="blogging" scheme="http://roller.apache.org/ns/tags/" />
        <category term="syncro" scheme="http://roller.apache.org/ns/tags/" />
        <category term="okta" scheme="http://roller.apache.org/ns/tags/" />
        <category term="apacheroller" scheme="http://roller.apache.org/ns/tags/" />
        <category term="porschebus" scheme="http://roller.apache.org/ns/tags/" />
        <category term="stoutthesyncro" scheme="http://roller.apache.org/ns/tags/" />
        <category term="2018" scheme="http://roller.apache.org/ns/tags/" />
        <category term="yearinreview" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;In 2018, I spoke at several fantastic meetups, traveled a bit overseas, and enjoyed some fun family vacations. We had the time of our lives driving Hefe in the Denver St. Paddy&apos;s Day Parade!&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;https://farm5.staticflickr.com/4782/40902535612_9fcc94e853_c.jpg&quot; title=&quot;Bubbles&quot; rel=&quot;lightbox[2018yearinreview]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/40902535612/in/album-72157689027458320/&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4782/40902535612_9fcc94e853.jpg&quot; width=&quot;500&quot; alt=&quot;Bubbles&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    We traveled to Crete for JCrete and had a blast with the Java community. We journeyed to Ireland with my folks, and I thoroughly enjoyed a speaking tour of Ireland JUGs and the Dublin JHipster Meetup. Our classic VWs had a great year with only minor repairs needed.
&lt;/p&gt;

&lt;p&gt;I&apos;m going to look back on 2018 using the following categories.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#professional&quot;&gt;Professional&lt;/a&gt;
        &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#speaking&quot;&gt;Speaking&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#community&quot;&gt;Community&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#projects&quot;&gt;Projects&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#personal&quot;&gt;Personal&lt;/a&gt;
        &lt;!--ul&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#stout-and-hefe&quot;&gt;Stout and Hefe&lt;/a&gt;&lt;/li&gt;
        &lt;/ul--&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#2019&quot;&gt;2019&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;professional&quot;&gt;Professional&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;For those stumbling upon this post with no context, I&apos;m a veteran open source developer that works at &lt;a href=&quot;https://okta.com&quot;&gt;Okta&lt;/a&gt; as a developer advocate.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
This year I focused on blogging more than speaking. I still spoke a fair bit, but I tried to focus on meetups more than conferences. The DevEx Team at Okta released a slew of SDKs at the end of 2017, so I had plenty to write about. Over the year, I found more and more developers had heard of Okta during my talks. I even found users in most audiences! This was quite a change from 2017, so it seems my team&apos;s advocacy efforts might be working.
&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;In 2018, I spoke at several fantastic meetups, traveled a bit overseas, and enjoyed some fun family vacations. We had the time of our lives driving Hefe in the Denver St. Paddy&apos;s Day Parade!&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;https://farm5.staticflickr.com/4782/40902535612_9fcc94e853_c.jpg&quot; title=&quot;Bubbles&quot; rel=&quot;lightbox[2018yearinreview]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/40902535612/in/album-72157689027458320/&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4782/40902535612_9fcc94e853.jpg&quot; width=&quot;500&quot; alt=&quot;Bubbles&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    We traveled to Crete for JCrete and had a blast with the Java community. We journeyed to Ireland with my folks, and I thoroughly enjoyed a speaking tour of Ireland JUGs and the Dublin JHipster Meetup. Our classic VWs had a great year with only minor repairs needed.
&lt;/p&gt;

&lt;p&gt;I&apos;m going to look back on 2018 using the following categories.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#professional&quot;&gt;Professional&lt;/a&gt;
        &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#speaking&quot;&gt;Speaking&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#community&quot;&gt;Community&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#projects&quot;&gt;Projects&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#personal&quot;&gt;Personal&lt;/a&gt;
        &lt;!--ul&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#stout-and-hefe&quot;&gt;Stout and Hefe&lt;/a&gt;&lt;/li&gt;
        &lt;/ul--&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2018_a_year_in_review#2019&quot;&gt;2019&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;professional&quot;&gt;Professional&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;For those stumbling upon this post with no context, I&apos;m a veteran open source developer that works at &lt;a href=&quot;https://okta.com&quot;&gt;Okta&lt;/a&gt; as a developer advocate.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
This year I focused on blogging more than speaking. I still spoke a fair bit, but I tried to focus on meetups more than conferences. The DevEx Team at Okta released a slew of SDKs at the end of 2017, so I had plenty to write about. Over the year, I found more and more developers had heard of Okta during my talks. I even found users in most audiences! This was quite a change from 2017, so it seems my team&apos;s advocacy efforts might be working.
&lt;/p&gt;
&lt;p&gt;
    I wrote 29 blog posts throughout the year on &lt;a href=&quot;https://developer.okta.com/blog&quot;&gt;the Okta developer blog&lt;/a&gt;. &lt;!-- If you count nine on raibledesigns.com and five on jhipster-book.com, that&apos;s 43! --&gt; We publish two types of blog posts: thought leadership and conversion. Thought leadership posts tend to be about a hot topic while conversion posts are generally tutorials. I wrote a series of posts on PWAs with Ionic + Angular and Spring Boot. The series started in January and ended in July.
&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/01/18/cryptocurrency-pwa-secured-by-okta&quot;&gt;Protect Your Cryptocurrency Wealth Tracking PWA with Okta&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/01/23/replace-local-storage-with-okta-profile-attributes&quot;&gt;Use Okta (Instead of Local Storage) to Store Your User&apos;s Data Securely&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/05/02/testing-spring-boot-angular-components&quot;&gt;The Hitchhiker&apos;s Guide to Testing Spring Boot APIs and Angular Components with WireMock, Jest, Protractor, and Travis CI&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/06/18/spring-boot-angular-auth-code-flow&quot;&gt;Deploy Your Secure Spring Boot + Angular PWA as a Single Artifact&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/07/11/ci-cd-spring-boot-jenkins-x-kubernetes&quot;&gt;Add CI/CD to Your Spring Boot App with Jenkins X and Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I also wrote a number of posts on &lt;a href=&quot;https://www.jhipster.tech&quot;&gt;JHipster&lt;/a&gt;, starting with &lt;a href=&quot;https://developer.okta.com/blog/2018/01/30/jhipster-ionic-with-oidc-authentication&quot;&gt;Ionic for JHipster&lt;/a&gt;. Then I transitioned to microservices and showed &lt;a href=&quot;https://developer.okta.com/blog/2018/02/13/secure-spring-microservices-with-oauth&quot;&gt;how to build a Spring microservices architecture with Spring Security and OAuth 2.0&lt;/a&gt;. I felt this was important, as it&apos;s the same basic architecture that JHipster uses.&lt;/p&gt;
&lt;p&gt;
    I published &lt;a href=&quot;https://developer.okta.com/blog/2018/03/01/develop-microservices-jhipster-oauth&quot;&gt;Develop a Microservices Architecture with OAuth 2.0 and JHipster&lt;/a&gt;, and had two more JHipster posts about its React and React Native support.
&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/06/25/react-spring-boot-photo-gallery-pwa&quot;&gt;Build a Photo Gallery PWA with React, Spring Boot, and JHipster&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/10/10/react-native-spring-boot-mobile-app&quot;&gt;Build a Mobile App with React Native and Spring Boot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I learned about React and React Native from research I did while writing previous posts.&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/03/16/build-react-native-authentication-oauth-2&quot;&gt;Build a React Native Application and Authenticate with OAuth 2.0&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/07/19/simple-crud-react-and-spring-boot&quot;&gt;Use React and Spring Boot to Build a Simple CRUD App&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
    I stayed current on the latest releases of Angular and Spring Boot because I &amp;#x2764; them both!
&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/05/09/upgrade-to-angular-6&quot;&gt;Angular 6: What&apos;s New, and Why Upgrade
    &lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/11/26/spring-boot-2-dot-1-oidc-oauth2-reactive-apis&quot;&gt;Spring Boot 2.1: Outstanding OIDC, OAuth 2.0, and Reactive API Support&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/12/04/angular-7-oidc-oauth2-pkce&quot;&gt;Angular 7: What&apos;s New and Noteworthy + OIDC Goodness&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/08/22/basic-crud-angular-7-and-spring-boot-2&quot;&gt;Build a Basic CRUD App with Angular 7.0 and Spring Boot 2.1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
    I heard from several developers that they wanted to use Okta with their Java apps, but they weren&apos;t using Spring. Or they were using Spring MVC, but not Spring Boot. I wrote &lt;a href=&quot;https://developer.okta.com/blog/2018/09/12/secure-java-ee-rest-api&quot;&gt;Build a Java REST API with Java EE and OIDC&lt;/a&gt; to show a few authn/authz techniques: JWT validation, using Spring Security, and using Pac4j.
&lt;/p&gt;
&lt;p&gt;I had a blast in August and September collaborating with Josh Long about going &lt;a href=&quot;https://youtu.be/1xpwYe154Ys&quot;&gt;Full Stack Reactive with Spring WebFlux and React&lt;/a&gt;. Josh authored his parts with AsciiDoc and forced me to integrate &lt;a href=&quot;https://asciidoctor.org/&quot;&gt;Asciidoctor&lt;/a&gt; support in our blog. It took awhile, but I was thrilled with the result. Now I get to author all my blog posts with AsciiDoc! &amp;#x1F389;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/09/21/reactive-programming-with-spring&quot;&gt;Get Started with Reactive Programming in Spring&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/09/24/reactive-apis-with-spring-webflux&quot;&gt;Build Reactive APIs with Spring WebFlux&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/09/25/spring-webflux-websockets-react&quot;&gt;Full Stack Reactive with Spring WebFlux, WebSockets, and React&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
    I played with other new technologies in 2018, namely &lt;a href=&quot;https://developer.okta.com/blog/2018/07/11/build-react-graphql-api-user-authentication&quot;&gt;GraphQL and TypeORM&lt;/a&gt;, &lt;a href=&quot;https://developer.okta.com/blog/2018/09/17/desktop-app-electron-authentication&quot;&gt;Electron&lt;/a&gt;, and &lt;a href=&quot;https://developer.okta.com/blog/2018/12/03/bootiful-spring-boot-java-vue-typescript&quot;&gt;Vue with TypeScript&lt;/a&gt;.
&lt;/p&gt;
&lt;h3&gt;The Super Epic Advocacy Battle!&lt;/h3&gt;
&lt;p&gt;
    I was super motivated to write a bunch of blog posts in June and July because I was having a &quot;most views&quot; contest with &lt;a href=&quot;https://twitter.com/rdegges&quot;&gt;Randall Degges&lt;/a&gt;. The contest started after I mouthed off that I thought I could outperform him in the waning hours of our Oktane 2018 conference. He accepted my challenge and we competed for two months. He wrote mostly thought leadership posts, I wrote mostly tutorials. Long story short: he won. I had to wear gold pants the week of CodeOne for my lack of winning.
&lt;/p&gt;
&lt;div style=&quot;margin: 0 auto; max-width: 500px&quot;&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Hanging out at Oracle Code One conf with my buddy &lt;a href=&quot;https://twitter.com/mraible?ref_src=twsrc%5Etfw&quot;&gt;@mraible&lt;/a&gt; and his amazing MC Hammer pants.&lt;br&gt;&lt;br&gt;I wonder why he&amp;#39;s wearing them? :D&lt;br&gt;&lt;br&gt;He&amp;#39;s about to get onstage to talk about micro services &amp;lt;33333 &lt;a href=&quot;https://t.co/syoiIeSDMc&quot;&gt;pic.twitter.com/syoiIeSDMc&lt;/a&gt;&lt;/p&gt;&amp;mdash; Randall Degges (@rdegges) &lt;a href=&quot;https://twitter.com/rdegges/status/1054452785725358080?ref_src=twsrc%5Etfw&quot;&gt;October 22, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;
If only I&apos;d published &lt;a href=&quot;https://developer.okta.com/blog/2018/07/30/10-ways-to-secure-spring-boot&quot;&gt;10 Excellent Ways to Secure Your Spring Boot Application&lt;/a&gt; earlier in our contest. I collaborated on it with &lt;a href=&quot;https://twitter.com/sjmaple&quot;&gt;Simon Maple&lt;/a&gt;, and it seemed to be popular.
&lt;/p&gt;
&lt;p&gt;
I wrote a few other thought leadership posts throughout 2018:
&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/03/19/how-to-be-productive-at-work&quot;&gt;How to Achieve Massive Productivity at Work&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/11/20/three-developer-tools-im-thankful-for&quot;&gt;Three Developer Tools I&apos;m Thankful For&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developer.okta.com/blog/2018/12/11/learning-java-first-language&quot;&gt;Learning Java as a First Language&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;speaking&quot;&gt;Speaking&lt;/h3&gt;
&lt;p&gt;
    According to TripIt, I took 26 trips, to 37 cities, in 6 countries. That&apos;s three fewer trips than 2017, and I only had 119 days on the road (versus 141). By my count, I spoke at 20 events.
&lt;/p&gt;
&lt;table&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;ol&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/DOSUG1&quot;&gt;Denver Open Source Users Group&lt;/a&gt; (DOSUG)&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;http://ujug.org/&quot;&gt;Utah JUG&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;http://seajug.org/&quot;&gt;Seattle JUG&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/Google-Developer-Group-Boulder/&quot;&gt;GDG Boulder&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/Richmond-Java-Users-Group/&quot;&gt;Richmond JUG&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.okta.com/oktane18/&quot;&gt;Oktane&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://jhipster-conf.github.io/&quot;&gt;JHipsterConf&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://uberconf.com/conference/denver/2018/07/home&quot;&gt;UberConf&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/boston-java/&quot;&gt;Boston JUG&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/BelfastJUG/&quot;&gt;Belfast JUG&lt;/a&gt;&lt;/li&gt;
            &lt;/ol&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;ol start=&quot;11&quot;&gt;
                &lt;li&gt;&lt;a href=&quot;http://www.dubjug.org/&quot;&gt;Dublin JUG&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/JHipsterDublin/&quot;&gt;JHipster Dublin&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;Denver Okta User Group&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://springoneplatform.io/&quot;&gt;SpringOne Platform&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;Salt Lake City Okta User Group&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/Denver-Cloud-Security-Alliance-Meetup/&quot;&gt;Denver CSA Meetup&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;http://connect.tech/&quot;&gt;Connect.Tech&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.oracle.com/code-one/&quot;&gt;CodeOne&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/ChicagoJUG/&quot;&gt;Chicago JUG&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;https://therichwebexperience.com/conference/clearwater/2018/12/home&quot;&gt;The Rich Web Experience&lt;/a&gt;&lt;/li&gt;
            &lt;/ol&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/jhipsterconf_2018_summer_solstice_in&quot;&gt;JHipsterConf was especially fun&lt;/a&gt; because I took my son, Jack, with me. &lt;/p&gt;
&lt;div style=&quot;margin: 0 auto; max-width: 500px&quot;&gt;
    &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;I had a wonderful time this week in Paris and at &lt;a href=&quot;https://twitter.com/jhipsterconf?ref_src=twsrc%5Etfw&quot;&gt;@jhipsterconf&lt;/a&gt;. Many thanks to the &lt;a href=&quot;https://twitter.com/java_hipster?ref_src=twsrc%5Etfw&quot;&gt;@java_hipster&lt;/a&gt; developers, community, &lt;a href=&quot;https://twitter.com/juliendubois?ref_src=twsrc%5Etfw&quot;&gt;@juliendubois&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/deepu105?ref_src=twsrc%5Etfw&quot;&gt;@deepu105&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/ippontech?ref_src=twsrc%5Etfw&quot;&gt;@ippontech&lt;/a&gt; for making it all possible! &lt;a href=&quot;https://twitter.com/hashtag/JHipsterConf?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#JHipsterConf&lt;/a&gt; &lt;a href=&quot;https://t.co/61ZfRZxg8G&quot;&gt;pic.twitter.com/61ZfRZxg8G&lt;/a&gt;&lt;/p&gt;&amp;mdash; Matt Raible (@mraible) &lt;a href=&quot;https://twitter.com/mraible/status/1010477663943909377?ref_src=twsrc%5Etfw&quot;&gt;June 23, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;
    I also attended a few conferences that I did not speak at: &lt;a href=&quot;https://www.iterateconf.io/&quot;&gt;Iterate&lt;/a&gt;, &lt;a href=&quot;http://www.jcrete.org/&quot;&gt;JCrete&lt;/a&gt;, and &lt;a href=&quot;https://monktoberfest.com/&quot;&gt;Monktoberfest&lt;/a&gt;. All of these were special in their own ways. JCrete was an unconference in an exotic location (Crete, Greece) and was a fantastic experience. I learned that 1) it&apos;s important to rent a car if you bring your family and 2) an unconference is what you make of it. Put a lot into it, and you&apos;ll get a lot out of it. As a speaker, I think it&apos;s a fantastic conference format because it&apos;s an excellent networking atmosphere. You can also learn a lot if there are peers with expertise in the topic you&apos;re interested in. Monktoberfest also provided next-level networking.
&lt;/p&gt;

&lt;h3 id=&quot;community&quot;&gt;Community&lt;/h3&gt;
&lt;p&gt;I was involved in many community activities in 2018: &lt;a href=&quot;https://www.meetup.com/Devoxx4Kids-Denver/&quot;&gt;Devoxx4Kids Denver&lt;/a&gt;,
    &lt;a href=&quot;https://www.meetup.com/DenverJavaUsersGroup/&quot;&gt;Denver JUG&lt;/a&gt;, &lt;a href=&quot;https://www.meetup.com/DenverMicroservices/&quot;&gt;Denver Microservices Meetup&lt;/a&gt;, and I attended a few &lt;a href=&quot;https://www.meetup.com/DOSUG1/&quot;&gt;DOSUG&lt;/a&gt; meetups too.&lt;/p&gt;
&lt;p&gt;We had three Devoxx4Kids Denver workshops in 2018:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/Devoxx4Kids-Denver/events/247280135/&quot;&gt;Create 3D Models and Animations with Blender&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/Devoxx4Kids-Denver/events/249912127/&quot;&gt;Building Games With Unity&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.meetup.com/Devoxx4Kids-Denver/events/256271996/&quot;&gt;Gotta Catch &#8216;Em All! Raspberry Pi and Java Pokemon Training&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
    Thanks to &lt;a href=&quot;https://twitter.com/elgatodekaitlyn&quot;&gt;Kaitlyn Hornbuckle&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/james-sablatura-9235b350/&quot;&gt;James Sablatura&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/tingsterchin&quot;&gt;Cassandra Chin&lt;/a&gt; for teaching these classes.
&lt;/p&gt;
&lt;div style=&quot;margin: 0 auto; max-width: 500px&quot;&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Finished training Denver Pok&#233;mon Trainers at &lt;a href=&quot;https://twitter.com/hashtag/Devoxx4Kids?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#Devoxx4Kids&lt;/a&gt;.  Gotta catch them all!  &lt;a href=&quot;https://twitter.com/mraible?ref_src=twsrc%5Etfw&quot;&gt;@mraible&lt;/a&gt; &lt;a href=&quot;https://twitter.com/melissajmckay?ref_src=twsrc%5Etfw&quot;&gt;@melissajmckay&lt;/a&gt; &lt;a href=&quot;https://t.co/zQSbIdH7Zb&quot;&gt;pic.twitter.com/zQSbIdH7Zb&lt;/a&gt;&lt;/p&gt;&amp;mdash; Cassandra Chin (@tingsterchin) &lt;a href=&quot;https://twitter.com/tingsterchin/status/1071827255653949440?ref_src=twsrc%5Etfw&quot;&gt;December 9, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;
    We announced the &lt;strong&gt;2018 Denver JUG Rock Stars&lt;/strong&gt; at our December meetup. Venkat, David, and Jeff were voted as the group&apos;s favorite speakers. Y&apos;all were excellent! Thanks for adding DJUG to your schedules.
&lt;/p&gt;
&lt;div style=&quot;margin: 0 auto; max-width: 500px&quot;&gt;
    &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;At this week&amp;#39;s &lt;a href=&quot;https://twitter.com/denverjug?ref_src=twsrc%5Etfw&quot;&gt;@denverjug&lt;/a&gt;, we announced the Denver JUG Rock Stars of 2018. If you want to be entertained, intrigued, &amp;amp; educated: &lt;a href=&quot;https://twitter.com/venkat_s?ref_src=twsrc%5Etfw&quot;&gt;@venkat_s&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/dblevins?ref_src=twsrc%5Etfw&quot;&gt;@dblevins&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/jeffscottbrown?ref_src=twsrc%5Etfw&quot;&gt;@jeffscottbrown&lt;/a&gt; are three of our favorite speakers. &lt;a href=&quot;https://twitter.com/hashtag/denverjug?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#denverjug&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/rockstars?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#rockstars&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/java?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#java&lt;/a&gt;&lt;br&gt;&lt;br&gt;Thanks to &lt;a href=&quot;https://twitter.com/oktadev?ref_src=twsrc%5Etfw&quot;&gt;@oktadev&lt;/a&gt; for sponsoring trophies! &lt;a href=&quot;https://t.co/uTNcDZVCFi&quot;&gt;pic.twitter.com/uTNcDZVCFi&lt;/a&gt;&lt;/p&gt;&amp;mdash; Matt Raible (@mraible) &lt;a href=&quot;https://twitter.com/mraible/status/1073687604741181440?ref_src=twsrc%5Etfw&quot;&gt;December 14, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;h3 id=&quot;projects&quot;&gt;Projects&lt;/h3&gt;
&lt;p&gt;My projects these days are mostly around JHipster. I supported its OAuth 2.0 and OIDC support as best I could, and &lt;a href=&quot;https://github.com/oktadeveloper/generator-jhipster-ionic/releases&quot;&gt;released five versions of its Ionic module&lt;/a&gt;. I wrote about &lt;a href=&quot;https://developer.okta.com/blog/2018/01/30/jhipster-ionic-with-oidc-authentication&quot;&gt;how to use Ionic with JHipster&lt;/a&gt; in late January. I recorded a screencast showing
    &lt;a href=&quot;https://youtu.be/-VQ_SVkaXbs&quot;&gt;how to get started with JHipster 5&lt;/a&gt; in June.
&lt;/p&gt;
&lt;div style=&quot;text-align: center&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/-VQ_SVkaXbs&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;We released the JHipster Mini-Book &lt;a href=&quot;http://www.jhipster-book.com/#!/news/entry/jhipster-mini-book-v4x-released&quot;&gt;version 4.5 in April&lt;/a&gt; and &lt;a href=&quot;https://raibledesigns.com/rd/entry/the_jhipster_mini_book_v5&quot;&gt;version 5.0 in November&lt;/a&gt;. I published a Pluralsight course on &lt;a href=&quot;http://www.jhipster-book.com/#!/news/entry/pluralsight-developing-microservices-and-mobile-apps-with-jhipster-play-by-play&quot;&gt;developing microservices and mobile apps with JHipster&lt;/a&gt; in April and released &lt;a href=&quot;http://www.jhipster-book.com/#!/news/entry/21-points-v5-has-been-released&quot;&gt;21-Points Health 5.0&lt;/a&gt; in October.&lt;/p&gt;

&lt;h2 id=&quot;personal&quot;&gt;Personal&lt;/h2&gt;

&lt;p&gt;
    This year was a mix of work your ass off and try to have fun at the same time. There were many times when we wished we were home, but the times on the road were grand. I suspect this will be a constant battle for Trish and I. We love to be home, but we love to explore new places. If old friends gather with us at home or in new places, it&apos;s bound to be a fantastic evening!
&lt;/p&gt;
&lt;p&gt;
    The biggest change was Abbie became a &lt;em&gt;driver&lt;/em&gt;. For those parents with kids that have to chaperone endlessly throughout the weeks and weekends, you know this is a BFD! As of December 27, 2018, Abbie&apos;s now the captain of the ranch-to-school ship. She even drove in the blowing snow yesterday!
&lt;/p&gt;
&lt;p&gt;There were many highlights in 2019. My early favorite (that makes me tear up as I write this) is &lt;a href=&quot;//raibledesigns.com/rd/entry/hefe_3_5_has_been&quot;&gt;Hefe 3.5&lt;/a&gt;.
&lt;/p&gt;
    &lt;div style=&quot;max-width: 500px; margin: 0 auto&quot;&gt;
        &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;My daughter observed the other day that most people are frowning when they&#8217;re driving. I&#8217;m not one of this people. In fact, I have to wear sunglasses to hide my tears of joy! &amp;#x1F923; &lt;a href=&quot;https://twitter.com/hashtag/HefeTheBus?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#HefeTheBus&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/21windows?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#21windows&lt;/a&gt; &lt;a href=&quot;https://t.co/0LWaQkjZlx&quot;&gt;pic.twitter.com/0LWaQkjZlx&lt;/a&gt;&lt;/p&gt;&amp;mdash; Matt Raible (@mraible) &lt;a href=&quot;https://twitter.com/mraible/status/973996844052180992?ref_src=twsrc%5Etfw&quot;&gt;March 14, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;We had a blast with Trish&apos;s parents &lt;a href=&quot;https://raibledesigns.com/rd/entry/spring_break_2018_sun_fun&quot;&gt;during Spring Break in Florida&lt;/a&gt; and squeezed in a day trip to Disney World.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm1.staticflickr.com/810/26408506757_ba6e81542e_c.jpg&quot; title=&quot;Disney Fireworks!&quot; rel=&quot;lightbox[2018yearinreview]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/26408506757/in/album-72157667508590818/&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/810/26408506757_ba6e81542e.jpg&quot; width=&quot;500&quot; alt=&quot;Disney Fireworks!&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://raibledesigns.com/rd/entry/farewell_to_the_2017_18&quot;&gt;2017-18&lt;/a&gt; ski season didn&apos;t bring a lot of snow, but our ski trip to Utah was wonderful!&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm1.staticflickr.com/970/41365298975_1c2a604378_c.jpg&quot; title=&quot;Alta!&quot; rel=&quot;lightbox[2018yearinreview]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/41365298975/in/dateposted-public/&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/970/41365298975_1c2a604378.jpg&quot; width=&quot;500&quot; alt=&quot;Alta!&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Trish and I celebrated our 5th anniversary at JCrete. I hope the next five years are as adventurous as the last five!&lt;/p&gt;
&lt;div style=&quot;max-width: 500px; margin: 0 auto&quot;&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Happy Friday! We&#8217;re having a blast celebrating our 5th anniversary in Greece. &amp;#x1F603 &lt;a href=&quot;https://twitter.com/hashtag/JCrete?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#JCrete&lt;/a&gt; &lt;a href=&quot;https://t.co/yMzphpNhnj&quot;&gt;pic.twitter.com/yMzphpNhnj&lt;/a&gt;&lt;/p&gt;&amp;mdash; Matt Raible (@mraible) &lt;a href=&quot;https://twitter.com/mraible/status/1022829794151395328?ref_src=twsrc%5Etfw&quot;&gt;July 27, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;Jack &lt;a href=&quot;https://raibledesigns.com/rd/entry/happy_birthday_jack7&quot;&gt;turned 14&lt;/a&gt;, and Abbie &lt;a href=&quot;https://raibledesigns.com/rd/entry/happy_birthday_abbie12&quot;&gt;turned 16&lt;/a&gt;. I&apos;m proud to say they&apos;re both fabulous humans. &amp;#x1F60A&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;a data-href=&quot;https://www.flickr.com/photos/mraible/43441216425/&quot; href=&quot;https://farm2.staticflickr.com/1894/43441216425_7e456c4b73_c.jpg&quot; title=&quot;Jack at Versailles&quot; rel=&quot;lightbox[2018yearinreview]&quot;&gt;&lt;img src=&quot;https://farm2.staticflickr.com/1894/43441216425_7e456c4b73_m.jpg&quot; width=&quot;240&quot; alt=&quot;Jack at Versailles&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
  &lt;a data-href=&quot;https://www.flickr.com/photos/mraible/45018903354&quot; href=&quot;https://farm5.staticflickr.com/4912/45018903354_2d4ff98729_c.jpg&quot; title=&quot;Abbie in Crete&quot; rel=&quot;lightbox[2018yearinreview]&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4912/45018903354_2d4ff98729_m.jpg&quot; width=&quot;240&quot; alt=&quot;Abbie in Crete&quot; style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;If you want a glimpse of my backwoods childhood (without electricity) in Montana, see my &lt;a href=&quot;https://raibledesigns.com/rd/entry/life_update_thanksgiving_in_montana&quot;&gt;Life Update: Thanksgiving in Montana, RWX2018, Devoxx4Kids, DJUG, and Trish&apos;s Birthday&lt;/a&gt; post.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

    &lt;a href=&quot;https://farm5.staticflickr.com/4914/31450743277_6741c5de04_c.jpg&quot; title=&quot;The Cabin&apos;s dining room&quot; rel=&quot;lightbox[2018yearinreview]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/31450743277/in/album-72157704814416525/&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4914/31450743277_6741c5de04_m.jpg&quot; width=&quot;240&quot; alt=&quot;The Cabin&apos;s dining room&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm5.staticflickr.com/4820/45666897694_449e38462f_c.jpg&quot; title=&quot;The stove! My dad used to love sitting on the oven door every morning.&quot; rel=&quot;lightbox[2018yearinreview]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/45666897694/in/album-72157704814416525/&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4820/45666897694_449e38462f_m.jpg&quot; width=&quot;240&quot; alt=&quot;The stove! My dad used to love sitting on the oven door every morning.&quot; style=&quot;border: 1px solid black; margin-left: 15px;&quot;&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm5.staticflickr.com/4837/32518041268_d3d696a280_c.jpg&quot; title=&quot;It&apos;s a guest room now, but I think my sister (Kalin) was born in this corner.&quot; rel=&quot;lightbox[2018yearinreview]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/32518041268/in/album-72157704814416525/&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4837/32518041268_d3d696a280_m.jpg&quot; width=&quot;240&quot; alt=&quot;It&apos;s a guest room now, but I think my sister (Kalin) was born in this corner.&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm5.staticflickr.com/4821/45666893624_e6d3d5a8a7_c.jpg&quot; title=&quot;I was born in this corner.&quot; rel=&quot;lightbox[2018yearinreview]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/45666893624/in/album-72157704814416525/&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4821/45666893624_e6d3d5a8a7_m.jpg&quot; width=&quot;240&quot; alt=&quot;I was born in this corner.&quot; style=&quot;border: 1px solid black; margin-left: 15px;&quot;&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;h2 id=&quot;2019&quot;&gt;2019&lt;/h2&gt;
&lt;p&gt;
    Professionally, I&apos;m planning to travel a bit more to exotic locations. Atlanta, San Francisco, Paris, Bangalore, Barcelona, and Kansas City are on my list (before August). The &lt;a href=&quot;https://twitter.com/oktadev&quot;&gt;Developer Relations team&lt;/a&gt; at &lt;a href=&quot;https://twitter.com/okta&quot;&gt;Okta&lt;/a&gt; is a fantastic place to be. As many of y&apos;all know, the best thing about a job is often your boss. Mine is &lt;a href=&quot;https://twitter.com/rdegges&quot;&gt;Randall Degges&lt;/a&gt;. He&apos;s a legitimate badass hacker. Don&apos;t try to win a popularity contest with him. There&apos;s a good chance I&apos;ll be at Okta as long as he&apos;s my boss.
&lt;/p&gt;
&lt;p&gt;On the developer relations team, we set our own schedules, plan our own interests, schedule our own conference appearances, and sponsor our favorite local events. Being a developer advocate is a gratifying job. You can write about your favorite open source frameworks, attend/sponsor local meetups, and learn new things every day! If you happen to be #devrel folk (or a like-minded awesomeperson), you might like my &lt;a href=&quot;https://developer.okta.com/blog/2019/01/28/developer-relations-pro-tips&quot;&gt;Pro Tips for Developer Relations&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;Personally, I&apos;d like to ski, raft, bike, and have a good time in 2019 a lot more! Y&apos;all know I won&apos;t have any problem with the last one, but its predecessors are the ones that really make me smile. Skiing down a chute, rafting through a class IV, and biking in Moab are some of the most exhilarating activities I&apos;ve ever experienced. I&apos;m getting a bit older (44) these days, but I still love playing in the outdoors. Luckily, I married a magical woman that loves the outdoors as much as I do. Even better, &lt;a href=&quot;https://www.mcginityphoto.com/&quot;&gt;she photographs its excellence&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Abbie is the school-commute driver, but Jack will be 15 in August, and he&apos;s determined to get his learners permit as soon as he can. That means he&apos;ll need a family member in the car that&apos;s 21+. If he wants to drive, the 20-minute-each-way commute is back on in the fall. For those of you with children of similar ages, you know that this is a precious time in our lives. I don&apos;t have a &lt;em&gt;work&lt;/em&gt; commute. Driving my kids to school takes an hour round-trip. If it were a commute to work, I&apos;d hate it. However, it&apos;s precious time with my kids, and it&apos;s really quite fabulous. Even if they&apos;re staring at their phones, you have their full attention. Ask questions and enjoy their responses.&lt;/p&gt;
&lt;p&gt;
Last year, I &lt;a href=&quot;https://raibledesigns.com/rd/entry/2017_a_year_in_review#personal&quot;&gt;said&lt;/a&gt; one of my goals was to simply be content. This year, I&apos;m taking it up a notch. If you don&apos;t have goals, how can you measure how you improved your life? I&apos;m a big believer in self-improvement, so here goes (in order of priority):
&lt;/p&gt;
&lt;h3 id=&quot;personal-goals&quot;&gt;Personal&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;Good Blood Pressure&lt;/li&gt;
    &lt;li&gt;More 2 and 3 point days&lt;/li&gt;
    &lt;li&gt;Ride/ski/hoops 4x week&lt;/li&gt;
    &lt;li&gt;Walk daily (preferably at home with Sagan and Daisy)&lt;/li&gt;
    &lt;li&gt;More salads, less red meat&lt;/li&gt;
    &lt;li&gt;Love is a verb, embrace 1:1 time with everyone (Trish, kids, parents, friends)&lt;/li&gt;
    &lt;li&gt;20 days camping&lt;/li&gt;
    &lt;li&gt;25 days skiing&lt;/li&gt;
    &lt;li&gt;15 days rafting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&apos;m a big fan of the last three. Those activities typically involve a break from technology, the great outdoors, and exquisite views. &lt;a href=&quot;https://www.instagram.com/vwsforlife/&quot;&gt;Follow me on Instagram&lt;/a&gt; if you want a highlight reel.&lt;/p&gt;
&lt;p&gt;I have some work-related goals too, because metrics seem to motivate me.&lt;/p&gt;
&lt;h3 id=&quot;work&quot;&gt;Work&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Author/publish two blog posts per month&lt;/li&gt;
    &lt;li&gt;Review/mentor four blog posts per month&lt;/li&gt;
    &lt;li&gt;Record/publish two videos per month&lt;/li&gt;
    &lt;li&gt;One performance/speaking gig per month&lt;/li&gt;
    &lt;li&gt;Three &quot;no travel&quot; months&lt;/li&gt;
    &lt;li&gt;Stand more while working&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
    I believe 2019 will be fabulous, and I hope to reflect my favorite moments on this blog. If you&apos;re a long-time follower, you&apos;ll notice I&apos;m mostly active &lt;a href=&quot;https://twitter.com/mraible&quot;&gt;@mraible&lt;/a&gt;. Y&apos;all use Twitter, right? That&apos;s my modern day notification channel. When I&apos;m super giddy, I&apos;ll post pictures of my favorite moments &lt;a href=&quot;https://www.instagram.com/vwsforlife&quot;&gt;on Instagram&lt;/a&gt;. When I want to save them forever, I publish them to &lt;a href=&quot;https://www.flickr.com/photos/mraible&quot;&gt;Flickr&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;I hope to see you at a conference or meetup in 2019!&lt;/p&gt;
&lt;div style=&quot;margin: 0 auto; max-width: 600px&quot;&gt;
    &lt;blockquote class=&quot;instagram-media&quot; data-instgrm-captioned data-instgrm-permalink=&quot;https://www.instagram.com/p/BdoMtTilm2M/?utm_source=ig_embed&amp;amp;utm_medium=loading&quot; data-instgrm-version=&quot;12&quot; style=&quot; background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:540px; min-width:326px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);&quot;&gt;&lt;div style=&quot;padding:16px;&quot;&gt; &lt;a href=&quot;https://www.instagram.com/p/BdoMtTilm2M/?utm_source=ig_embed&amp;amp;utm_medium=loading&quot; style=&quot; background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;&quot; target=&quot;_blank&quot;&gt; &lt;div style=&quot; display: flex; flex-direction: row; align-items: center;&quot;&gt; &lt;div style=&quot;background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 40px; margin-right: 14px; width: 40px;&quot;&gt;&lt;/div&gt; &lt;div style=&quot;display: flex; flex-direction: column; flex-grow: 1; justify-content: center;&quot;&gt; &lt;div style=&quot; background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; margin-bottom: 6px; width: 100px;&quot;&gt;&lt;/div&gt; &lt;div style=&quot; background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; width: 60px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;padding: 19% 0;&quot;&gt;&lt;/div&gt;&lt;div style=&quot;display:block; height:50px; margin:0 auto 12px; width:50px;&quot;&gt;&lt;svg width=&quot;50px&quot; height=&quot;50px&quot; viewBox=&quot;0 0 60 60&quot; version=&quot;1.1&quot; xmlns=&quot;https://www.w3.org/2000/svg&quot; xmlns&lt;img src=&quot;https://raibledesigns.com/images/smileys/love.gif&quot; class=&quot;smiley&quot; alt=&quot;:x&quot; title=&quot;:x&quot; /&gt;link=&quot;https://www.w3.org/1999/xlink&quot;&gt;&lt;g stroke=&quot;none&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;g transform=&quot;translate(-511.000000, -20.000000)&quot; fill=&quot;#000000&quot;&gt;&lt;g&gt;&lt;path d=&quot;M556.869,30.41 C554.814,30.41 553.148,32.076 553.148,34.131 C553.148,36.186 554.814,37.852 556.869,37.852 C558.924,37.852 560.59,36.186 560.59,34.131 C560.59,32.076 558.924,30.41 556.869,30.41 M541,60.657 C535.114,60.657 530.342,55.887 530.342,50 C530.342,44.114 535.114,39.342 541,39.342 C546.887,39.342 551.658,44.114 551.658,50 C551.658,55.887 546.887,60.657 541,60.657 M541,33.886 C532.1,33.886 524.886,41.1 524.886,50 C524.886,58.899 532.1,66.113 541,66.113 C549.9,66.113 557.115,58.899 557.115,50 C557.115,41.1 549.9,33.886 541,33.886 M565.378,62.101 C565.244,65.022 564.756,66.606 564.346,67.663 C563.803,69.06 563.154,70.057 562.106,71.106 C561.058,72.155 560.06,72.803 558.662,73.347 C557.607,73.757 556.021,74.244 553.102,74.378 C549.944,74.521 548.997,74.552 541,74.552 C533.003,74.552 532.056,74.521 528.898,74.378 C525.979,74.244 524.393,73.757 523.338,73.347 C521.94,72.803 520.942,72.155 519.894,71.106 C518.846,70.057 518.197,69.06 517.654,67.663 C517.244,66.606 516.755,65.022 516.623,62.101 C516.479,58.943 516.448,57.996 516.448,50 C516.448,42.003 516.479,41.056 516.623,37.899 C516.755,34.978 517.244,33.391 517.654,32.338 C518.197,30.938 518.846,29.942 519.894,28.894 C520.942,27.846 521.94,27.196 523.338,26.654 C524.393,26.244 525.979,25.756 528.898,25.623 C532.057,25.479 533.004,25.448 541,25.448 C548.997,25.448 549.943,25.479 553.102,25.623 C556.021,25.756 557.607,26.244 558.662,26.654 C560.06,27.196 561.058,27.846 562.106,28.894 C563.154,29.942 563.803,30.938 564.346,32.338 C564.756,33.391 565.244,34.978 565.378,37.899 C565.522,41.056 565.552,42.003 565.552,50 C565.552,57.996 565.522,58.943 565.378,62.101 M570.82,37.631 C570.674,34.438 570.167,32.258 569.425,30.349 C568.659,28.377 567.633,26.702 565.965,25.035 C564.297,23.368 562.623,22.342 560.652,21.575 C558.743,20.834 556.562,20.326 553.369,20.18 C550.169,20.033 549.148,20 541,20 C532.853,20 531.831,20.033 528.631,20.18 C525.438,20.326 523.257,20.834 521.349,21.575 C519.376,22.342 517.703,23.368 516.035,25.035 C514.368,26.702 513.342,28.377 512.574,30.349 C511.834,32.258 511.326,34.438 511.181,37.631 C511.035,40.831 511,41.851 511,50 C511,58.147 511.035,59.17 511.181,62.369 C511.326,65.562 511.834,67.743 512.574,69.651 C513.342,71.625 514.368,73.296 516.035,74.965 C517.703,76.634 519.376,77.658 521.349,78.425 C523.257,79.167 525.438,79.673 528.631,79.82 C531.831,79.965 532.853,80.001 541,80.001 C549.148,80.001 550.169,79.965 553.369,79.82 C556.562,79.673 558.743,79.167 560.652,78.425 C562.623,77.658 564.297,76.634 565.965,74.965 C567.633,73.296 568.659,71.625 569.425,69.651 C570.167,67.743 570.674,65.562 570.82,62.369 C570.966,59.17 571,58.147 571,50 C571,41.851 570.966,40.831 570.82,37.631&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div style=&quot;padding-top: 8px;&quot;&gt; &lt;div style=&quot; color:#3897f0; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:550; line-height:18px;&quot;&gt; View this post on Instagram&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;padding: 12.5% 0;&quot;&gt;&lt;/div&gt; &lt;div style=&quot;display: flex; flex-direction: row; margin-bottom: 14px; align-items: center;&quot;&gt;&lt;div&gt; &lt;div style=&quot;background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(0px) translateY(7px);&quot;&gt;&lt;/div&gt; &lt;div style=&quot;background-color: #F4F4F4; height: 12.5px; transform: rotate(-45deg) translateX(3px) translateY(1px); width: 12.5px; flex-grow: 0; margin-right: 14px; margin-left: 2px;&quot;&gt;&lt;/div&gt; &lt;div style=&quot;background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(9px) translateY(-18px);&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;margin-left: 8px;&quot;&gt; &lt;div style=&quot; background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 20px; width: 20px;&quot;&gt;&lt;/div&gt; &lt;div style=&quot; width: 0; height: 0; border-top: 2px solid transparent; border-left: 6px solid #f4f4f4; border-bottom: 2px solid transparent; transform: translateX(16px) translateY(-4px) rotate(30deg)&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;margin-left: auto;&quot;&gt; &lt;div style=&quot; width: 0px; border-top: 8px solid #F4F4F4; border-right: 8px solid transparent; transform: translateY(16px);&quot;&gt;&lt;/div&gt; &lt;div style=&quot; background-color: #F4F4F4; flex-grow: 0; height: 12px; width: 16px; transform: translateY(-4px);&quot;&gt;&lt;/div&gt; &lt;div style=&quot; width: 0; height: 0; border-top: 8px solid #F4F4F4; border-left: 8px solid transparent; transform: translateY(-4px) translateX(8px);&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt; &lt;p style=&quot; margin:8px 0 0 0; padding:0 4px;&quot;&gt; &lt;a href=&quot;https://www.instagram.com/p/BdoMtTilm2M/?utm_source=ig_embed&amp;amp;utm_medium=loading&quot; style=&quot; color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;&quot; target=&quot;_blank&quot;&gt;Fun family photo in Crested Butte. #lastbestskitown&lt;/a&gt;&lt;/p&gt; &lt;p style=&quot; color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;&quot;&gt;A post shared by &lt;a href=&quot;https://www.instagram.com/vwsforlife/?utm_source=ig_embed&amp;amp;utm_medium=loading&quot; style=&quot; color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px;&quot; target=&quot;_blank&quot;&gt; Matt Raible&lt;/a&gt; (@vwsforlife) on &lt;time style=&quot; font-family:Arial,sans-serif; font-size:14px; line-height:17px;&quot; datetime=&quot;2018-01-07T00:27:20+00:00&quot;&gt;Jan 6, 2018 at 4:27pm PST&lt;/time&gt;&lt;/p&gt;&lt;/div&gt;&lt;/blockquote&gt; &lt;script async src=&quot;//www.instagram.com/embed.js&quot;&gt;&lt;/script&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/angular_summit_2015</id>
        <title type="html">Angular Summit 2015</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/angular_summit_2015"/>
        <published>2015-10-01T10:29:31-06:00</published>
        <updated>2015-10-08T21:32:22-06:00</updated> 
        <category term="/The Web" label="The Web" />
        <category term="aurelia" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javascript" scheme="http://roller.apache.org/ns/tags/" />
        <category term="bootstrap" scheme="http://roller.apache.org/ns/tags/" />
        <category term="angular2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="angularjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jhipster" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring-boot" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="meteor" scheme="http://roller.apache.org/ns/tags/" />
        <category term="es6" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;p&gt;
  I was in Boston this week, speaking and attending the very first &lt;a href=&quot;http://angularsummit.com&quot;&gt;Angular Summit&lt;/a&gt;. I had the privilege of delivering the opening keynote on Monday. I spoke about the Art of Angular
  and used a slide deck similar to &lt;a href=&quot;//raibledesigns.com/rd/entry/the_art_of_angularjs_in&quot;&gt;last time&lt;/a&gt;. I did
  update the presentation to show the astronomical growth of AngularJS in terms of candidate skills (on LinkedIn) and job opportunities (on Dice.com)&lt;sup&gt;1&lt;/sup&gt;.
&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;https://farm1.staticflickr.com/691/21198424124_e9b9b37afb_c.jpg&quot; title=&quot;LinkedIn Skills Growth for JavaScript MVC Frameworks&quot; rel=&quot;lightbox[angularsummit2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/21198424124/in/dateposted-public/&quot;&gt;&lt;img src=&quot;https://farm1.staticflickr.com/691/21198424124_e9b9b37afb_c.jpg&quot; width=&quot;300&quot; alt=&quot;LinkedIn Skills Growth for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;https://farm6.staticflickr.com/5808/21633143850_9aef93d361_c.jpg&quot; title=&quot;Dice.com Job Growth for JavaScript MVC Frameworks&quot; rel=&quot;lightbox[angularsummit2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/21633143850/in/dateposted-public/&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5808/21633143850_9aef93d361_c.jpg&quot; width=&quot;300&quot; alt=&quot;Dice.com Job Growth for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I mentioned the recently announced &lt;a href=&quot;http://angularjs.blogspot.com/2015/08/angular-1-and-angular-2-coexistence.html&quot;&gt;good news for Angular 2&lt;/a&gt;:
  &lt;/p&gt;&lt;ul&gt;
  &lt;li&gt;We&apos;re enabling mixing of Angular 1 and Angular 2 in the same application.&lt;/li&gt;
  &lt;li&gt;You can mix Angular 1 and Angular 2 components in the same view.&lt;/li&gt;
  &lt;li&gt;Angular 1 and Angular 2 can inject services across frameworks.&lt;/li&gt;
  &lt;li&gt;Data binding works across frameworks.&lt;/li&gt;
  &lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;In related news, &lt;a href=&quot;https://twitter.com/cdoremus&quot;&gt;Craig Doremus&lt;/a&gt; recently posted a &lt;a href=&quot;https://github.com/cdoremus/state-geo-angular&quot;&gt;state-geo-angular&lt;/a&gt; project
  that shows how you can develop an Angular 1.x application that will be easy to upgrade to Angular 2.x.
  Thanks Craig!
&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/vaTKWLA8oVDr8z&quot; width=&quot;600&quot; height=&quot;377&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen=&quot;&quot;&gt; &lt;/iframe&gt;
&lt;/p&gt;

&lt;div style=&quot;text-align: right; max-width: 600px; margin: -20px auto 10px auto&quot;&gt;
    &lt;a href=&quot;//raibledesigns.com/rd/page/publications&quot;&gt;Download&lt;/a&gt; | &lt;a href=&quot;//www.slideshare.net/mraible/the-art-of-angularjs-in-2015-angular-summit-2015&quot;&gt;SlideShare&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;After my keynote, I attended &lt;a href=&quot;https://twitter.com/prpatel&quot;&gt;Pratik Patel&lt;/a&gt;&apos;s session on &lt;a href=&quot;https://angularsummit.com/conference/boston/2015/09/session?id=34208&quot;&gt;High Performance JavaScript Web Apps&lt;/a&gt;.
  Pratik pointed out &lt;a href=&quot;http://mobitest.akamai.com&quot;&gt;mobitest.akamai.com&lt;/a&gt; for testing an app&apos;s performance and seeing its blocking resources. He also mentioned
  &lt;a href=&quot;http://speedgun.io/&quot;&gt;speedgun.io&lt;/a&gt; (currently unavailable) for capturing performance numbers as part of a continuous integration process. Finally,
  he recommended &lt;a href=&quot;http://addyosmani.com/blog/video-javascript-memory-management-masterclass/&quot;&gt;Addy Somani&apos;s JavaScript Memory Management Masterclass&lt;/a&gt;.
&lt;p&gt;
My second presentation was about &lt;a href=&quot;http://jhipster.github.io/&quot;&gt;JHipster&lt;/a&gt;. Near the end of the presentation,
I mentioned that I hope to finish the &lt;a href=&quot;http://www.jhipster-book.com/&quot;&gt;JHipster Book&lt;/a&gt; this month. Writing presentations for
&lt;a href=&quot;//raibledesigns.com/rd/entry/springone_2gx_2015_my_presentations&quot;&gt;SpringOne 2GX&lt;/a&gt; and the Angular Summit occupied a lot of my free time in September. Now that it&apos;s October, I&apos;ll be dedicating my free time to finishing the book. In fact, I think I can finish the rough draft this week!
&lt;/p&gt;&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/769Ne9avDiEeWl&quot; width=&quot;600&quot; height=&quot;377&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen=&quot;&quot;&gt; &lt;/iframe&gt;
&lt;/p&gt;

&lt;div style=&quot;text-align: right; max-width: 600px; margin: -20px auto 10px auto&quot;&gt;
&lt;a href=&quot;//raibledesigns.com/rd/page/publications&quot;&gt;Download&lt;/a&gt; | &lt;a href=&quot;//www.slideshare.net/mraible/get-hip-with-jhipster-spring-boot-angularjs-bootstrap-angular-summit-2015&quot;&gt;SlideShare&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;
  For the last session of the day, I attended &lt;a href=&quot;https://twitter.com/johnlindquist&quot;&gt;John Lindquist&apos;s&lt;/a&gt; session on &lt;a href=&quot;http://angularsummit.com/conference/boston/2015/09/session?id=34230&quot;&gt;Angular 2 Components&lt;/a&gt;. John showed us
  how &lt;em&gt;everything is a component in Angular 2&lt;/em&gt;. He also said &quot;now is the time to learn ES6&quot; and built an
  &lt;a href=&quot;https://github.com/johnlindquist/angular-2-quickstart&quot;&gt;Angular 2 ToDo App&lt;/a&gt; using ES6 and a bit of TypeScript. You might recognize John&apos;s name; he&apos;s the founder of &lt;a href=&quot;http://egghead.io/&quot;&gt;egghead.io&lt;/a&gt;, an excellent
  site for &lt;a href=&quot;https://egghead.io/playlists/new-to-angular-start-here&quot;&gt;learning Angular&lt;/a&gt; with bite-sized videos.
&lt;/p&gt;
&lt;p&gt;Tuesday morning started with a &lt;a href=&quot;http://angularsummit.com/conference/boston/2015/09/session?id=34187&quot;&gt;
  Angular 2.0 keynote&lt;/a&gt; from &lt;a href=&quot;https://twitter.com/ppavlovich&quot;&gt;Peter Pavlovich&lt;/a&gt;. I really enjoyed
  this session and received lots of good tips about getting ready for Angular 2. The tweet below from
  Ksenia Dmitrieva shows his advice.
&lt;/p&gt;
&lt;div style=&quot;margin: 0 auto; max-width: 500px;&quot;&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Best Practices for &lt;a href=&quot;https://twitter.com/hashtag/angularjs?src=hash&quot;&gt;#angularjs&lt;/a&gt; 1.X if you plan to switch to 2.0 by &lt;a href=&quot;https://twitter.com/ppavlovich&quot;&gt;@ppavlovich&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/AngularSummit?src=hash&quot;&gt;#AngularSummit&lt;/a&gt; &lt;a href=&quot;http://t.co/9nobqDc9G9&quot;&gt;pic.twitter.com/9nobqDc9G9&lt;/a&gt;&lt;/p&gt;&amp;mdash; Ksenia Dmitrieva (@KseniaDmitrieva) &lt;a href=&quot;https://twitter.com/KseniaDmitrieva/status/648865784152915968&quot;&gt;September 29, 2015&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;My biggest takeaway was to start following &lt;a href=&quot;https://github.com/johnpapa/angular-styleguide&quot;&gt;John Papa&apos;s Angular Style Guide&lt;/a&gt; &lt;abbr title=&quot;As Soon As Possible&quot;&gt;ASAP&lt;/abbr&gt;.
&lt;p&gt;The first session I attended on Tuesday was &lt;a href=&quot;https://twitter.com/JuddFlamm&quot;&gt;Judd Flamm&lt;/a&gt;&apos;s &lt;a href=&quot;https://angularsummit.com/conference/boston/2015/09/session?id=34298&quot;&gt;Google Material Design &amp;amp; Angular&lt;/a&gt;.
  I&apos;m using &lt;a href=&quot;https://fezvrasta.github.io/bootstrap-material-design/&quot;&gt;Material Design for Bootstrap&lt;/a&gt; on a side project, so I was interested in learning more about its inspiration.
  We learned that &lt;a href=&quot;https://design.google.com/&quot;&gt;Google Design&lt;/a&gt; has everything you need to know about why Material Design exists. We also
  learned about &lt;a href=&quot;https://material.angularjs.org&quot;&gt;Angular Material&lt;/a&gt; and spent most of the session looking at its components. Judd
  recommended &lt;a href=&quot;https://github.com/angular/material-start&quot;&gt;Angular Material-Start&lt;/a&gt; for those looking to get started quickly with both frameworks.
  Judd was a very entertaining speaker; I highly recommend you attend one of his talks if you get the opportunity.
&lt;/p&gt;
&lt;p&gt;After being dazzled by Peter&apos;s knowledge of Angular 2 in Tuesday&apos;s keynote, I attended two more of his talks: one on &lt;a href=&quot;https://www.meteor.com/&quot;&gt;Meteor&lt;/a&gt; and
  another on &lt;a href=&quot;http://aurelia.io/&quot;&gt;Aurelia&lt;/a&gt;. I&apos;ve known about Meteor for a while, but have become more intrigued by it lately with its
  &lt;a href=&quot;http://www.infoq.com/news/2015/09/meteor-12-ecmascript&quot;&gt;1.2 release&lt;/a&gt; and &lt;a href=&quot;http://info.meteor.com/blog/official-angular-support-with-angular-meteor-1.0.0&quot;&gt;Angular support&lt;/a&gt;. Meteor&apos;s
  command line tools that auto-inject CSS and JS demoed very well, as did it&apos;s installable features like a LESS support and Facebook authentication.
&lt;/p&gt;
&lt;p&gt;After hearing all the good things about Angular 2 from Peter, it was interesting to hear him downplay it in his Aurelia talk later that day. When he started showing code,
  it was pretty obvious that Aurelia is doing a great job of simplifying JavaScript MVC syntax for developers. You can develop components with almost half the
    code that Angular 2 requires, and it uses ES6, &lt;a href=&quot;http://jspm.io/&quot;&gt;jspm&lt;/a&gt; and &lt;a href=&quot;https://github.com/systemjs/systemjs&quot;&gt;SystemJS&lt;/a&gt;.
    If you&apos;re developing JavaScript, learning these tools will help prepare you for the future. It&apos;s cool that Aurelia encourages learning things you should learn anyway.
  &lt;/p&gt;
  &lt;p&gt;Aurelia and Angular 2 are both still in Alpha, so I&apos;m not sure it makes sense to use them on a project this year. However, I do think it&apos;s important to track
    them both. I especially think it&apos;s interesting that the founder of Aurelia, &lt;a href=&quot;http://twitter.com/EisenbergEffect&quot;&gt;Rob Eisenberg&lt;/a&gt;,
    &lt;a href=&quot;http://eisenbergeffect.bluespire.com/leaving-angular/&quot;&gt;left the Angular Team&lt;/a&gt; in November 2014 and &lt;a href=&quot;http://blog.durandal.io/2015/01/26/introducing-aurelia/&quot;&gt;
      announced Aurelia&lt;/a&gt; in January 2015 (&lt;a href=&quot;https://news.ycombinator.com/item?id=8948665&quot;&gt;Hacker News thread&lt;/a&gt;). Peter mentioned several times that Aurelia wants to help developers write apps,
      while AngularJS is more tied to helping Google write apps.
  &lt;/p&gt;
&lt;p&gt;
  There were around 400 people at Angular Summit, which I think is pretty good for a first-run conference. As with most No Fluff Just Stuff shows, it ran smoothly, had
    plenty of time between sessions and was filled with knowledgeable, entertaining speakers. It was fun doing my first keynote and I look forward to speaking again in November
    (at &lt;a href=&quot;http://www.devoxx.be/&quot;&gt;Devoxx&lt;/a&gt;) and December (at
    &lt;a href=&quot;http://www.therichwebexperience.com/conference/fort_lauderdale/2015/12/home&quot;&gt;The Rich Web Experience&lt;/a&gt;).
  &lt;/head&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: .9em&quot;&gt;1. I know Dice.com is probably not a great site, but it makes sense to use it since I&apos;ve
been tracking JavaScript MVC framework job stats on it since February 2014.&lt;/p&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/springone_2gx_2015_my_presentations</id>
        <title type="html">SpringOne 2GX 2015: My Presentations on Comparing Hot JavaScript Frameworks and NoXML </title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/springone_2gx_2015_my_presentations"/>
        <published>2015-09-20T12:29:00-06:00</published>
        <updated>2015-09-20T18:40:33-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="xml" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springframework" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javascript" scheme="http://roller.apache.org/ns/tags/" />
        <category term="s2gx" scheme="http://roller.apache.org/ns/tags/" />
        <category term="emberjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="angularjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="noxml" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springone2gx" scheme="http://roller.apache.org/ns/tags/" />
        <category term="reactjs" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last week, I had the pleasure of traveling to Washington, DC to speak at the annual &lt;a href=&quot;http://www.springone2gx.com/&quot;&gt;SpringOne 2GX conference&lt;/a&gt;. I was pretty stressed for the last few weeks because I had to create two new presentations from scratch, and both had to be 90 minutes long. I was also hoping to finish the JHipster Book before the conference started. I was able to finish both presentations in the nick of time, but did not find the time to write the last chapter in the JHipster Book.&lt;/p&gt;
&lt;p&gt;The first presentation was titled &lt;a href=&quot;https://2015.event.springone2gx.com/schedule/sessions/comparing_hot_javascript_frameworks_angularjs_ember_js_and_react_js.html&quot;&gt;Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js&lt;/a&gt;. I started by revisiting the &lt;a href=&quot;//raibledesigns.com/rd/entry/comparing_jvm_web_frameworks_at&quot;&gt;Comparing JVM Web Frameworks talk I did at vJUG&lt;/a&gt; last February. I explained how I think traditional web frameworks are no longer relevant in 2015, but I do believe server-side rendering is still &lt;em&gt;very&lt;/em&gt; relevant. From there, I used &lt;a href=&quot;http://www.ybrikman.com/&quot;&gt;Yevgeniy Brikman&#8217;s&lt;/a&gt; framework scorecard (from his &lt;a href=&quot;http://www.slideshare.net/brikis98/nodejs-vs-play-framework&quot;&gt;Node.js vs. Play Framework presentation&lt;/a&gt;) to rank each framework by a number of different criteria. You can see the final results on &lt;a href=&quot;http://www.slideshare.net/mraible/comparing-hot-javascript-frameworks-angularjs-emberjs-and-reactjs-springone-2gx-2015/160&quot;&gt;slide 160&lt;/a&gt;. Since the scores were so close, I believe you could tweak some scores a bit (or add weights to the different criteria) and make any of the frameworks come out on top.
&lt;/p&gt;
&lt;p&gt;
You can click through the presentation below, download it from &lt;a href=&quot;//raibledesigns.com/rd/page/publications&quot;&gt;my presentations page&lt;/a&gt;, or &lt;a href=&quot;//www.slideshare.net/mraible/comparing-hot-javascript-frameworks-angularjs-emberjs-and-reactjs-springone-2gx-2015&quot;&gt;see it on SlideShare&lt;/a&gt;.
&lt;/p&gt;
&lt;div style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/NGLRPcZiLF0pBo&quot; width=&quot;512&quot; height=&quot;325&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen&gt; &lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;I started writing the second presentation a week before I had to deliver it. On Thursday, September 10th, I stayed up late, trying to figure out how to create a good presentation on NoXML &lt;em&gt;and&lt;/em&gt; finish the last part of the JHipster Book. Then it came to me, I needed to &lt;em&gt;parallelize&lt;/em&gt; and do them both at the same time. I decided to compare AppFuse (which is similar to a legacy Spring application with lots of XML) to JHipster (which hardly contains any XML). 
&lt;/p&gt;
&lt;p&gt;
I wrote a 10-page Google Doc on how I planned to do this, then went rafting and camping with my family for the weekend. I finished most of the presentation on Monday night, but then realized the presentation wouldn&apos;t be long enough to fill 90 minutes. So I hunkered down at midnight, created a new AppFuse application and removed a bunch of its XML. This took me until 3:30am, and I was able to accomplish the following tasks:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring XML to Java&lt;/li&gt;
&lt;li&gt;Spring Security Configuration to Java&lt;/li&gt;
&lt;li&gt;web.xml to WebApplicationInitializer&lt;/li&gt;
&lt;li&gt;Spring MVC to Java&lt;/li&gt;
&lt;li&gt;Migrated to Spring Boot&lt;/li&gt;
&lt;li&gt;Maven to Groovy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;p&gt;I was pretty pumped when I completed my final goal: converting to Spring Boot and getting a test to pass. I made commits to an &lt;a href=&quot;https://github.com/mraible/appfuse-noxml/commits/master&quot;&gt;appfuse-noxml project on GitHub&lt;/a&gt; as I accomplished each step. You can see all the changes in &lt;a href=&quot;https://github.com/mraible/appfuse-noxml/commits/master&quot;&gt;the project&apos;s commit log&lt;/a&gt;. While I&apos;d figured everything out, I still needed to complete the presentation. Luckily, I found time to do this the night before, the morning of, and in the final hour before I had to deliver the talk. You can imagine my relief when I was done delivering both talks. 
&lt;/p&gt;
&lt;p&gt;
You can click through the presentation below, download it from &lt;a href=&quot;//raibledesigns.com/rd/page/publications&quot;&gt;my presentations page&lt;/a&gt;, or &lt;a href=&quot;//www.slideshare.net/mraible/noxml-eliminating-xml-in-spring-projects-springone-2gx-2015&quot;&gt;view it on SlideShare&lt;/a&gt;.
&lt;/p&gt;
&lt;div style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/4V9V7NSsNC2rd7&quot; width=&quot;512&quot; height=&quot;325&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen&gt; &lt;/iframe&gt; 
&lt;/div&gt;
&lt;p&gt;While I didn&apos;t get to spend much time at the conference, I did have a lot of fun while I was there. I got to meet some new folks, reconnect with old friends, and enjoy beers and dinner with a smiling crew on Thursday night. The Broncos victory late that night was the icing on the cake. &lt;img src=&quot;//raibledesigns.com/images/smileys/smile.gif&quot; class=&quot;smiley&quot; alt=&quot;:)&quot; title=&quot;:)&quot;&gt;&lt;/p&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/getting_hip_with_jhipster_at</id>
        <title type="html">Getting Hip with JHipster at Denver&apos;s Java User Group</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/getting_hip_with_jhipster_at"/>
        <published>2015-04-09T08:31:54-06:00</published>
        <updated>2015-04-09T19:20:43-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="angularjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring-boot" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jhipster" scheme="http://roller.apache.org/ns/tags/" />
        <category term="bootstrap" scheme="http://roller.apache.org/ns/tags/" />
        <category term="html5" scheme="http://roller.apache.org/ns/tags/" />
        <category term="yeoman" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;p&gt;Last night, I had the pleasure of &lt;a href=&quot;http://www.meetup.com/DenverJavaUsersGroup/events/220309287/&quot;&gt;speaking at Denver&apos;s Java User Group Meetup about JHipster&lt;/a&gt;. I&apos;ve been a big fan of &lt;a href=&quot;http://jhipster.github.io/&quot;&gt;JHipster&lt;/a&gt; ever since I started using it last fall. I developed a quick prototype for a client and wrote about &lt;a href=&quot;//raibledesigns.com/rd/entry/getting_started_with_jhipster_on&quot;&gt;solving some issues I had with it on OS X&lt;/a&gt;. I like the project because it encapsulates the primary open source tools I&apos;ve been using for the last couple of years: &lt;a href=&quot;http://projects.spring.io/spring-boot/&quot;&gt;Spring Boot&lt;/a&gt;, &lt;a href=&quot;https://angularjs.org/&quot;&gt;AngularJS&lt;/a&gt; and &lt;a href=&quot;http://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt;. I also wrote about its &lt;a href=&quot;http://www.infoq.com/news/2015/01/jhipster-2.0&quot;&gt;2.0 release&lt;/a&gt; on InfoQ in January.
&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;https://farm9.staticflickr.com/8820/16900780428_7093ff1754_c.jpg&quot; rel=&quot;lightbox[jhipsterdjug]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16900780428&quot; title=&quot;My Hipster Getup by Matt Raible, on Flickr&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8820/16900780428_7093ff1754_t.jpg&quot; width=&quot;100&quot; height=&quot;67&quot; alt=&quot;My Hipster Getup&quot; class=&quot;picture&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
To add some humor to my talk, I showed up as a well-dressed Java Developer. Like a mature gentleman might do, I started the evening with a glass of scotch (Glenlivet 12). Throughout the talk I became more hip and adjusted my attire, and beverage, accordingly. As you might expect, my demos had failures. The initial project creation stalled during Bower&apos;s &lt;em&gt;download all JavaScript dependencies&lt;/em&gt;. Luckily, I had a backup and was able to proceed. Towards the end, when I tried to deploy to Heroku, I was presented with a lovely message that &quot;Heroku toolbelt updating, please try again later&quot;. I guess auto-updating has its downsides. &lt;/p&gt;
&lt;p&gt;After finishing the demo, I cracked open a cold PBR to ease my frustration.&lt;/p&gt;
&lt;p&gt;I did two live coding sessions during this presentation; standing on the shoulders of giants to do so. I modeled Josh Long&apos;s &lt;a href=&quot;http://www.joshlong.com/jl/blogPost/tech_tip_geting_started_with_spring_boot.html&quot;&gt;Getting Started with Spring Boot&lt;/a&gt; to create a quick introduction to Spring Boot. IntelliJ IDEA 14.1 has a &lt;a href=&quot;http://blog.jetbrains.com/idea/2015/03/develop-spring-boot-applications-more-productively-with-intellij-idea-14-1/&quot;&gt;nice way to create Spring Boot projects&lt;/a&gt;, so that came in handy.  For the JHipster portion, I created a blogging app and used relationships and business logic similar to what Julien Dubois did in his &lt;a href=&quot;https://spring.io/blog/2015/03/31/webinar-replay-jhipster-for-spring-boot&quot;&gt;JHipster for Spring Boot Webinar&lt;/a&gt;. Watching Josh and Julien&apos;s demos will give you a similar experience to what DJUG attendees experienced last night, without the download/deployment failures.
&lt;/p&gt;
&lt;p&gt;You can click through my presentation below, download it from &lt;a href=&quot;//raibledesigns.com/rd/page/publications&quot;&gt;my
    presentations page&lt;/a&gt;, or &lt;a href=&quot;http://www.slideshare.net/mraible/get-hip-with-jhipster&quot;&gt;view it on SlideShare&lt;/a&gt;.
&lt;/p&gt;
&lt;div style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/46814366&quot; width=&quot;512&quot; height=&quot;325&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;You might notice my &lt;a href=&quot;http://www.slideshare.net/mraible/get-hip-with-jhipster/32&quot;&gt;announcement on slide #32&lt;/a&gt; that I&apos;ve signed up to write a book on JHipster.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;https://farm9.staticflickr.com/8825/17062597206_60a5bd6e19_c.jpg&quot; data-href=&quot;https://www.flickr.com/photos/mraible/17062597206&quot; rel=&quot;lightbox[jhipsterdjug]&quot; title=&quot;The JHipster Mini-Book by Matt Raible&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8825/17062597206_60a5bd6e19.jpg&quot; width=&quot;500&quot; alt=&quot;The JHipster Mini-Book&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I haven&apos;t started writing the book yet, but I have been talking with &lt;a href=&quot;http://infoq.com&quot;&gt;InfoQ&lt;/a&gt; and other folks about it for several months. I plan to use &lt;a href=&quot;https://github.com/asciidoctor/asciidoctor-gradle-examples&quot;&gt;Asciidoctor and Gradle&lt;/a&gt; as my authoring tools. If you have experience writing a book with these tools, I&apos;d love to hear about it. If you&apos;ve developed an application with JHipster and have some experience in the trenches, I&apos;d love to hear your stories too. 
&lt;/p&gt;
&lt;p&gt;
As I told DJUG last night, I plan to be done with the book in a few months. However, if you&apos;ve been a reader of this blog, you&apos;ll know I&apos;ve been planning to be done with my &apos;66 VW Bus in &lt;em&gt;just a few more months&lt;/em&gt; for quite some time, so that phrase has an interesting meaning for me. &lt;img src=&quot;https://raibledesigns.com/images/smileys/wink.gif&quot; class=&quot;smiley&quot; alt=&quot;;)&quot; title=&quot;;)&quot; /&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/the_art_of_angularjs_in</id>
        <title type="html">The Art of AngularJS in 2015</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/the_art_of_angularjs_in"/>
        <published>2015-02-04T09:14:57-07:00</published>
        <updated>2015-02-04T15:17:31-07:00</updated> 
        <category term="/The Web" label="The Web" />
        <category term="denver" scheme="http://roller.apache.org/ns/tags/" />
        <category term="angularjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grunt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="dosug" scheme="http://roller.apache.org/ns/tags/" />
        <category term="http2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="coffeescript" scheme="http://roller.apache.org/ns/tags/" />
        <category term="protractor" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javascript" scheme="http://roller.apache.org/ns/tags/" />
        <category term="html5" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jasmine" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;I&apos;ve been tracking statistics on jobs and skills for JavaScript MVC frameworks ever since I &lt;a href=&quot;//raibledesigns.com/rd/entry/devoxx_france_a_great_conference&quot;&gt;Compared JVM Web Frameworks at Devoxx
    France in 2013&lt;/a&gt;. At that time, Backbone was the dominant framework.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7452/16255644670_e426fb455f_c.jpg&quot; title=&quot;2013 Dice Jobs for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16255644670&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7452/16255644670_e426fb455f_m.jpg&quot; width=&quot;240&quot; alt=&quot;2013 Dice Jobs for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;https://farm8.staticflickr.com/7411/16255384478_67712c17dd_c.jpg&quot; title=&quot;2013 LinkedIn Skills for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16255384478&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7411/16255384478_67712c17dd_m.jpg&quot; width=&quot;240&quot; alt=&quot;2013 LinkedIn Skills for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Last year, I updated those statistics for a &lt;a href=&quot;//raibledesigns.com/rd/entry/the_art_of_angularjs&quot;&gt;presentation
    on AngularJS&lt;/a&gt; at Denver&apos;s Derailed. Angular had a similar amount of jobs as Backbone and a lot of people added it
    to their LinkedIn profiles. I found that Ember had grown around 300%, Backbone 200% and Angular 1000%!&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7381/16256817639_b1ea05213a_c.jpg&quot; title=&quot;2014 Dice Jobs for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16256817639&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7381/16256817639_b1ea05213a_m.jpg&quot; width=&quot;240&quot; alt=&quot;2014 Dice Jobs for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7381/16443061465_e89eda261c_c.jpg&quot; title=&quot;2014 LinkedIn Skills for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16443061465&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7381/16443061465_e89eda261c_m.jpg&quot; width=&quot;240&quot; alt=&quot;2014 LinkedIn Skills for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Before presenting on AngularJS at &lt;a href=&quot;http://www.meetup.com/DOSUG1/events/219099019/&quot;&gt;last night&apos;s Denver Open
    Source Users Group&lt;/a&gt;, I updated these statistics once again. The charts below show how the number of jobs for
    Angular has doubled in the last year, while jobs for Ember and Backbone have fallen slightly. As far as skills,
    developers learning Ember and Backbone has increased 200%, while skilled Angular folks has risen 400%.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm9.staticflickr.com/8637/16443001655_fb8593e2f3_c.jpg&quot; title=&quot;2015 Dice Jobs for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16443001655&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8637/16443001655_fb8593e2f3_m.jpg&quot; width=&quot;240&quot; alt=&quot;2015 Dice Jobs for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm9.staticflickr.com/8628/16257092107_c4a9735b65_c.jpg&quot; title=&quot;2015 LinkedIn Skills for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16257092107&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8628/16257092107_c4a9735b65_m.jpg&quot; width=&quot;240&quot; alt=&quot;2015 LinkedIn Skills for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Yes, AngularJS has experienced &lt;em&gt;huge&lt;/em&gt; growth in the last couple of years. You might even say it&apos;s the &lt;em&gt;Struts
    of the JavaScript world&lt;/em&gt;.
&lt;/p&gt;&lt;p&gt;For the presentation I delivered last night, I made a number of improvements over last year&apos;s. I added a live coding
    demo based on my &lt;a href=&quot;&quot;&gt;Getting Started with AngularJS&lt;/a&gt; tutorial. I used IntelliJ&apos;s &lt;a href=&quot;https://www.jetbrains.com/idea/help/live-templates.html&quot;&gt;live templates&lt;/a&gt; to make it look easy. However,
    since the audience was quiet, and some were falling asleep, I skipped over the &lt;a href=&quot;//raibledesigns.com/rd/entry/testing_angularjs_applications&quot;&gt;testing&lt;/a&gt; demo.&lt;/p&gt;
</summary>
        <content type="html">&lt;p&gt;I&apos;ve been tracking statistics on jobs and skills for JavaScript MVC frameworks ever since I &lt;a href=&quot;//raibledesigns.com/rd/entry/devoxx_france_a_great_conference&quot;&gt;Compared JVM Web Frameworks at Devoxx
    France in 2013&lt;/a&gt;. At that time, Backbone was the dominant framework.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7452/16255644670_e426fb455f_c.jpg&quot; title=&quot;2013 Dice Jobs for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16255644670&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7452/16255644670_e426fb455f.jpg&quot; width=&quot;500&quot; alt=&quot;2013 Dice Jobs for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7411/16255384478_67712c17dd_c.jpg&quot; title=&quot;2013 LinkedIn Skills for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16255384478&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7411/16255384478_67712c17dd.jpg&quot; width=&quot;500&quot; alt=&quot;2013 LinkedIn Skills for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Last year, I updated those statistics for a &lt;a href=&quot;//raibledesigns.com/rd/entry/the_art_of_angularjs&quot;&gt;presentation
    on AngularJS&lt;/a&gt; at Denver&apos;s Derailed. Angular had a similar amount of jobs as Backbone and a lot of people added it
    to their LinkedIn profiles. I found that Ember had grown around 300%, Backbone 200% and Angular 1000%!&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7381/16256817639_b1ea05213a_c.jpg&quot; title=&quot;2014 Dice Jobs for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16256817639&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7381/16256817639_b1ea05213a.jpg&quot; width=&quot;500&quot; alt=&quot;2014 Dice Jobs for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7381/16443061465_e89eda261c_c.jpg&quot; title=&quot;2014 LinkedIn Skills for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16443061465&quot;&gt;&lt;img src=&quot;https://farm8.staticflickr.com/7381/16443061465_e89eda261c.jpg&quot; width=&quot;500&quot; alt=&quot;2014 LinkedIn Skills for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Before presenting on AngularJS at &lt;a href=&quot;http://www.meetup.com/DOSUG1/events/219099019/&quot;&gt;last night&apos;s Denver Open
    Source Users Group&lt;/a&gt;, I updated these statistics once again. The charts below show how the number of jobs for
    Angular has doubled in the last year, while jobs for Ember and Backbone have fallen slightly. As far as skills,
    developers learning Ember and Backbone has increased 200%, while skilled Angular folks has risen 400%.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm9.staticflickr.com/8637/16443001655_fb8593e2f3_c.jpg&quot; title=&quot;2015 Dice Jobs for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16443001655&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8637/16443001655_fb8593e2f3.jpg&quot; width=&quot;500&quot; alt=&quot;2015 Dice Jobs for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm9.staticflickr.com/8628/16257092107_c4a9735b65_c.jpg&quot; title=&quot;2015 LinkedIn Skills for JavaScript MVC Frameworks by Matt Raible, on Flickr&quot; rel=&quot;lightbox[artofangular2015]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/16257092107&quot;&gt;&lt;img src=&quot;https://farm9.staticflickr.com/8628/16257092107_c4a9735b65.jpg&quot; width=&quot;500&quot; alt=&quot;2015 LinkedIn Skills for JavaScript MVC Frameworks&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Yes, AngularJS has experienced &lt;em&gt;huge&lt;/em&gt; growth in the last couple of years. You might even say it&apos;s the &lt;em&gt;Struts
    of the JavaScript world&lt;/em&gt;. I like to say that &lt;a href=&quot;http://www.infoq.com/news/2013/04/struts1-eol&quot;&gt;Struts 1.x was the &apos;Killer App&apos; for J2EE&lt;/a&gt; back in the day.
&lt;/p&gt;&lt;p&gt;For the presentation I delivered last night, I made a number of improvements over last year&apos;s. I added a live coding
    demo based on my &lt;a href=&quot;&quot;&gt;Getting Started with AngularJS&lt;/a&gt; tutorial. I used IntelliJ&apos;s &lt;a href=&quot;https://www.jetbrains.com/idea/help/live-templates.html&quot;&gt;live templates&lt;/a&gt; to make it look easy. However,
    since the audience was quiet, and some were falling asleep, I skipped over the &lt;a href=&quot;//raibledesigns.com/rd/entry/testing_angularjs_applications&quot;&gt;testing&lt;/a&gt; demo.&lt;/p&gt;
&lt;p&gt;I added a few slides on &lt;a href=&quot;http://foundation.zurb.com/apps/&quot;&gt;Foundation for Apps&lt;/a&gt; (FA). We&apos;ve selected
    AngularJS and Foundation on my current project, and I&apos;ve been researching how to integrate the two lately. FA is one
    solution I&apos;ve found, &lt;a href=&quot;http://pineconellc.github.io/angular-foundation/&quot;&gt;Angular Foundation&lt;/a&gt; is
    another. If you know of others, please let me know.&lt;/p&gt;
&lt;p&gt;For Java developers getting started with Angular, I recommended &lt;a href=&quot;http://jhipster.github.io/&quot;&gt;JHipster&lt;/a&gt;. I
    talked about its foundational frameworks and project options when creating your project. I included screenshots of
    its slick metrics UI and code generation features.&lt;/p&gt;
&lt;p&gt;I also added a slide for Dave Syer&apos;s excellent five-part series on Spring and AngularJS:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://spring.io/blog/2015/01/12/spring-and-angular-js-a-secure-single-page-application&quot;&gt;Spring and
        Angular JS: A Secure Single Page Application&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii&quot;&gt;The Login Page:
        Angular JS and Spring Security Part II&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://spring.io/blog/2015/01/20/the-resource-server-angular-js-and-spring-security-part-iii&quot;&gt;The
        Resource Server: Angular JS and Spring Security Part III&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://spring.io/blog/2015/01/28/the-api-gateway-pattern-angular-js-and-spring-security-part-iv&quot;&gt;The
        API Gateway Pattern: Angular JS and Spring Security Part IV&lt;/a&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v&quot;&gt;SSO with
        OAuth2: Angular JS and Spring Security Part V&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, I added a number of slides on &lt;a href=&quot;http://www.infoq.com/news/2014/10/angular-2-atscript&quot;&gt;Angular 2.0&lt;/a&gt;.
    I encouraged folks to checkout &lt;a href=&quot;http://12factor.net/&quot;&gt;The Twelve-Factor App&lt;/a&gt; and James Ward&apos;s
    &lt;a href=&quot;http://www.jamesward.com/2014/12/03/java-doesnt-suck-youre-just-using-it-wrong&quot;&gt;Java Doesn&#8217;t Suck &#8211; You&#8217;re Just Using it Wrong&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;The discussion with the audience was great, particularly around HTTP/2 and minification/concatenation of assets.
    Thanks to all who attended, I really enjoyed having the opportunity to share what I&apos;ve learned.&lt;/p&gt;
&lt;p&gt;You can click through my presentation below, download it from &lt;a href=&quot;//raibledesigns.com/rd/page/publications&quot;&gt;my
    presentations page&lt;/a&gt;, or view it &lt;a href=&quot;http://www.slideshare.net/mraible/the-art-of-angularjs-in-2015&quot;&gt;on SlideShare&lt;/a&gt;.
&lt;/p&gt;
&lt;div style=&quot;text-align: center&quot;&gt;
    &lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/44244006&quot; width=&quot;512&quot; height=&quot;325&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;If you live in Denver, there&apos;s a number of interesting meetups happening in the next couple months. &lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Monday, February 16: &lt;a href=&quot;http://www.meetup.com/HTML5-Denver-Users-Group/events/220053261/&quot;&gt;Introduction to ReactJS&lt;/a&gt; at HTML5 Denver&lt;/li&gt;
    &lt;li&gt;Tuesday &amp;amp; Wednesday, March 3rd and 4th: &lt;a href=&quot;http://thingmonk.com/&quot;&gt;ThingMonk&lt;/a&gt; at &lt;a href=&quot;http://www.drinkmilehighspirits.com/&quot;&gt;&lt;em&gt;a distillery!&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;Wednesday, April 8: I&apos;ll be speaking about JHipster at Denver Java User Group&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&apos;m also looking for speakers to teach programming to kids at &lt;a href=&quot;http://www.meetup.com/Devoxx4Kids-Denver/&quot;&gt;Devoxx4Kids Denver&lt;/a&gt;.
    Let me know if you have a fun topic you&apos;d like to present.&lt;/p&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/2014_a_year_in_review</id>
        <title type="html">2014 - A Year in Review</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/2014_a_year_in_review"/>
        <published>2015-01-31T09:37:43-07:00</published>
        <updated>2015-02-02T12:13:34-07:00</updated> 
        <category term="/Roller" label="Roller" />
        <category term="apacheroller" scheme="http://roller.apache.org/ns/tags/" />
        <category term="yearinreview" scheme="http://roller.apache.org/ns/tags/" />
        <category term="2014" scheme="http://roller.apache.org/ns/tags/" />
        <category term="blogging" scheme="http://roller.apache.org/ns/tags/" />
        <category term="roller" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;
    2014 was destined to be a spectacular year. When I &lt;a
    href=&quot;//raibledesigns.com/rd/entry/2013_a_year_in_review&quot;&gt;wrote my thoughts down last
    January&lt;/a&gt;, I thought the Broncos would win the Super Bowl and my &lt;a href=&quot;//raibledesigns.com/rd/category/The+Bus&quot;&gt;VW Bus restoration project&lt;/a&gt; would be finished by summer.
    To focus on finishing the bus project, I didn&apos;t submit any talks to conferences.
    Instead of traveling to exotic locations, we opted to visit a bunch in our own backyard instead.
&lt;/p&gt;
I should&apos;ve known it&apos;d be an interesting year when the Broncos flopped in the Super Bowl.
&lt;p&gt;For this &lt;a href=&quot;//raibledesigns.com/rd/tags/yearinreview&quot;&gt;Year in Review&lt;/a&gt; post, I&apos;ll use the format I&apos;ve used
    the last couple of years.
&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#professional&quot;&gt;Professional&lt;/a&gt;
        &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#speaking&quot;&gt;Speaking&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#devoxx4kids&quot;&gt;Devoxx4Kids&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#projects&quot;&gt;Projects&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#personal&quot;&gt;Personal&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#2015&quot;&gt;2015&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;professional&quot;&gt;Professional&lt;/h2&gt;
&lt;p&gt;I had three different clients throughout the year, all in the health care industry. I continued working on a project
    with &lt;a href=&quot;http://www.johnmuirhealth.com/&quot;&gt;John
        Muir Health&lt;/a&gt; where we developed a hybrid mobile app. I wrote about what I learned in
    &lt;a href=&quot;//raibledesigns.com/rd/entry/documenting_your_spring_api_with&quot;&gt;Documenting your Spring API with Swagger&lt;/a&gt;
    and &lt;a href=&quot;//raibledesigns.com/rd/entry/developing_an_ios_native_app&quot;&gt;Developing an iOS Native App with Ionic&lt;/a&gt;.
    Since I wrote the article about &lt;a href=&quot;https://github.com/martypitt/swagger-springmvc&quot;&gt;Swagger&apos;s Spring MVC&lt;/a&gt;
    support,
    it has become much easier to integrate; now it only requires an &lt;code&gt;@EnableSwagger&lt;/code&gt; annotation.
&lt;/p&gt;
&lt;p&gt;
    In April, I started consulting with a small company in Alabama. I helped them modernize their tech stack and
    implemented a number of web services with
    &lt;a href=&quot;http://camel.apache.org&quot;&gt;Apache Camel&lt;/a&gt;. I wrote about this in a four-part series in September and
    October.&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;
    2014 was destined to be a spectacular year. When I &lt;a
    href=&quot;//raibledesigns.com/rd/entry/2013_a_year_in_review&quot;&gt;wrote my thoughts down last
    January&lt;/a&gt;, I thought the Broncos would win the Super Bowl and my &lt;a href=&quot;//raibledesigns.com/rd/category/The+Bus&quot;&gt;VW Bus restoration project&lt;/a&gt; would be finished by summer.
    To focus on finishing the bus project, I didn&apos;t submit any talks to conferences.
    Instead of traveling to exotic locations, we opted to visit a bunch in our own backyard instead.
&lt;/p&gt;
I should&apos;ve known it&apos;d be an interesting year when the Broncos flopped in the Super Bowl.
&lt;p&gt;For this &lt;a href=&quot;//raibledesigns.com/rd/tags/yearinreview&quot;&gt;Year in Review&lt;/a&gt; post, I&apos;ll use the format I&apos;ve used
    the last couple of years.
&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#professional&quot;&gt;Professional&lt;/a&gt;
        &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#speaking&quot;&gt;Speaking&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#devoxx4kids&quot;&gt;Devoxx4Kids&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#projects&quot;&gt;Projects&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#personal&quot;&gt;Personal&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/2014_a_year_in_review#2015&quot;&gt;2015&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;professional&quot;&gt;Professional&lt;/h2&gt;
&lt;p&gt;I had three different clients throughout the year, all in the health care industry. I continued working on a project
    with &lt;a href=&quot;http://www.johnmuirhealth.com/&quot;&gt;John
        Muir Health&lt;/a&gt; where we developed a hybrid mobile app. I wrote about what I learned in
    &lt;a href=&quot;//raibledesigns.com/rd/entry/documenting_your_spring_api_with&quot;&gt;Documenting your Spring API with Swagger&lt;/a&gt;
    and &lt;a href=&quot;//raibledesigns.com/rd/entry/developing_an_ios_native_app&quot;&gt;Developing an iOS Native App with Ionic&lt;/a&gt;.
    Since I wrote the article about &lt;a href=&quot;https://github.com/martypitt/swagger-springmvc&quot;&gt;Swagger&apos;s Spring MVC&lt;/a&gt;
    support,
    it has become much easier to integrate; now it only requires an &lt;code&gt;@EnableSwagger&lt;/code&gt; annotation.
&lt;/p&gt;
&lt;p&gt;
    In April, I started consulting with a small company in Alabama. I helped them modernize their tech stack and
    implemented a number of web services with
    &lt;a href=&quot;http://camel.apache.org&quot;&gt;Apache Camel&lt;/a&gt;. I wrote about this in a four-part series in September and
    October.&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/developing_services_with_apache_camel&quot;&gt;Developing Services with Apache
        Camel - Part I: The Inspiration&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/developing_services_with_apache_camel1&quot;&gt;Developing Services with Apache
        Camel - Part II: Creating and Testing Routes&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/developing_services_with_apache_camel2&quot;&gt;Developing Services with Apache
        Camel - Part III: Integrating Spring 4 and Spring Boot&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;//raibledesigns.com/rd/entry/developing_services_with_apache_camel3&quot;&gt;Developing Services with Apache
        Camel - Part IV: Load Testing and Monitoring&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;
&lt;p&gt;
    I continued leveraging Spring Boot in my client projects and wrote about
    &lt;a href=&quot;//raibledesigns.com/rd/entry/building_a_rest_api_with&quot;&gt;Building a REST API with JAXB, Spring Boot and
        Spring Data&lt;/a&gt; at the end of that engagement.
&lt;/p&gt;
&lt;p&gt;
    In November, I had time off between clients. I visited my parents and their awesome retirement home in
    Montana. I also took some time to refactor AppFuse to be a bit leaner and meaner. I signed up with a new health care
    client in December. It&apos;s been an enjoyable experience so far, especially since I&apos;m only working
    20 hours per week this quarter.
&lt;/p&gt;
&lt;p&gt;I&apos;m currently booked with clients through the end of March, but hoping to find one with a challenging project in
    April.&lt;/p&gt;
&lt;h3 id=&quot;speaking&quot;&gt;Speaking&lt;/h3&gt;
&lt;p&gt;
    To optimize cash flow towards the bus project, I didn&apos;t submit any talks to conferences in 2014. However, I did
    talk about &lt;a href=&quot;//raibledesigns.com/rd/entry/comparing_jvm_web_frameworks_at&quot;&gt;Comparing JVM Web
    Frameworks&lt;/a&gt;
    at the &lt;a href=&quot;http://www.meetup.com/DOSUG1/events/155080452/&quot;&gt;Denver Open Source Users Group&lt;/a&gt; and
    &lt;a href=&quot;http://www.meetup.com/virtualJUG/events/153096902/&quot;&gt;vJUG&lt;/a&gt; in February. I also spoke at local user groups
    (DeRailed and HTML5 Users)
    about &lt;a href=&quot;//raibledesigns.com/rd/entry/the_art_of_angularjs&quot;&gt;The Art of AngularJS&lt;/a&gt; in the first part of
    the year.
    In the fall, I participated in panels on unit testing at &lt;a href=&quot;http://www.denverstartupweek.org&quot;&gt;Denver Startup
    Week&lt;/a&gt; and
    &lt;a href=&quot;https://www.airpair.com/airconf2014/keynote/developer-writing-tips-and-tricks&quot;&gt;building a personal
        brand&lt;/a&gt;
    at &lt;a href=&quot;https://www.airpair.com/airconf2014/&quot;&gt;AirConf&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;I hope to attend and speak at more conferences in 2015. To help facilitate this, I&apos;ve &lt;a
    href=&quot;https://gist.github.com/mraible/3754940a56ecfe560b17&quot;&gt;published a list of talks&lt;/a&gt; I&apos;d like to present.&lt;/p&gt;
&lt;h4 id=&quot;devoxx4kids&quot;&gt;Devoxx4Kids Denver&lt;/h4&gt;
&lt;p&gt;2014 was the inaugural year for &lt;a href=&quot;http://www.meetup.com/Devoxx4Kids-Denver/&quot;&gt;Devoxx4Kids Denver&lt;/a&gt;. In April,
    I &lt;a href=&quot;//raibledesigns.com/rd/entry/devoxx4kids_denver_chapter_begins&quot;&gt;announced our first meetup&lt;/a&gt;. It
    was an
    &lt;a href=&quot;http://www.meetup.com/Devoxx4Kids-Denver/events/172037212/&quot;&gt;Introduction to Server-Side Minecraft
        Programming&lt;/a&gt;,
    taught by Denver&apos;s own &lt;a href=&quot;http://thirstyhead.com&quot;&gt;Scott Davis&lt;/a&gt;. It was a &lt;a
        href=&quot;//raibledesigns.com/rd/entry/first_devoxx4kids_in_denver_a&quot;&gt;
        wild success&lt;/a&gt; and the kids had a great time hacking.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm8.staticflickr.com/7342/13930299459_a81657c6b4_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/13930299459&quot;
       title=&quot;Devoxx4Kids Denver by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm8.staticflickr.com/7342/13930299459_a81657c6b4_q.jpg&quot; width=&quot;150&quot; alt=&quot;Devoxx4Kids Denver&quot;
        style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;//farm3.staticflickr.com/2908/14137000853_14f916473f_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14137000853&quot;
       title=&quot;Devoxx4Kids Denver by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm3.staticflickr.com/2908/14137000853_14f916473f_q.jpg&quot; width=&quot;150&quot; alt=&quot;Devoxx4Kids Denver&quot;
        style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;//farm8.staticflickr.com/7192/13930311930_cc968f16d7_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/13930311930&quot;
       title=&quot;Devoxx4Kids Denver by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm8.staticflickr.com/7192/13930311930_cc968f16d7_q.jpg&quot; width=&quot;150&quot; alt=&quot;Devoxx4Kids Denver&quot;
        style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm8.staticflickr.com/7201/13930237257_acff755c13_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/13930237257&quot;
       title=&quot;Scott Davis by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm8.staticflickr.com/7201/13930237257_acff755c13_m.jpg&quot; width=&quot;240&quot; alt=&quot;Scott Davis&quot;
        style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;//farm8.staticflickr.com/7338/14116881615_c61ce047dd_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14116881615&quot;
       title=&quot;Thanks for the great room Thrive! by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm8.staticflickr.com/7338/14116881615_c61ce047dd_m.jpg&quot; width=&quot;240&quot;
        alt=&quot;Thanks for the great room Thrive!&quot; style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I didn&apos;t plan any events during the summer, but we held a couple workshops in the fall: one on &lt;a
    href=&quot;http://www.meetup.com/Devoxx4Kids-Denver/events/216557092/&quot;&gt;littleBits&lt;/a&gt; and a second on &lt;a
    href=&quot;http://www.meetup.com/Devoxx4Kids-Denver/events/219019619/&quot;&gt;Greenfoot&lt;/a&gt;.
    The kids had &lt;a href=&quot;//raibledesigns.com/rd/entry/devoxx4kids_denver_having_fun_with&quot;&gt;a lot of fun with
        littleBits&lt;/a&gt; thanks to &lt;a href=&quot;https://twitter.com/juansanchez&quot;&gt;Juan Sanchez&lt;/a&gt; of &lt;a
        href=&quot;https://twitter.com/tackmobile&quot;&gt;Tack Mobile&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

    &lt;a href=&quot;https://farm8.staticflickr.com/7502/15713320297_7e878f557d_c.jpg&quot;
       title=&quot;Juan in Action by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/15713320297&quot;&gt;&lt;img
        src=&quot;https://farm8.staticflickr.com/7502/15713320297_7e878f557d.jpg&quot; width=&quot;500&quot; alt=&quot;Juan in Action&quot;
        style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Unfortunately, I wasn&apos;t able to attend the Greenfoot workshop with &lt;a href=&quot;https://twitter.com/thesteve0&quot;&gt;Steve
    Pousty&lt;/a&gt;, but I heard it was awesome. Thanks again to &lt;a href=&quot;https://twitter.com/mojavelinux&quot;&gt;Dan Allen&lt;/a&gt; for
    assisting with this class.&lt;/p&gt;
&lt;p&gt;I haven&apos;t scheduled any Devoxx4Kids Denver meetups for 2015 yet. If you&apos;re interested in speaking, please let me
    know!&lt;/p&gt;
&lt;h3 id=&quot;projects&quot;&gt;Projects&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;AppFuse:&lt;/strong&gt; I didn&apos;t have many posts about AppFuse in 2014, but I did work on it from time to time.
    Upgrading its dependencies was a good way to stay up-to-date with open source frameworks, in addition to
    &lt;a href=&quot;//raibledesigns.com/rd/entry/how_do_you_stay_current&quot;&gt;lots of reading&lt;/a&gt;.
    &lt;a href=&quot;http://www.infoq.com/news/2014/01/appfuse-3.0-java7-spring-4&quot;&gt;InfoQ covered the AppFuse 3.0 release&lt;/a&gt;
    and I &lt;a href=&quot;http://www.infoq.com/author/Matt-Raible&quot;&gt;continue to write for them&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
    In December, I &lt;a href=&quot;//raibledesigns.com/rd/entry/appfuse_reduced&quot;&gt;removed 10,000 lines of XML&lt;/a&gt; from the
    project without affecting any functionality. In the past month, I&apos;ve &lt;a
    href=&quot;https://github.com/appfuse/appfuse/pull/22&quot;&gt;added support for generating CRUD&lt;/a&gt; for all
    its web frameworks (including AppFuse Light&apos;s). This includes Spring + FreeMarker, Stripes and Wicket. GWT support
    is still in progress. I hope to do a release soon; there&apos;s only &lt;a
    href=&quot;http://issues.appfuse.org/issues/?filter=10290&quot;&gt;10 issues left&lt;/a&gt; as of this writing.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Roller:&lt;/strong&gt; I didn&apos;t contribute any code to &lt;a href=&quot;http://roller.apache.org&quot;&gt;Apache Roller&lt;/a&gt; in
    2014, but I
    &lt;a href=&quot;//raibledesigns.com/rd/entry/this_site_now_powered_by&quot;&gt;upgraded this site to the latest release,
        upgraded to Java 8 + Tomcat 7, and integrated Wufoo Forms&lt;/a&gt;.
    I hope to make some scalability improvements to how I&apos;ve deployed Roller in the near future.&lt;/p&gt;

&lt;h2 id=&quot;personal&quot;&gt;Personal&lt;/h2&gt;
&lt;p&gt;I started off the year with a trip of a lifetime: &lt;a
    href=&quot;//raibledesigns.com/rd/entry/heli_skiing_in_british_columbia&quot;&gt;Heli Skiing in British Columbia with CMH
    Gothics&lt;/a&gt;. An excerpt from my blog post:
&lt;/p&gt;
&lt;blockquote class=&quot;quote&quot;&gt;
    Everyday was awesome, but Wednesday was incredible. It snowed 10 cm on Tuesday night, which turned into knee-deep
    powder and face shots. The hoots and hollers from everyone floating down forced my face into a sorta perma-grin. For
    many of us, it was the best skiing day of our entire lives. The video below tries to capture how much fun we had
    throughout the week, but ultimately fails. It&apos;s one of those things you have to experience to really appreciate. I
    ended up skiing around 80,000 vertical feet in four days.
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;http://farm8.staticflickr.com/7296/12079639335_d260827bdd_c.jpg&quot;
       data-href=&quot;http://www.flickr.com/photos/mraible/12079639335/&quot; title=&quot;Yee Haw! by mraible, on Flickr&quot;
       rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7296/12079639335_d260827bdd_m.jpg&quot; width=&quot;240&quot;
                                    alt=&quot;Yee Haw!&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;http://farm3.staticflickr.com/2853/12079930503_7b5271e6f1_c.jpg&quot;
       data-href=&quot;http://www.flickr.com/photos/mraible/12079930503/&quot; title=&quot;Group Photo by mraible, on Flickr&quot;
       rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm3.staticflickr.com/2853/12079930503_7b5271e6f1_m.jpg&quot; width=&quot;240&quot;
                                    alt=&quot;Group Photo&quot; style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;http://farm4.staticflickr.com/3829/12438946834_b13c351fc2_c.jpg&quot;
       data-href=&quot;http://www.flickr.com/photos/mraible/12438946834/&quot; title=&quot;Freshies by mraible, on Flickr&quot;
       rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.staticflickr.com/3829/12438946834_b13c351fc2.jpg&quot; width=&quot;500&quot;
                                    alt=&quot;Freshies&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;iframe src=&quot;//player.vimeo.com/video/86139573&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot;
            mozallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;
    After returning from British Columbia, Trish and I skied Breckenridge and Copper before taking the kids to Aspen for
    three feet of powder on Super Bowl weekend.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm8.staticflickr.com/7449/13966477190_b401b0450b_c.jpg&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/13966477190&quot; title=&quot;Copper! by Matt Raible, on Flickr&quot;&gt;&lt;img
        src=&quot;//farm8.staticflickr.com/7449/13966477190_b401b0450b.jpg&quot; width=&quot;500&quot; alt=&quot;Copper!&quot;
        style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm8.staticflickr.com/7352/14153277974_751d0a62c4_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/14153277974&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       title=&quot;Happy Kids by Matt Raible, on Flickr&quot;&gt;&lt;img
        src=&quot;//farm8.staticflickr.com/7352/14153277974_751d0a62c4_m.jpg&quot; width=&quot;240&quot; alt=&quot;Happy Kids&quot;
        style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;//farm8.staticflickr.com/7450/14153278784_fe50b717d8_c.jpg&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/14153278784&quot; title=&quot;Happy Trish by Matt Raible, on Flickr&quot;&gt;&lt;img
        src=&quot;//farm8.staticflickr.com/7450/14153278784_fe50b717d8_m.jpg&quot; width=&quot;240&quot; alt=&quot;Happy Trish&quot;
        style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;We skied all over Colorado in February and March. We even did some winter camping in the Syncro for Valentine&apos;s Day.
    It snowed a lot that night.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;//farm8.staticflickr.com/7295/13966464277_d75d38efda_c.jpg&quot;
                                 data-href=&quot;https://www.flickr.com/photos/mraible/13966464277&quot;
                                 rel=&quot;lightbox[2014yearinreview]&quot;
                                 title=&quot;Yikes! by Matt Raible, on Flickr&quot;&gt;&lt;img
    src=&quot;//farm8.staticflickr.com/7295/13966464277_d75d38efda.jpg&quot;
    width=&quot;500&quot; style=&quot;border: 1px solid black&quot; alt=&quot;Yikes!&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wrote about all our skiing adventures in &lt;a href=&quot;//raibledesigns.com/rd/entry/farewell_to_the_2013_2014&quot;&gt;Farewell
    to the 2013-2014 Ski Season&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On April 10th, I reminisced that &lt;a href=&quot;//raibledesigns.com/rd/entry/10_years_ago_today_i&quot;&gt;10 years ago today,
    I bought a VW Bus&lt;/a&gt;. In that post,
    I explained some body-work quality issues the current restoration shop found. Nevertheless, I still thought it would
    be done in &lt;em&gt;just a few more months&lt;/em&gt;.
&lt;/p&gt;
&lt;p&gt;
    We journeyed to Florida with Abbie and Jack for Spring Break. We relished in a super-fun family vacation where we
    golfed, swam and even spent a day frolicking with their Mom and
    fianc&#233; (now husband), Dave. We&apos;re pretty proud that we&apos;re all still a family even though Julie and I are divorced. I
    wrote about our vacation in
    &lt;a href=&quot;//raibledesigns.com/rd/entry/spring_break_in_florida_golf&quot;&gt;Spring Break in Florida: Golf, Beaches and
        Boats!&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm3.staticflickr.com/2871/13630302365_cdd438a1da_c.jpg&quot;
       data-href=&quot;//www.flickr.com/photos/mcginityphoto/13630302365&quot; title=&quot;Family photo by Trish McGinity, on Flickr&quot;
       rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm3.staticflickr.com/2871/13630302365_cdd438a1da_m.jpg&quot; width=&quot;240&quot;
                                            alt=&quot;Family photo&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;//farm4.staticflickr.com/3770/13630730864_66e90d2dcc_c.jpg&quot;
       data-href=&quot;//www.flickr.com/photos/mcginityphoto/13630730864&quot; title=&quot;Family photo by Trish McGinity, on Flickr&quot;
       rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.staticflickr.com/3770/13630730864_66e90d2dcc_m.jpg&quot; width=&quot;240&quot;
                                            alt=&quot;Family photo&quot; style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm8.staticflickr.com/7138/13630479433_2220968cfb_c.jpg&quot;
       data-href=&quot;//www.flickr.com/photos/mcginityphoto/13630479433&quot;
       title=&quot;Abbie and Jack playing at the beach by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm8.staticflickr.com/7138/13630479433_2220968cfb.jpg&quot; width=&quot;500&quot;
        alt=&quot;Abbie and Jack playing at the beach&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm8.staticflickr.com/7174/13695119114_2fbccbaa98_c.jpg&quot;
       data-href=&quot;//www.flickr.com/photos/mraible/13695119114&quot; title=&quot;Family Fun Day by Matt Raible, on Flickr&quot;
       rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7174/13695119114_2fbccbaa98.jpg&quot; width=&quot;500&quot;
                                            alt=&quot;Family Fun Day&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;//farm8.staticflickr.com/7152/13694777145_1fac338f01_c.jpg&quot; data-href=&quot;//www.flickr.com/photos/mraible/13694777145&quot; title=&quot;Happy Tuesday! by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7152/13694777145_1fac338f01.jpg&quot; width=&quot;500&quot; alt=&quot;Happy Tuesday!&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The hospitality from Trish&apos;s parents was like no other. I especially enjoyed a fishing trip with her Dad Joe in the
    Everglades. I love these people!&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm8.staticflickr.com/7046/13694837593_58d9e6b107_c.jpg&quot;
       data-href=&quot;//www.flickr.com/photos/mraible/13694837593&quot; title=&quot;Good lookin&apos; McGinity&apos;s by Matt Raible, on Flickr&quot;
       rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7046/13694837593_58d9e6b107.jpg&quot; width=&quot;500&quot;
                                            alt=&quot;Good lookin&apos; McGinity&apos;s&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Our winter activities in the Syncro were incredible. Trish sold her Nissan Xterra (the one with the &lt;a
    href=&quot;//raibledesigns.com/rd/entry/music_mountain_biking_and_memories&quot;&gt;sick bass&lt;/a&gt;) in December.
    Yes, that&apos;s right - we only had one vehicle during ski season last year. The fact that it worked so well
    is amazing. In May, we kicked it up a knotch and drove it to Moab for
    &lt;a href=&quot;//raibledesigns.com/rd/entry/syncro_solstice_2014&quot;&gt;Syncro Solstice&lt;/a&gt;. My parents went with us
    and we experienced fabulous weather and met a bunch of super-cool Vanagon owners.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm6.staticflickr.com/5078/14224287244_6265231910_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/14224287244&quot;
       title=&quot;National Park Lovers by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm6.staticflickr.com/5078/14224287244_6265231910_m.jpg&quot; width=&quot;240&quot; alt=&quot;National Park Lovers&quot;
        style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;//farm3.staticflickr.com/2898/14224288314_88efc37ddc_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/14224288314&quot; title=&quot;Arches Lover by Matt Raible, on Flickr&quot;
       rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm3.staticflickr.com/2898/14224288314_88efc37ddc_m.jpg&quot;
                                               width=&quot;240&quot; alt=&quot;Arches Lover&quot;
                                               style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm6.staticflickr.com/5554/14217096892_99a2cd5868_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14217096892&quot;
       title=&quot;Moab Sunset by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm6.staticflickr.com/5554/14217096892_99a2cd5868.jpg&quot; width=&quot;500&quot; alt=&quot;Moab Sunset&quot;
        style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;We made record time from Moab back to Denver (5 hours). The next day is when things started to go downhill. I washed
    the engine for the &lt;a href=&quot;http://www.vwgreenshow.com/&quot;&gt;VWs on the Green&lt;/a&gt; show. On that Monday, the engine started
    &quot;lurching&quot; where it seemed like it wasn&apos;t getting gas (it turned out to be caused by a lack of air). We drove the lurcher for several weeks, journeying to &lt;a href=&quot;http://campoutforthecause.org/&quot;&gt;Campout for
        the Cause&lt;/a&gt; and
    a &lt;a href=&quot;//raibledesigns.com/rd/entry/rafting_the_yampa_through_dinosaur&quot;&gt;exhilarating raft trip down the Yampa River&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm3.staticflickr.com/2933/14390991814_5f505549d1_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14390991814&quot;
       title=&quot;80&apos;s Party Group! by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm3.staticflickr.com/2933/14390991814_5f505549d1.jpg&quot; width=&quot;500&quot; style=&quot;border: 1px solid black&quot;
        alt=&quot;80&apos;s Party Group!&quot;&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm3.staticflickr.com/2896/14390758792_9d6270b5ee_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14390758792&quot;
       title=&quot;2014 DNM Raft Sunset by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm3.staticflickr.com/2896/14390758792_9d6270b5ee.jpg&quot; width=&quot;500&quot; style=&quot;border: 1px solid black&quot;
        alt=&quot;2014 DNM Raft Sunset&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    We had the lurching examined in mid-June by &lt;a href=&quot;http://www.rockymountainwesty.com/&quot;&gt;Rocky Mountain Westy&lt;/a&gt;; we also had them install some
    bumpers (for a better trailer hitch) and refreshed the tires. &lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm4.staticflickr.com/3863/14455716405_3e62021f4f_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/14455716405&quot;
       title=&quot;She cleans up real nice! by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm4.staticflickr.com/3863/14455716405_3e62021f4f.jpg&quot; width=&quot;500&quot; alt=&quot;She cleans up real nice!&quot;
        style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The ol&apos; van looked pretty good when our Dads arrived in Denver for &lt;a
    href=&quot;//raibledesigns.com/rd/entry/father_s_day_weekend_on1&quot;&gt;some whitewater on the Arkansas&lt;/a&gt;.

&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm4.staticflickr.com/3846/14269111618_d3edcef091_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14269111618&quot;
       title=&quot;Abbie doesn&apos;t approve of Jack&apos;s ponytail by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm4.staticflickr.com/3846/14269111618_d3edcef091_q.jpg&quot; width=&quot;150&quot;
        alt=&quot;Abbie doesn&apos;t approve of Jack&apos;s ponytail&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;//farm3.staticflickr.com/2904/14269108790_a028704fd5_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14269108790&quot;
       title=&quot;Here we go on the Arkansas River! by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm3.staticflickr.com/2904/14269108790_a028704fd5_q.jpg&quot; width=&quot;150&quot;
        alt=&quot;Here we go on the Arkansas River!&quot; style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;//farm4.staticflickr.com/3917/14269273977_5a9c0e24b7_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14269273977&quot;
       title=&quot;Kids having a blast :) by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm4.staticflickr.com/3917/14269273977_5a9c0e24b7_q.jpg&quot; width=&quot;150&quot; alt=&quot;Kids having a blast :)&quot;
        style=&quot;border: 1px solid black; margin-left: 15px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm4.staticflickr.com/3880/14475890743_dd49939dd1_c.jpg&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14475890743&quot; title=&quot;Dads Rule! by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.staticflickr.com/3880/14475890743_dd49939dd1.jpg&quot; width=&quot;500&quot; alt=&quot;Dads Rule!&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;In July, we skipped the annual road trip to The Cabin in favor of a &lt;a
    href=&quot;//raibledesigns.com/rd/entry/the_scenic_way_to_santa&quot;&gt;romantic road trip to see old friends in Santa Fe&lt;/a&gt;.
    The Syncro&apos;s engine seized on that trip and I experienced my favorite breakdown ever. The engine froze at a gas
    station near our Ski Shack and I was able to walk home. Luckily, Trish&apos;s Dad had recently (over Father&apos;s Day
    weekend) gifted his Nissan Maxima to us. After a train ride to fetch our other car, our road trip continued and we celebrated our
    first anniversary at &lt;a href=&quot;http://www.broadmoor.com/&quot;&gt;The Broadmoor&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm3.staticflickr.com/2919/14731242511_21c3bfb306_c.jpg&quot;
       title=&quot;Let me count the ways I love my husband! by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14731242511&quot;&gt;&lt;img
        src=&quot;https://farm3.staticflickr.com/2919/14731242511_21c3bfb306_m.jpg&quot;
        alt=&quot;Let me count the ways I love my husband!&quot; height=&quot;213&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3836/14734139772_a1a4587d6e_c.jpg&quot;
       title=&quot;The Broadmoor Reflection by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14734139772&quot;&gt;&lt;img
        src=&quot;https://farm4.staticflickr.com/3836/14734139772_a1a4587d6e_n.jpg&quot; alt=&quot;The Broadmoor Reflection&quot;
        width=&quot;320&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm3.staticflickr.com/2909/14734449205_cf43a022fb_c.jpg&quot;
       title=&quot;Broadmoor Pools Sunset by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14734449205&quot;&gt;&lt;img
        src=&quot;https://farm3.staticflickr.com/2909/14734449205_cf43a022fb.jpg&quot; width=&quot;500&quot; alt=&quot;Broadmoor Pools Sunset&quot;
        style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;After we returned from Santa Fe, I turned 40 years old. We rocked out a Journey concert to celebrate and Trish
    surprised me with a birthday visit from my kick-ass sister. The following evening, a bunch of friends took me
    on a Craft Brewery Tour in a school/prison bus. Both nights were epic.&lt;/p&gt;
&lt;p&gt;At the end of July, Trish had one of her favorite photos &lt;a
    href=&quot;//raibledesigns.com/rd/entry/mcginity_photo_on_the_cover&quot;&gt;featured on the cover of Whisky Magazine&lt;/a&gt;.&lt;/p&gt;
&lt;div style=&quot;text-align: center&quot;&gt;
    &lt;div class=&quot;fb-post fb_iframe_widget&quot;
         data-href=&quot;https://www.facebook.com/McGinityPhoto/photos/a.850652041614866.1073741826.227903283889748/900521199961283/?type=1&quot;
         data-width=&quot;381&quot; fb-xfbml-state=&quot;rendered&quot;
         fb-iframe-plugin-query=&quot;app_id=226411374036019&amp;amp;href=https%3A%2F%2Fwww.facebook.com%2FMcGinityPhoto%2Fphotos%2Fa.850652041614866.1073741826.227903283889748%2F900521199961283%2F%3Ftype%3D1&amp;amp;locale=en_US&amp;amp;sdk=joey&amp;amp;width=381&quot;&gt;&lt;span
        style=&quot;vertical-align: bottom; width: 381px; height: 688px;&quot;&gt;
&lt;iframe name=&quot;f34c3266e8&quot; width=&quot;381px&quot; height=&quot;1000px&quot; frameborder=&quot;0&quot; allowtransparency=&quot;true&quot; scrolling=&quot;no&quot;
        title=&quot;fb:post Facebook Social Plugin&quot;
        src=&quot;https://www.facebook.com/plugins/post.php?app_id=226411374036019&amp;amp;channel=https%3A%2F%2Fs-static.ak.facebook.com%2Fconnect%2Fxd_arbiter%2FoDB-fAAStWy.js%3Fversion%3D41%23cb%3Df24185ec44%26domain%3Draibledesigns.com%26origin%3Dhttps%253A%252F%252Fraibledesigns.com%252Ff23d0f86c%26relation%3Dparent.parent&amp;amp;href=https%3A%2F%2Fwww.facebook.com%2FMcGinityPhoto%2Fphotos%2Fa.850652041614866.1073741826.227903283889748%2F900521199961283%2F%3Ftype%3D1&amp;amp;locale=en_US&amp;amp;sdk=joey&amp;amp;width=381&quot;
        style=&quot;border: none; visibility: visible; width: 381px; height: 688px;&quot; class=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In August, we flew to Boston to celebrate Trish&apos;s Dad&apos;s 75th birthday. My parents joined us, we visited my Dad&apos;s
    family in New York and took the kids to the Big Apple. They loved the &lt;a
        href=&quot;https://www.facebook.com/photo.php?fbid=10152192418746712&amp;l=8ecc4d288d&quot;&gt;Statue of Liberty&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Abbie started middle school (6th grade) in mid-August and Jack started 4th grade. They looked great on their &lt;a
    href=&quot;//raibledesigns.com/rd/entry/the_first_day_of_school3&quot;&gt;first day of school&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a data-href=&quot;https://www.flickr.com/photos/mraible/14959942801&quot;
       href=&quot;https://farm6.staticflickr.com/5555/14959942801_f77e1b2539_c.jpg&quot;
       title=&quot;First Day of School 2014 by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;https://farm6.staticflickr.com/5555/14959942801_f77e1b2539.jpg&quot; width=&quot;313&quot; alt=&quot;First Day of School 2014&quot;
        style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;We were pumped about our &lt;a href=&quot;https://www.flickr.com/photos/mraible/sets/72157646475691716/&quot;&gt;new engine&lt;/a&gt; in
    the Syncro when we left Denver for &lt;a href=&quot;//raibledesigns.com/rd/entry/rafting_the_green_river_through&quot;&gt;Rafting
        the Green River through Desolation Canyon&lt;/a&gt;. We celebrated Jack&apos;s 10th birthday on that trip and had a very
    memorable expedition with some really cool people.&lt;/p&gt;
&lt;p&gt;Trish&apos;s photo from our last night on the river makes me want do it all again.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3874/15057533280_553792dd0b_c.jpg&quot;
       title=&quot;My favorite night shot by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mcginityphoto/15057533280&quot;&gt;&lt;img
        src=&quot;https://farm4.staticflickr.com/3874/15057533280_553792dd0b.jpg&quot; width=&quot;500&quot; alt=&quot;My favorite night shot&quot;
        style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;In October, I started considering health over wealth when we embarked on a &lt;a
    href=&quot;//raibledesigns.com/rd/entry/the_21_day_sugar_detox&quot;&gt;21-day Sugar Detox&lt;/a&gt;. I&apos;m proud to say that, as a
    result, I&apos;m off blood pressure medication and continue to lose weight and feel better. We&apos;re cooking at home more
    than ever, exercising daily and I&apos;ve lost almost 20 pounds in the process.&lt;/p&gt;
&lt;p&gt;Medallion, the horse that Trish and Abbie were leasing (and almost ready to buy) got sick with &lt;a
    href=&quot;http://en.wikipedia.org/wiki/Horse_colic&quot;&gt;colic&lt;/a&gt; on Friday, October 10. I remembered the day without
    looking at a calendar because Trish called me to tell me about his illness. She was out of town on a business trip and was
    absolutely distraught. She told me about the situation and asked me to visit Medallion while he endured extreme
    pain. I worked out of my van at the stables that day, checking on him every couple hours. They had to put him down
    that evening. Abbie took it pretty well when I told her a couple hours later, but there were heaps of tears later
    that night.&lt;/p&gt;
&lt;p&gt;Our little girl &lt;a href=&quot;//raibledesigns.com/rd/entry/happy_birthday_abbie8&quot;&gt;turned 12&lt;/a&gt; a few weeks later.
    The kids put on some dark costumes for Halloween.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;//farm6.staticflickr.com/5602/15102098834_11f2245aaf_c.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/15102098834&quot;
       title=&quot;Abbie and Jack - Halloween 2014 by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;&gt;&lt;img
        src=&quot;//farm6.staticflickr.com/5602/15102098834_11f2245aaf.jpg&quot; width=&quot;500&quot; alt=&quot;Abbie and Jack - Halloween 2014&quot;
        style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;A week later, I visited my parents in Montana. We played cribbage, ate scrumptious meals and trounced around the
    woods looking for bucks. I marveled at the &lt;a href=&quot;//raibledesigns.com/rd/entry/the_house&quot;&gt;beauty of my parents&apos;
        retirement home&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7478/15796548721_d411c4540c_c.jpg&quot;
       title=&quot;The House by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/15796548721&quot;&gt;&lt;img
        src=&quot;https://farm8.staticflickr.com/7478/15796548721_d411c4540c_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;The House&quot;
        style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm6.staticflickr.com/5613/15613589540_00b4e688cb_c.jpg&quot;
       title=&quot;Front Door by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/15613589540&quot;&gt;&lt;img
        src=&quot;https://farm6.staticflickr.com/5613/15613589540_00b4e688cb_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Front Door&quot;
        style=&quot;border: 1px solid black; margin-left: 15px;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7514/15798430545_eb55462d2a_c.jpg&quot;
       title=&quot;The Porch by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/15798430545&quot;&gt;&lt;img
        src=&quot;https://farm8.staticflickr.com/7514/15798430545_eb55462d2a_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;The Porch&quot;
        style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm6.staticflickr.com/5613/15613591370_95ed96861b_c.jpg&quot;
       title=&quot;Sweet Railings by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/15613591370&quot;&gt;&lt;img
        src=&quot;https://farm6.staticflickr.com/5613/15613591370_95ed96861b_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot;
        alt=&quot;Sweet Railings&quot; style=&quot;border: 1px solid black; margin-left: 15px;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I neglected to blog or tweet about my self-caused Syncro accidents in Q4 of 2014. Long story short: it&apos;s been getting
    body work done for quite some time (two accidents!) and I look forward to getting it back in tip-top-shape next
    week. Thank goodness for USAA insurance.&lt;/p&gt;
&lt;p&gt;The biggest event of the year happened just before Christmas: &lt;a
    href=&quot;//raibledesigns.com/rd/entry/the_bus_is_painted_holy&quot;&gt;THE BUS IS PAINTED!! HOLY CHRISTMAS PRESENT BATMAN!&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm8.staticflickr.com/7517/15887916088_ff0e2e5088_c.jpg&quot;
       title=&quot;JAMES VERHEY - WITH THE BEST CHRISTMAS PRESENT EVER! by Matt Raible, on Flickr&quot; rel=&quot;lightbox[2014yearinreview]&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/15887916088&quot;&gt;&lt;img
        src=&quot;https://farm8.staticflickr.com/7517/15887916088_ff0e2e5088.jpg&quot; width=&quot;500&quot;
        alt=&quot;JAMES VERHEY - WITH THE BEST CHRISTMAS PRESENT EVER!&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&quot;2015&quot;&gt;2015&lt;/h2&gt;
&lt;p&gt;It&apos;s hard to believe that 2015 could possibly top 2014. I started the year heli-skiing and ended it with a painted
    bus. &lt;em&gt;However&lt;/em&gt;, the bus isn&apos;t done yet. Last year, I wrote:&lt;/p&gt;
&lt;blockquote class=&quot;quote&quot;&gt;
    My goal for 2014 is singular: &lt;em&gt;finish The Bus.&lt;/em&gt;
&lt;/blockquote&gt;
&lt;p&gt;I continue that mission this year. I&apos;ve negotiated a deal with &lt;a href=&quot;http://www.reincarnationauto.com/&quot;&gt;ReinCARnation&lt;/a&gt;
    to have it done by April 1st. Yes, it seems strange that April Fools is the &lt;em&gt;finished bus&lt;/em&gt; delivery date.
    However, I&apos;m confident they&apos;ll make it happen. This could be the year I&apos;ve dreamed about since I was in high school.
    It was in 1991 that I first fantasized about putting a 911 engine in a VW Bus.
&lt;/p&gt;
&lt;p&gt;
    This year, I hope to be cruise around Colorado in two running VW Busses. From there, I plan to surround myself with the laughter of our children, the enthusiasm of our border collies and the warmness of Trish&apos;s love. It&apos;s gonna be a &lt;em&gt;really&lt;/em&gt; great year! &lt;img src=&quot;//raibledesigns.com/images/smileys/grin.gif&quot; class=&quot;smiley&quot; alt=&quot;:-D&quot; title=&quot;:-D&quot;&gt;
&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/getting_started_with_angularjs</id>
        <title type="html">Getting Started with AngularJS</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/getting_started_with_angularjs"/>
        <published>2015-01-29T11:12:38-07:00</published>
        <updated>2015-09-23T06:44:03-06:00</updated> 
        <category term="/The Web" label="The Web" />
        <category term="npm" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javascript" scheme="http://roller.apache.org/ns/tags/" />
        <category term="git" scheme="http://roller.apache.org/ns/tags/" />
        <category term="angularjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="node" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;I was hired by my current client in November to help them choose a technology stack for developing modern web applications.
   In our first sprint, we decided to look at JavaScript MVC frameworks. I suggested &lt;a href=&quot;https://angularjs.org/&quot;&gt;AngularJS&lt;/a&gt;, &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember.js&lt;/a&gt; and &lt;a href=&quot;http://facebook.github.io/react/&quot;&gt;React&lt;/a&gt;. Since
    most of the team was new to JavaScript MVC, I decided to create a tutorial for them. I tried to make it easy so they
    could learn how to write a simple web application with AngularJS. I thought others could benefit from this article as well,
so I asked (and received) permission from my client to publish it here.&lt;/p&gt;
&lt;h3&gt;What you&apos;ll build&lt;/h3&gt;
&lt;p&gt;You&apos;ll build a simple web application with AngularJS. You&apos;ll also add search and edit features with mock data.&lt;/p&gt;
&lt;h3&gt;What you&apos;ll need&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;About 15-30 minutes&lt;/li&gt;
    &lt;li&gt;A favorite text editor or IDE. I recommend &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ IDEA&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt; installed.&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; and NPM installed.&lt;/li&gt;
&lt;/ul&gt;</summary>
        <content type="html">&lt;p&gt;I was hired by my current client in November to help them choose a technology stack for developing modern web applications.
   In our first sprint, we decided to look at JavaScript MVC frameworks. I suggested &lt;a href=&quot;https://angularjs.org/&quot;&gt;AngularJS&lt;/a&gt;, &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember.js&lt;/a&gt; and &lt;a href=&quot;http://facebook.github.io/react/&quot;&gt;React&lt;/a&gt;. Since
    most of the team was new to JavaScript MVC, I decided to create a tutorial for them. I tried to make it easy so they
    could learn how to write a simple web application with AngularJS. I thought others could benefit from this article as well,
so I asked (and received) permission from my client to publish it here.&lt;/p&gt;
&lt;h3&gt;What you&apos;ll build&lt;/h3&gt;
&lt;p&gt;You&apos;ll build a simple web application with AngularJS. You&apos;ll also add search and edit features with mock data.&lt;/p&gt;
&lt;h3&gt;What you&apos;ll need&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;About 15-30 minutes&lt;/li&gt;
    &lt;li&gt;A favorite text editor or IDE. I recommend &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ IDEA&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt; installed.&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; and NPM installed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Create a simple web application&lt;/h3&gt;
&lt;ol&gt;
    &lt;li&gt;
        &lt;p&gt;Clone the angular-seed repository using &lt;a href=&quot;http://git-scm.com/&quot;&gt;git&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;
git clone https://github.com/angular/angular-seed.git angular-tutorial
cd angular-tutorial&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;There are two kinds of dependencies in this project: tools and angular framework code. The tools help manage
            and test the application.&lt;/p&gt;
        &lt;ul&gt;
            &lt;li&gt;To get the tools that depend upon via &lt;code&gt;npm&lt;/code&gt;, the &lt;a href=&quot;https://www.npmjs.org/&quot;&gt;node
                package manager&lt;/a&gt;.
            &lt;/li&gt;
            &lt;li&gt;To get the angular code via &lt;code&gt;bower&lt;/code&gt;, a &lt;a href=&quot;http://bower.io/&quot;&gt;client-side code package
                manager&lt;/a&gt;.
            &lt;/li&gt;
        &lt;/ul&gt;
        &lt;p&gt;The project has preconfigured &lt;code&gt;npm&lt;/code&gt;&amp;nbsp;to automatically run &lt;code&gt;bower&lt;/code&gt;&amp;nbsp;so you can
            simply do:&lt;/p&gt;
        &lt;pre&gt;npm install&lt;/pre&gt;
    &lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Run the application&lt;/h3&gt;
&lt;p&gt;The project is configured with a simple development web server. The simplest way to start this server is:&lt;/p&gt;
&lt;pre&gt;npm start&lt;/pre&gt;
&lt;p&gt;Now browse to the app at &lt;code&gt;&lt;a href=&quot;http://localhost:8000/app/index.html&quot;&gt;http://localhost:8000/app/&lt;/a&gt;&lt;/code&gt;.
&lt;/p&gt;
&lt;h3&gt;Add a search feature&lt;/h3&gt;
&lt;p&gt;To add a search feature, open the project in an IDE or your favorite text editor. For IntelliJ IDEA, use File &amp;gt;
    New Project &amp;gt; Static Web and point to the directory you cloned angular-seed to.&lt;/p&gt;
&lt;h3&gt;The Basics&lt;/h3&gt;
&lt;ol&gt;
    &lt;li&gt;
        &lt;p&gt;Create an &lt;code&gt;app/search/index.html&lt;/code&gt; file with the following HTML:&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;form ng-submit=&quot;search()&quot;&amp;gt;
    &amp;lt;input type=&quot;search&quot; name=&quot;search&quot; ng-model=&quot;term&quot;&amp;gt;
    &amp;lt;button&amp;gt;Search&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Create &lt;code&gt;app/search/search.js&lt;/code&gt; and define the routes (URLs) and controller for the search feature.
        &lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
angular.module(&apos;myApp.search&apos;, [&apos;ngRoute&apos;])

    .config([&apos;$routeProvider&apos;, function ($routeProvider) {
        $routeProvider
            .when(&apos;/search&apos;, {
                templateUrl: &apos;search/index.html&apos;,
                controller: &apos;SearchController&apos;
            })
    }])

    .controller(&apos;SearchController&apos;, function () {
        console.log(&quot;In Search Controller...&quot;);
    });
&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Modify &lt;code&gt;app/app.js&lt;/code&gt; and add the &amp;quot;myApp.search&amp;quot; module you created above.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;angular.module(&apos;myApp&apos;, [
  &apos;ngRoute&apos;,
  &apos;myApp.view1&apos;,
  &apos;myApp.view2&apos;,
  &apos;myApp.version&apos;,
  &apos;myApp.search&apos;
])&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Modify &lt;code&gt;app/index.html&lt;/code&gt; and add a link to the search.js file.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;script src=&quot;view2/view2.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;search/search.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;components/version/version.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Refresh your browser and navigate to &lt;a href=&quot;http://localhost:8000/app/#/search&quot;&gt;http://localhost:8000/app/#/search.&lt;/a&gt;
            You should see an input field and search button. You should also see a log message printed in your browser&apos;s
            console.
            In Chrome, you can view the console using View &amp;gt; Developer &amp;gt; JavaScript Console. You can make it
            easier to navigate to this page by adding a menu item in &lt;code&gt;app/index.html&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;ul class=&quot;menu&quot;&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#/view1&quot;&amp;gt;view1&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#/view2&quot;&amp;gt;view2&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#/search&quot;&amp;gt;search&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/pre&gt;
    &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This section has shown you how to add a new controller and view to a basic AngularJS application. This was fairly simple to create.
    The next section shows you how to create a fake backend API. &lt;/p&gt;
&lt;h3&gt;The Backend&lt;/h3&gt;
&lt;p&gt;To get search results, you&apos;re going to create a SearchService
    that makes HTTP requests. These HTTP requests will be handled by a mock backend using some of Angular&apos;s built-in
    mocking tools. The backend implementation was created using &lt;a
        href=&quot;http://www.jeremyzerr.com/angularjs-backend-less-development-using-httpbackend-mock&quot;&gt;AngularJS Backend-less Development Using a $httpBackend Mock&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;
        &lt;p&gt;Add a &lt;code&gt;SearchService&lt;/code&gt; to &lt;code&gt;app/search/search.js&lt;/code&gt;. This is done in Angular using its &lt;a
            href=&quot;https://docs.angularjs.org/guide/providers#factory-recipe&quot;&gt;Factory Recipe&lt;/a&gt;. Make sure to remove the
            semicolon from the &lt;code&gt;.controller&lt;/code&gt; code block.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;.controller(&apos;SearchController&apos;, function () {
    console.log(&quot;In Search Controller...&quot;);
})

.factory(&apos;SearchService&apos;, function ($http) {
    var service = {
        query: function (term) {
            return $http.get(&apos;/search/&apos; + term);
        }
    };
    return service;
});
&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Inject the &lt;code&gt;SearchService&lt;/code&gt; into the &lt;code&gt;SearchController&lt;/code&gt; and use it to get results from
            the backend. The form in &lt;code&gt;app/search/index.html&lt;/code&gt; calls the &lt;code&gt;search()&lt;/code&gt; function. The
            &amp;quot;term&amp;quot; is defined by the input field in this page with
            &lt;span style=&quot;color: rgb(0,0,255);&quot;&gt;ng-model=&lt;/span&gt;&lt;span
                style=&quot;color: rgb(0,128,0);&quot;&gt;&amp;quot;term&amp;quot;.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;.controller(&apos;SearchController&apos;, function ($scope, SearchService) {
    $scope.search = function () {
        console.log(&quot;Search term is: &quot; + $scope.term);
        SearchService.query($scope.term).then(function (response) {
            $scope.searchResults = response.data;
        });
    };
})&lt;/pre&gt;
        &lt;p&gt;If you try to search for a &quot;foo&quot; term now, you&apos;ll see the following error in your console.&lt;/p&gt;
        &lt;pre&gt;Search term is: foo&lt;br/&gt;GET &lt;a href=&quot;http://localhost:8000/search/foo&quot;&gt;http://localhost:8000/search/foo&lt;/a&gt; 404 (Not Found)&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Create &lt;code&gt;app/search/mock-api.js&lt;/code&gt; for the fake backend. Populate it with the following JavaScript.
        &lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;// We will be using backend-less development
// $http uses $httpBackend to make its calls to the server
// $resource uses $http, so it uses $httpBackend too
// We will mock $httpBackend, capturing routes and returning data
angular.module(&apos;myApp&apos;)
    .service(&apos;ServerDataModel&apos;, function ServerDataModel() {
        this.data = [
            {
                id: 1,
                name: &quot;Peyton Manning&quot;,
                phone: &quot;(303) 567-8910&quot;,
                address: {
                    street: &quot;1234 Main Street&quot;,
                    city: &quot;Greenwood Village&quot;,
                    state: &quot;CO&quot;,
                    zip: &quot;80111&quot;
                }
            },
            {
                id: 2,
                name: &quot;Demaryius Thomas&quot;,
                phone: &quot;(720) 213-9876&quot;,
                address: {
                    street: &quot;5555 Marion Street&quot;,
                    city: &quot;Denver&quot;,
                    state: &quot;CO&quot;,
                    zip: &quot;80202&quot;
                }
            },
            {
                id: 3,
                name: &quot;Von Miller&quot;,
                phone: &quot;(917) 323-2333&quot;,
                address: {
                    street: &quot;14 Mountain Way&quot;,
                    city: &quot;Vail&quot;,
                    state: &quot;CO&quot;,
                    zip: &quot;81657&quot;
                }
            }
        ];

        this.getData = function () {
            return this.data;
        };

        this.search = function (term) {
            if (term == &quot;&quot; || term == &quot;*&quot;) {
                return this.getData();
            }
            // find the name that matches the term
            var list = $.grep(this.getData(), function (element, index) {
                term = term.toLowerCase();
                return (element.name.toLowerCase().match(term));
            });

            if (list.length === 0) {
                return [];
            } else {
                return list;
            }
        };
    })
    .run(function ($httpBackend, ServerDataModel) {

        $httpBackend.whenGET(/\/search\/\w+/).respond(function (method, url, data) {
            // parse the matching URL to pull out the term (/search/:term)
            var term = url.split(&apos;/&apos;)[2];

            var results = ServerDataModel.search(term);

            return [200, results, {Location: &apos;/search/&apos; + term}];
        });

        $httpBackend.whenGET(/search\/index.html/).passThrough();
        $httpBackend.whenGET(/view/).passThrough();
    });&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;This file uses &lt;a href=&quot;http://api.jquery.com/jquery.grep/&quot;&gt;jQuery.grep()&lt;/a&gt;, so you&apos;ll need to install
            jQuery. Modify &lt;code&gt;bower.json&lt;/code&gt; and add jQuery to the list of dependencies. &lt;pre
        class=&quot;brush: js&quot;&gt;&quot;dependencies&quot;: {
  ...
  &quot;html5-boilerplate&quot;: &quot;~4.3.0&quot;,
  &quot;jquery&quot;: &quot;~1.10.x&quot;
}&lt;/pre&gt;
        &lt;p&gt;Stop the npm process, run
            &amp;quot;npm install&amp;quot; to download and install jQuery, then &amp;quot;npm start&amp;quot; again.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Modify &lt;code&gt;app/app.js&lt;/code&gt;&amp;nbsp;and add a dependency on &lt;a
            href=&quot;https://docs.angularjs.org/api/ngMockE2E&quot;&gt;ngMockE2E&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;angular.module(&apos;myApp&apos;, [&apos;ngMockE2E&apos;,
  &apos;ngRoute&apos;,
  ...&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Modify &lt;code&gt;app/index.html&lt;/code&gt; to include references to &lt;code&gt;jquery.js&lt;/code&gt;,
            &lt;code&gt;angular-mocks.js&lt;/code&gt; and &lt;code&gt;mock-api.js&lt;/code&gt;.&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
&amp;lt;script src=&quot;bower_components/angular-route/angular-route.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;bower_components/angular-mocks/angular-mocks.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;bower_components/jquery/jquery.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
...
&amp;lt;script src=&quot;search/mock-api.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;components/version/version.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Add the following HTML to &lt;code&gt;app/search/index.html&lt;/code&gt; to display the search results.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;div&amp;gt;
    &amp;lt;pre&amp;gt;{{ searchResults | json}}&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
        &lt;p&gt;After making this change, you should be able to search for &amp;quot;p&amp;quot;, &amp;quot;d&amp;quot; or &amp;quot;v&amp;quot; and
            see results as JSON.&lt;/p&gt;&lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;To make the results more readable, change the above HTML to use a &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; and Angular&apos;s &lt;a
            href=&quot;https://docs.angularjs.org/api/ng/directive/ngRepeat&quot;&gt;ng-repeat&lt;/a&gt; directive.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;table ng-show=&quot;searchResults.length&quot; style=&quot;width: 100%&quot;&amp;gt;
    &amp;lt;thead&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Phone&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Address&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
    &amp;lt;tr ng-repeat=&quot;person in searchResults&quot;&amp;gt;
        &amp;lt;td&amp;gt;{{person.name}}&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;{{person.phone}}&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;{{person.address.street}}&amp;lt;br/&amp;gt;
            {{person.address.city}}, {{person.address.state}} {{person.address.zip}}
        &amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/pre&gt;
    &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This section has shown you how to fetch and display search results. The next section builds on this and shows how to edit and save a record.&lt;/p&gt;
&lt;h3&gt;Add an Edit Feature&lt;/h3&gt;
&lt;ol&gt;
    &lt;li&gt;
        &lt;p&gt;Modify &lt;code&gt;app/search/index.html&lt;/code&gt;&amp;nbsp;to add a link for editing a person.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;table ng-show=&quot;searchResults.length&quot; style=&quot;width: 100%&quot;&amp;gt;
    ...
    &amp;lt;tr ng-repeat=&quot;person in searchResults&quot;&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;a href=&quot;&quot; ng-click=&quot;edit(person)&quot;&amp;gt;{{person.name}}&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
        ...
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Add an &lt;code&gt;edit()&lt;/code&gt; function to &lt;code&gt;SearchController&lt;/code&gt;.
           Notice that the &lt;a href=&quot;https://docs.angularjs.org/api/ng/service/$location&quot;&gt;$location service&lt;/a&gt;
            dependency has been added to the controller&apos;s initialization function. &lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
.controller(&apos;SearchController&apos;, function ($scope, $location, SearchService) {
    ...

    $scope.edit = function (person) {
        $location.path(&quot;/edit/&quot; + person.id);
    }
})&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Create a route to handle the edit URL in &lt;code&gt;app/search/search.js&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
.config([&apos;$routeProvider&apos;, function ($routeProvider) {
    $routeProvider
        .when(&apos;/search&apos;, {
            templateUrl: &apos;search/index.html&apos;,
            controller: &apos;SearchController&apos;
        })
        .when(&apos;/edit/:id&apos;, {
            templateUrl: &apos;search/edit.html&apos;,
            controller: &apos;EditController&apos;
        });
}])&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Create &lt;code&gt;app/search/edit.html&lt;/code&gt; to display an editable form. The HTML below shows how you can use &lt;a
            href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes&quot;&gt;HTML5&apos;s data
            attributes&lt;/a&gt; to have valid attributes instead of ng-*.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
&amp;lt;form ng-submit=&quot;save()&quot;&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;label for=&quot;name&quot;&amp;gt;Name:&amp;lt;/label&amp;gt;
        &amp;lt;input type=&quot;text&quot; data-ng-model=&quot;person.name&quot; id=&quot;name&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;label for=&quot;phone&quot;&amp;gt;Phone:&amp;lt;/label&amp;gt;
        &amp;lt;input type=&quot;text&quot; data-ng-model=&quot;person.phone&quot; id=&quot;phone&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;fieldset&amp;gt;
        &amp;lt;legend&amp;gt;Address:&amp;lt;/legend&amp;gt;
        &amp;lt;address style=&quot;margin-left: 50px&quot;&amp;gt;
            &amp;lt;input type=&quot;text&quot; data-ng-model=&quot;person.address.street&quot;&amp;gt;&amp;lt;br/&amp;gt;
            &amp;lt;input type=&quot;text&quot; data-ng-model=&quot;person.address.city&quot;&amp;gt;,
            &amp;lt;input type=&quot;text&quot; data-ng-model=&quot;person.address.state&quot; size=&quot;2&quot;&amp;gt;
            &amp;lt;input type=&quot;text&quot; data-ng-model=&quot;person.address.zip&quot; size=&quot;5&quot;&amp;gt;
        &amp;lt;/address&amp;gt;
    &amp;lt;/fieldset&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;button type=&quot;submit&quot;&amp;gt;Save&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Modify &lt;code&gt;SearchService&lt;/code&gt;&amp;nbsp;to contain functions for finding a person by their id, and saving
            them.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
.factory(&apos;SearchService&apos;, function ($http) {
    var service = {
        query: function (term) {
            return $http.get(&apos;/search/&apos; + term);
        },
        fetch: function (id) {
            return $http.get(&apos;/edit/&apos; + id);
        },
        save: function(data) {
            return $http.post(&apos;/edit/&apos; + data.id, data);
        }
    };
    return service;
});&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Create &lt;code&gt;EditController&lt;/code&gt; in &lt;code&gt;app/search/search.js&lt;/code&gt;. &lt;a
            href=&quot;https://docs.angularjs.org/api/ngRoute/service/$routeParams&quot;&gt;$routeParams&lt;/a&gt; is an Angular service
            that allows you to grab parameters from a URL.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
.controller(&apos;EditController&apos;, function ($scope, $location, $routeParams, SearchService) {
    SearchService.fetch($routeParams.id).then(function (response) {
        $scope.person = response.data;
    });

    $scope.save = function() {
        SearchService.save($scope.person).then(function(response) {
            $location.path(&quot;/search/&quot; + $scope.person.name);
        });
    }
})&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;At the bottom of &lt;code&gt;app/search/mock-api.js&lt;/code&gt;, in its &lt;code&gt;run()&lt;/code&gt; function, add the following:
        &lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;$httpBackend.whenGET(/\/search/).respond(function (method, url, data) {
    var results = ServerDataModel.search(&quot;&quot;);

    return [200, results];
});

$httpBackend.whenGET(/\/edit\/\d+/).respond(function (method, url, data) {
    // parse the matching URL to pull out the id (/edit/:id)
    var id = url.split(&apos;/&apos;)[2];

    var results = ServerDataModel.find(id);

    return [200, results, {Location: &apos;/edit/&apos; + id}];
});

$httpBackend.whenPOST(/\/edit\/\d+/).respond(function(method, url, data) {
    var params = angular.fromJson(data);

    // parse the matching URL to pull out the id (/edit/:id)
    var id = url.split(&apos;/&apos;)[2];

    var person = ServerDataModel.update(id, params);

    return [201, person, { Location: &apos;/edit/&apos; + id }];
});

$httpBackend.whenGET(/search\/edit.html/).passThrough();&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Further up in the same file, add &lt;code&gt;find()&lt;/code&gt; and &lt;code&gt;update()&lt;/code&gt; methods to &lt;code&gt;ServerDataModel&lt;/code&gt;.
        &lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;this.getData = function () {
    return this.data;
};

this.search = function (term) {
    ...
};

this.find = function (id) {
    // find the game that matches that id
    var list = $.grep(this.getData(), function (element, index) {
        return (element.id == id);
    });
    if (list.length === 0) {
        return {};
    }
    // even if list contains multiple items, just return first one
    return list[0];
};

this.update = function (id, dataItem) {
    // find the game that matches that id
    var people = this.getData();
    var match = null;
    for (var i = 0; i &lt; people.length; i++) {
        if (people[i].id == id) {
            match = people[i];
            break;
        }
    }
    if (!angular.isObject(match)) {
        return {};
    }
    angular.extend(match, dataItem);
    return match;
};&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;The &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; in &lt;code&gt;app/search/edit.html&lt;/code&gt;&amp;nbsp;calls a &lt;code&gt;save()&lt;/code&gt; function to update a
            person&apos;s data. You already implemented this above. The function executes the logic below.&amp;nbsp;&lt;/p&gt;
        &lt;pre class=&quot;brush: js&quot;&gt;$location.path(&quot;/search/&quot; + $scope.person.name);&lt;/pre&gt;
        &lt;p&gt;Since the SearchController doesn&apos;t execute a search automatically when you execute this URL, add the
            following logic to do so in &lt;code&gt;app/search/search.js&lt;/code&gt;. Note that
            &lt;code&gt;$routeParams&lt;/code&gt; is added to the list of injected dependencies.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
.controller(&apos;SearchController&apos;, function ($scope, $location, $routeParams, SearchService) {
    if ($routeParams.term) {
        SearchService.query($routeParams.term).then(function (response) {
            $scope.term = $routeParams.term;
            $scope.searchResults = response.data;
        });
    }
    ...
})&lt;/pre&gt;
        &lt;p&gt;You&apos;ll also need to add a new route so search/term is recognized.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;.config([&apos;$routeProvider&apos;, function ($routeProvider) {
    $routeProvider
        .when(&apos;/search&apos;, {
            templateUrl: &apos;search/index.html&apos;,
            controller: &apos;SearchController&apos;
        })
        .when(&apos;/search/:term&apos;, {
            templateUrl: &apos;search/index.html&apos;,
            controller: &apos;SearchController&apos;
        })
        ...
}])&lt;/pre&gt;
    &lt;/li&gt;
    &lt;li&gt;After making all these changes, you should be able to refresh your browser and search/edit/update a person&apos;s
        information. If it works - nice job!
    &lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Source Code&lt;/h3&gt;
&lt;p&gt;A completed project with this code in it is available on GitHub at &lt;a
    href=&quot;https://github.com/mraible/angular-tutorial&quot;&gt;https://github.com/mraible/angular-tutorial&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;There are three commits that make the changes for the three main steps in this tutorial:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a
        href=&quot;https://github.com/mraible/angular-tutorial/commit/9792a0fbf1c2a5f1171498de7666e6f13cdd0537&quot;&gt;The
        Basics&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a
        href=&quot;https://github.com/mraible/angular-tutorial/commit/e9c277a50606d7ebaf9bcefa46f5942e2edf7ecf&quot;&gt;The
        Backend&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a
        href=&quot;https://github.com/mraible/angular-tutorial/commit/56be9decd0242dd60f06ef7232db723d6595ed0c&quot;&gt;Add
        an Edit Feature&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Extra Credit&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://linqed.eu/2014/10/07/deploying-angular-seed-to-heroku/&quot;&gt;Deploy your completed app to Heroku&lt;/a&gt;. See
    running version of this tutorial at &lt;a
        href=&quot;https://angular-123.herokuapp.com&quot;&gt;https://angular-123.herokuapp.com&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;I hope you&apos;ve enjoyed this quick-and-easy tutorial on how to get started with AngularJS. In a future tutorial, I&apos;ll show
you &lt;a href=&quot;//raibledesigns.com/rd/entry/testing_angularjs_applications&quot;&gt;how to write unit tests and integration tests for this application&lt;/a&gt;. If you&apos;re in Denver next Tuesday, I&apos;ll be &lt;a href=&quot;http://www.meetup.com/DOSUG1/events/219099019/&quot;&gt;speaking about AngularJS at Denver&apos;s Open Source Users Group&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&apos;re a Java developer that&apos;s interested in developing with AngularJS and Spring Boot, you might want to checkout
the &lt;a href=&quot;http://www.infoq.com/news/2015/01/jhipster-2.0&quot;&gt;recently released JHipster 2.0&lt;/a&gt;.&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/appfuse_reduced</id>
        <title type="html">AppFuse, Reduced</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/appfuse_reduced"/>
        <published>2014-12-16T06:03:31-07:00</published>
        <updated>2014-12-17T16:39:14-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maintenance" scheme="http://roller.apache.org/ns/tags/" />
        <category term="lessxml" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;
In November, I had some time off between clients. To occupy my time, I exercised my body and brain a bit. I spent a couple hours a day exercising and a few hours a day working on
&lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt;. AppFuse isn&apos;t used to start projects nearly as much as it once was. This makes sense since there&apos;s been a ton of innovation on the JVM and there&apos;s lots of
&lt;em&gt;get-started-quickly&lt;/em&gt; frameworks now. Among my favorites are Spring Boot, JHipster, Grails and Play.
&lt;p&gt;
    You can see that AppFuse&apos;s community activity has decreased quite a bit over the years by looking at its mailing list
    traffic.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;http://appfuse.markmail.org/&quot;
       title=&quot;AppFuse Mailing List Traffic, December 2014 by Matt Raible, on Flickr&quot;&gt;&lt;img
        src=&quot;https://farm8.staticflickr.com/7525/15825430580_0531875e59.jpg&quot; width=&quot;500&quot; 
        alt=&quot;AppFuse Mailing List Traffic, December 2014&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    Even though there&apos;s not a lot of users talking on the mailing list, it still seems to get quite a few downloads from
    Maven Central.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://www.flickr.com/photos/mraible/16011987392&quot;
       title=&quot;AppFuse Maven Central Stats, November 2014 by Matt Raible, on Flickr&quot;&gt;&lt;img
        src=&quot;https://farm8.staticflickr.com/7534/16011987392_442236433b.jpg&quot; width=&quot;500&quot; 
        alt=&quot;AppFuse Maven Central Stats, November 2014&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    I think the biggest value that AppFuse provides now is a learning tool for those who work on it. Also, it&apos;s a good place to
    show other developers how they can evolve with open source frameworks (e.g. Spring, Hibernate, JSF, Tapestry, Struts) over several years. Showing how
    we migrated to Spring MVC Test, for example, might be useful. The upcoming move to Spring Data instead of our
    Generic DAO solution might be interesting as well. 
&lt;/p&gt;
&lt;p&gt;
    Regardless of whether AppFuse is used a lot or not, it should be easy to maintain. Over the several weeks, I made some
    opinionated changes and achieved some pretty good progress on simplifying things and making the project easier to
    maintain. The previous structure has a lot of duplicate versions, properties and plugin configurations between
    different projects. I was able to leverage Maven&apos;s inheritance model to make a number of improvements:
&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;
In November, I had some time off between clients. To occupy my time, I exercised my body and brain a bit. I spent a couple hours a day exercising and a few hours a day working on
&lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt;. AppFuse isn&apos;t used to start projects nearly as much as it once was. This makes sense since there&apos;s been a ton of innovation on the JVM and there&apos;s lots of
&lt;em&gt;get-started-quickly&lt;/em&gt; frameworks now. Among my favorites are Spring Boot, JHipster, Grails and Play.
&lt;p&gt;
    You can see that AppFuse&apos;s community activity has decreased quite a bit over the years by looking at its mailing list
    traffic.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;http://appfuse.markmail.org/&quot;
       title=&quot;AppFuse Mailing List Traffic, December 2014 by Matt Raible, on Flickr&quot;&gt;&lt;img
        src=&quot;https://farm8.staticflickr.com/7525/15825430580_0531875e59.jpg&quot; width=&quot;500&quot; 
        alt=&quot;AppFuse Mailing List Traffic, December 2014&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    Even though there&apos;s not a lot of users talking on the mailing list, it still seems to get quite a few downloads from
    Maven Central.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://www.flickr.com/photos/mraible/16011987392&quot;
       title=&quot;AppFuse Maven Central Stats, November 2014 by Matt Raible, on Flickr&quot;&gt;&lt;img
        src=&quot;https://farm8.staticflickr.com/7534/16011987392_442236433b.jpg&quot; width=&quot;500&quot; 
        alt=&quot;AppFuse Maven Central Stats, November 2014&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    I think the biggest value that AppFuse provides now is a learning tool for those who work on it. Also, it&apos;s a good place to
    show other developers how they can evolve with open source frameworks (e.g. Spring, Hibernate, JSF, Tapestry, Struts) over several years. Showing how
    we migrated to Spring MVC Test, for example, might be useful. The upcoming move to Spring Data instead of our
    Generic DAO solution might be interesting as well. 
&lt;/p&gt;
&lt;p&gt;
    Regardless of whether AppFuse is used a lot or not, it should be easy to maintain. Over the several weeks, I made some
    opinionated changes and achieved some pretty good progress on simplifying things and making the project easier to
    maintain. The previous structure has a lot of duplicate versions, properties and plugin configurations between
    different projects. I was able to leverage Maven&apos;s inheritance model to make a number of improvements:
&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Changed AppFuse&apos;s parent to be based on the &lt;a
        href=&quot;http://www.infoq.com/news/2014/07/springio-platform&quot;&gt;Spring IO Platform&lt;/a&gt;. This project
        is a dependency manager that defines version numbers for open source projects that work well with Spring.
    &lt;/li&gt;
    &lt;li&gt;Defined plugins, their versions and configurations in &lt;code&gt;&amp;lt;pluginManagement&gt;&lt;/code&gt;.&lt;/li&gt;
    &lt;li&gt;Defined dependencies, their versions and exclusions in &lt;code&gt;&amp;lt;dependencyManagement&gt;&lt;/code&gt;.&lt;/li&gt;
    &lt;li&gt;Simplified archetypes so new projects have minimal dependencies. For example, here&apos;s a basic project&apos;s &lt;code&gt;pom.xml&lt;/code&gt;:
    &lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&amp;gt;

    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
    &amp;lt;groupId&amp;gt;com.company&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;springmvc-project&amp;lt;/artifactId&amp;gt;
    &amp;lt;packaging&amp;gt;war&amp;lt;/packaging&amp;gt;
    &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
    &amp;lt;name&amp;gt;AppFuse Spring MVC Application&amp;lt;/name&amp;gt;

    &amp;lt;parent&amp;gt;
        &amp;lt;groupId&amp;gt;org.appfuse&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;appfuse-web&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;3.5.0-SNAPSHOT&amp;lt;/version&amp;gt;
    &amp;lt;/parent&amp;gt;

    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;de.juplo&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;hibernate4-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;/plugin&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;dbunit-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;/plugin&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;build-helper-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;

    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.appfuse&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;appfuse-${web.framework}&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${appfuse.version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;

    &amp;lt;properties&amp;gt;
        &amp;lt;amp.genericCore&amp;gt;true&amp;lt;/amp.genericCore&amp;gt;
        &amp;lt;amp.fullSource&amp;gt;false&amp;lt;/amp.fullSource&amp;gt;
        &amp;lt;dao.framework&amp;gt;hibernate&amp;lt;/dao.framework&amp;gt;
        &amp;lt;db.name&amp;gt;mydatabase&amp;lt;/db.name&amp;gt;
        &amp;lt;web.framework&amp;gt;spring&amp;lt;/web.framework&amp;gt;

        &amp;lt;!-- Framework/Plugin versions --&amp;gt;
        &amp;lt;appfuse.version&amp;gt;3.5.0-SNAPSHOT&amp;lt;/appfuse.version&amp;gt;
        &amp;lt;java.version&amp;gt;1.7&amp;lt;/java.version&amp;gt;
    &amp;lt;/properties&amp;gt;

    &amp;lt;profiles&amp;gt;
        &amp;lt;profile&amp;gt;
            &amp;lt;id&amp;gt;itest&amp;lt;/id&amp;gt;
            &amp;lt;build&amp;gt;
                &amp;lt;plugins&amp;gt;
                    &amp;lt;plugin&amp;gt;
                        &amp;lt;groupId&amp;gt;org.codehaus.cargo&amp;lt;/groupId&amp;gt;
                        &amp;lt;artifactId&amp;gt;cargo-maven2-plugin&amp;lt;/artifactId&amp;gt;
                    &amp;lt;/plugin&amp;gt;
                    &amp;lt;plugin&amp;gt;
                        &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
                        &amp;lt;artifactId&amp;gt;webtest-maven-plugin&amp;lt;/artifactId&amp;gt;
                    &amp;lt;/plugin&amp;gt;
                &amp;lt;/plugins&amp;gt;
            &amp;lt;/build&amp;gt;
        &amp;lt;/profile&amp;gt;
    &amp;lt;/profiles&amp;gt;

    &amp;lt;reporting&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;webtest-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/reporting&amp;gt;
&amp;lt;/project&amp;gt;
&lt;/pre&gt;
&lt;style type=&quot;text/css&quot;&gt;
    span.diffstat {
        white-space: nowrap;
        text-align: right;
        font-family: Helvetica, arial, freesans, clean, sans-serif, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;
        color: #666;
        font-weight: bold;
        font-size: 12px;
        cursor: default;
    }

    span.diffstat .lines-added, span.diffstat .lines-deleted {
        display: inline-block;
        margin-left: 3px;
        font-weight: bold;
    }
&lt;/style&gt;
&lt;p&gt;
    The pull request for these changes says it all:
&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/appfuse/appfuse/pull/20&quot;&gt;AppFuse&lt;/a&gt; &lt;span class=&quot;diffstat&quot;&gt;
          &lt;span class=&quot;lines-added&quot; style=&quot;color: #55a532&quot;&gt;
            &lt;span class=&quot;diffstat-icon&quot;&gt;+&lt;/span&gt;4,822
          &lt;/span&gt;
          &lt;span class=&quot;lines-deleted&quot; style=&quot;color: #bd2c00&quot;&gt;
            &lt;span class=&quot;diffstat-icon&quot;&gt;-&lt;/span&gt;14,369
          &lt;/span&gt;
        &lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/appfuse/appfuse-light/pull/1&quot;&gt;AppFuse Light&lt;/a&gt; &lt;span class=&quot;diffstat&quot;&gt;
              &lt;span class=&quot;lines-added&quot; style=&quot;color: #55a532&quot;&gt;
                &lt;span class=&quot;diffstat-icon&quot;&gt;+&lt;/span&gt;776
              &lt;/span&gt;
              &lt;span class=&quot;lines-deleted&quot; style=&quot;color: #bd2c00&quot;&gt;
                &lt;span class=&quot;diffstat-icon&quot;&gt;-&lt;/span&gt;4,687
              &lt;/span&gt;

            &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&apos;s right, I was able to eliminate a good chunk of code without affecting any of AppFuse&apos;s functionality&lt;sup&gt;&lt;a
    href=&quot;http://raibledesigns.com/rd/entry/appfuse_reduced#footnote1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.
    I think we can all agree that less code == easier maintenance. This theme will continue as we work on future
    releases.
&lt;/p&gt;

&lt;p&gt;Other improvements include migrating all tests to use JUnit4, integrating Spring MVC Test, and configuring the
    surefire plugin to run tests in parallel. I also The &lt;a href=&quot;http://mojo.codehaus.org/build-helper-maven-plugin/&quot;&gt;build-helper-maven-plugin&lt;/a&gt;
    is now used to find open ports for Cargo to run and a lot of testing was done to ensure you can build/test multiple
    AppFuse-derived projects at the same time. Finally, I migrated to the &lt;a href=&quot;http://juplo.de/hibernate4-maven-plugin/&quot;&gt;hibernate4-maven-plugin&lt;/a&gt; and upgraded to Tapestry 5.4.&lt;/p&gt;

&lt;p&gt;In the next version of AppFuse, I plan to remove as
    much XML as possible - moving all of the configuration to Spring&apos;s JavaConfig. We&apos;ll also be moving to Java 8 as a
    minimum. I&apos;m even considering getting rid of all the pom.xml files in favor of another build language that requires
    less code. &lt;/p&gt;
&lt;p&gt;In other words, the upcoming 3.5 release will be the last release that supports Java 7 and uses Spring&apos;s XML for configuration. AppFuse 4.0 will strive for #NoXML.
   &lt;a href=&quot;http://appfuse.org/display/APF/Roadmap&quot;&gt;The project&apos;s roadmap&lt;/a&gt; has more details on additional
    hopes and dreams.&lt;/p&gt;

&lt;p&gt;We&apos;d love to hear your feedback on these change. Do you like the simplification theme? Are you OK with having AppFuse
    as a parent in your projects?
&lt;/p&gt;
&lt;p class=&quot;footnotes&quot; style=&quot;border-top: 1px dotted silver; padding-top: 5px; font-size: .9em&quot;&gt;
    &lt;a name=&quot;footnote1&quot;&gt;&lt;/a&gt;1. For project
    and code stats, see &lt;a href=&quot;https://www.openhub.net/p/appfuse/analyses/latest/languages_summary&quot;&gt;AppFuse on Open
    Hub&lt;/a&gt;.
&lt;/p&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/building_a_rest_api_with</id>
        <title type="html">Building a REST API with JAXB, Spring Boot and Spring Data</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/building_a_rest_api_with"/>
        <published>2014-10-29T05:52:37-06:00</published>
        <updated>2014-10-29T20:25:55-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="jaxb" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rest" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring-boot" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="api" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring-data" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;
&lt;a href=&quot;https://jaxb.java.net/&quot;&gt;&lt;img src=&quot;//raibledesigns.com/repository/images/javaxml-duke.gif&quot; alt=&quot;Project JAXB&quot; width=&quot;100&quot; class=&quot;picture&quot; style=&quot;margin-top: -20px&quot;&gt;&lt;/a&gt;
    If someone asked you to develop a REST API on the JVM, which frameworks would you use? I was recently tasked with such a project.
    My client asked me to implement a REST API to ingest requests from a 3rd party. The project entailed consuming XML
    requests, storing the data in a database, then exposing the data to internal application with a JSON endpoint.
    Finally, it would allow taking in a JSON request and turning it into an XML request back to the 3rd party.
&lt;/p&gt;
&lt;p&gt;
    With the recent &lt;a href=&quot;http://www.infoq.com/news/2014/10/apache-camel-2.14&quot;&gt;release of Apache Camel 2.14&lt;/a&gt; and
    &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel2&quot;&gt;my success using it&lt;/a&gt;, I started by
    copying my Apache Camel / CXF / Spring Boot project and trimming it down to the bare essentials. I whipped together
    a simple &lt;em&gt;Hello World&lt;/em&gt; service using Camel and Spring MVC. I also integrated Swagger into both. Both
    implementations were pretty easy to create (&lt;a href=&quot;http://camel.465427.n5.nabble.com/Camel-s-Swagger-vs-Spring-MVC-Swagger-td5757023.html&quot;&gt;sample code&lt;/a&gt;),
    but I decided to use Spring MVC. My reasons were simple: its REST support was more mature, I knew it well, and
    &lt;a href=&quot;http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/testing.html#spring-mvc-test-framework&quot;&gt;Spring MVC Test&lt;/a&gt; makes it easy to test APIs.
&lt;/p&gt;
&lt;p class=&quot;alert alert-info&quot;&gt;&lt;strong&gt;Camel&apos;s Swagger support without web.xml&lt;/strong&gt;&lt;br/&gt;
    As part of the aforementioned spike, I learned out how to configure Camel&apos;s REST and Swagger support using Spring&apos;s
    JavaConfig and no web.xml. I made this into a sample project and put it on GitHub as
    &lt;a href=&quot;https://github.com/mraible/camel-rest-swagger&quot;&gt;camel-rest-swagger&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
    This article shows how I built a REST API with Java 8, Spring Boot/MVC, JAXB and Spring Data (JPA and REST
    components).
    I stumbled a few times while developing this project, but figured out how to get over all the hurdles. I hope this
    helps the team that&apos;s now maintaining this project (my last day was Friday) and those that are trying to do
    something similar.
&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;
&lt;a href=&quot;https://jaxb.java.net/&quot;&gt;&lt;img src=&quot;//raibledesigns.com/repository/images/javaxml-duke.gif&quot; alt=&quot;Project JAXB&quot; width=&quot;100&quot; class=&quot;picture&quot; style=&quot;margin-top: -20px&quot;&gt;&lt;/a&gt;
    If someone asked you to develop a REST API on the JVM, which frameworks would you use? I was recently tasked with such a project.
    My client asked me to implement a REST API to ingest requests from a 3rd party. The project entailed consuming XML
    requests, storing the data in a database, then exposing the data to internal application with a JSON endpoint.
    Finally, it would allow taking in a JSON request and turning it into an XML request back to the 3rd party.
&lt;/p&gt;
&lt;p&gt;
    With the recent &lt;a href=&quot;http://www.infoq.com/news/2014/10/apache-camel-2.14&quot;&gt;release of Apache Camel 2.14&lt;/a&gt; and
    &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel2&quot;&gt;my success using it&lt;/a&gt;, I started by
    copying my Apache Camel / CXF / Spring Boot project and trimming it down to the bare essentials. I whipped together
    a simple &lt;em&gt;Hello World&lt;/em&gt; service using Camel and Spring MVC. I also integrated Swagger into both. Both
    implementations were pretty easy to create (&lt;a href=&quot;http://camel.465427.n5.nabble.com/Camel-s-Swagger-vs-Spring-MVC-Swagger-td5757023.html&quot;&gt;sample code&lt;/a&gt;),
    but I decided to use Spring MVC. My reasons were simple: its REST support was more mature, I knew it well, and
    &lt;a href=&quot;http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/testing.html#spring-mvc-test-framework&quot;&gt;Spring MVC Test&lt;/a&gt; makes it easy to test APIs.
&lt;/p&gt;
&lt;p class=&quot;alert alert-info&quot;&gt;&lt;strong&gt;Camel&apos;s Swagger support without web.xml&lt;/strong&gt;&lt;br/&gt;
    As part of the aforementioned spike, I learned out how to configure Camel&apos;s REST and Swagger support using Spring&apos;s
    JavaConfig and no web.xml. I made this into a sample project and put it on GitHub as
    &lt;a href=&quot;https://github.com/mraible/camel-rest-swagger&quot;&gt;camel-rest-swagger&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
    This article shows how I built a REST API with Java 8, Spring Boot/MVC, JAXB and Spring Data (JPA and REST
    components).
    I stumbled a few times while developing this project, but figured out how to get over all the hurdles. I hope this
    helps the team that&apos;s now maintaining this project (my last day was Friday) and those that are trying to do
    something similar.
&lt;/p&gt;
&lt;h3 id=&quot;jaxb&quot;&gt;XML to Java with JAXB&lt;/h3&gt;
&lt;p&gt;
    The data we needed to ingest from a 3rd party was based on the &lt;a href=&quot;http://ncpdp.org/&quot;&gt;NCPDP&lt;/a&gt; Standards. As a member,
    we were able to download a number of XSD files, put them in our project and generate Java classes to handle the
    incoming/outgoing requests. I used the &lt;a href=&quot;https://java.net/projects/maven-jaxb2-plugin/pages/Home&quot;&gt;maven-jaxb2-plugin&lt;/a&gt;
    to generate the Java classes.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.jvnet.jaxb2.maven2&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-jaxb2-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.8.3&amp;lt;/version&amp;gt;
    &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;generate&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
            &amp;lt;configuration&amp;gt;
                &amp;lt;args&amp;gt;
                    &amp;lt;arg&amp;gt;-XtoString&amp;lt;/arg&amp;gt;
                    &amp;lt;arg&amp;gt;-Xequals&amp;lt;/arg&amp;gt;
                    &amp;lt;arg&amp;gt;-XhashCode&amp;lt;/arg&amp;gt;
                    &amp;lt;arg&amp;gt;-Xcopyable&amp;lt;/arg&amp;gt;
                &amp;lt;/args&amp;gt;
                &amp;lt;plugins&amp;gt;
                    &amp;lt;plugin&amp;gt;
                        &amp;lt;groupId&amp;gt;org.jvnet.jaxb2_commons&amp;lt;/groupId&amp;gt;
                        &amp;lt;artifactId&amp;gt;jaxb2-basics&amp;lt;/artifactId&amp;gt;
                        &amp;lt;version&amp;gt;0.6.4&amp;lt;/version&amp;gt;
                    &amp;lt;/plugin&amp;gt;
                &amp;lt;/plugins&amp;gt;
                &amp;lt;schemaDirectory&amp;gt;src/main/resources/schemas/ncpdp&amp;lt;/schemaDirectory&amp;gt;
            &amp;lt;/configuration&amp;gt;
        &amp;lt;/execution&amp;gt;
    &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The first error I ran into was about a property already being defined.
&lt;/p&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;
[INFO] --- maven-jaxb2-plugin:0.8.3:generate (default) @ spring-app ---
[ERROR] Error while parsing schema(s).Location [ file:/Users/mraible/dev/spring-app/src/main/resources/schemas/ncpdp/structures.xsd{1811,48}].
com.sun.istack.SAXParseException2; systemId: file:/Users/mraible/dev/spring-app/src/main/resources/schemas/ncpdp/structures.xsd;
    lineNumber: 1811; columnNumber: 48; Property &quot;MultipleTimingModifierAndTimingAndDuration&quot; is already defined.
    Use &amp;lt;jaxb:property&gt; to resolve this conflict.
at com.sun.tools.xjc.ErrorReceiver.error(ErrorReceiver.java:86)
&lt;/pre&gt;
&lt;p&gt;
    I was able to workaround this by upgrading to maven-jaxb2-plugin version 0.9.1. I created a controller and stubbed
    out a response with hard-coded data. I confirmed the incoming XML-to-Java marshalling worked by testing with a
    sample request provided by our 3rd party customer. I started with a &lt;code&gt;curl&lt;/code&gt;
    command, because it was easy to use and could be run by anyone with the file and curl installed.
&lt;/p&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;
curl -X POST -H &apos;Accept: application/xml&apos; -H &apos;Content-type: application/xml&apos; \
--data-binary @sample-request.xml http://localhost:8080/api/message -v
&lt;/pre&gt;
&lt;p&gt;
    This is when I ran into another stumbling block: the response wasn&apos;t getting marshalled back to XML correctly.
    After some research, I found out this was caused by the lack of &lt;code&gt;@XmlRootElement&lt;/code&gt; annotations on my
    generated classes.
    I
    posted a question to Stack Overflow titled &lt;a
        href=&quot;http://stackoverflow.com/questions/26070566/returning-jaxb-generated-elements-from-spring-boot-controller&quot;&gt;
    Returning JAXB-generated elements from Spring Boot Controller&lt;/a&gt;. After banging my head against the wall for a
    couple days, I figured out &lt;a href=&quot;http://stackoverflow.com/a/26124104/65681&quot;&gt;the solution&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
    I created a bindings.xjb file in the same directory as my schemas. This causes JAXB to generate &lt;code&gt;@XmlRootElement&lt;/code&gt;
    on
    classes.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot;?&amp;gt;
&amp;lt;jxb:bindings version=&quot;1.0&quot;
              xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot;
              xmlns:jxb=&quot;http://java.sun.com/xml/ns/jaxb&quot;
              xmlns:xjc=&quot;http://java.sun.com/xml/ns/jaxb/xjc&quot;
              xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
              xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd&quot;&amp;gt;

    &amp;lt;jxb:bindings schemaLocation=&quot;transport.xsd&quot; node=&quot;/xsd:schema&quot;&amp;gt;
        &amp;lt;jxb:globalBindings&amp;gt;
            &amp;lt;xjc:simple/&amp;gt;
        &amp;lt;/jxb:globalBindings&amp;gt;
    &amp;lt;/jxb:bindings&amp;gt;
&amp;lt;/jxb:bindings&amp;gt;
&lt;/pre&gt;
&lt;p&gt;To add namespaces prefixes to the returned XML, I had to modify the maven-jaxb2-plugin to add a couple arguments.
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;arg&amp;gt;-extension&amp;lt;/arg&amp;gt;
&amp;lt;arg&amp;gt;-Xnamespace-prefix&amp;lt;/arg&amp;gt;
&lt;/pre&gt;
&lt;p&gt;And add a dependency:&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.jvnet.jaxb2_commons&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;jaxb2-namespace-prefix&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.1&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Then I modified &lt;code&gt;bindings.xjb&lt;/code&gt; to include the package and prefix settings. I also moved
    &lt;code&gt;&amp;lt;xjc:simple/&amp;gt;&lt;/code&gt; into a global setting. I eventually had to add prefixes for all schemas and their
    packages. &lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot;?&amp;gt;
&amp;lt;bindings version=&quot;2.0&quot; xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot; xmlns=&quot;http://java.sun.com/xml/ns/jaxb&quot;
          xmlns:xjc=&quot;http://java.sun.com/xml/ns/jaxb/xjc&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
          xmlns:namespace=&quot;http://jaxb2-commons.dev.java.net/namespace-prefix&quot;
          xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd
              http://jaxb2-commons.dev.java.net/namespace-prefix http://java.net/projects/jaxb2-commons/sources/svn/content/namespace-prefix/trunk/src/main/resources/prefix-namespace-schema.xsd&quot;&amp;gt;

    &amp;lt;globalBindings&amp;gt;
        &amp;lt;xjc:simple/&amp;gt;
    &amp;lt;/globalBindings&amp;gt;

    &amp;lt;bindings schemaLocation=&quot;transport.xsd&quot; node=&quot;/xsd:schema&quot;&amp;gt;
        &amp;lt;schemaBindings&amp;gt;
            &amp;lt;package name=&quot;org.ncpdp.schema.transport&quot;/&amp;gt;
        &amp;lt;/schemaBindings&amp;gt;
        &amp;lt;bindings&amp;gt;
            &amp;lt;namespace:prefix name=&quot;transport&quot;/&amp;gt;
        &amp;lt;/bindings&amp;gt;
    &amp;lt;/bindings&amp;gt;
&amp;lt;/bindings&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
    I learned how to add prefixes from the &lt;a href=&quot;https://java.net/projects/jaxb2-commons/pages/Namespace-prefix&quot;&gt;namespace-prefix
    plugins page&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;Finally, I customized the code-generation process to generate Joda Time&apos;s
    &lt;a href=&quot;http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTime.html&quot;&gt;DateTime&lt;/a&gt; instead of the
    default &lt;code&gt;XMLGregorianCalendar&lt;/code&gt;. This involved a couple custom XmlAdapters and a couple
    additional lines in &lt;code&gt;bindings.xjb&lt;/code&gt;. You can see the adapters and &lt;code&gt;bindings.xjb&lt;/code&gt; with all
    necessary prefixes
    in &lt;a href=&quot;https://gist.github.com/mraible/abad8d78c1f053ec686b&quot;&gt;this gist&lt;/a&gt;.
    Nicolas Fr&#228;nkel&apos;s &lt;a href=&quot;http://blog.frankel.ch/customize-your-jaxb-bindings&quot;&gt;Customize your JAXB bindings&lt;/a&gt;
    was a great resource for making all this work.
&lt;/p&gt;
&lt;p&gt;I wrote a test to prove that the ingest API worked as desired.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class InitiateRequestControllerTest {

    @Inject
    private InitiateRequestController controller;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }

    @Test
    public void testGetNotAllowedOnMessagesAPI() throws Exception {
        mockMvc.perform(get(&quot;/api/initiate&quot;)
                .accept(MediaType.APPLICATION_XML))
                .andExpect(status().isMethodNotAllowed());
    }

    @Test
    public void testPostPaInitiationRequest() throws Exception {
        String request = new Scanner(new ClassPathResource(&quot;sample-request.xml&quot;).getFile()).useDelimiter(&quot;\\Z&quot;).next();

        mockMvc.perform(post(&quot;/api/initiate&quot;)
                .accept(MediaType.APPLICATION_XML)
                .contentType(MediaType.APPLICATION_XML)
                .content(request))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_XML))
                .andExpect(xpath(&quot;/Message/Header/To&quot;).string(&quot;3rdParty&quot;))
                .andExpect(xpath(&quot;/Message/Header/SenderSoftware/SenderSoftwareDeveloper&quot;).string(&quot;HID&quot;))
                .andExpect(xpath(&quot;/Message/Body/Status/Code&quot;).string(&quot;010&quot;));
    }
}
&lt;/pre&gt;
&lt;h3 id=&quot;spring-data&quot;&gt;Spring Data for JPA and REST&lt;/h3&gt;
&lt;p&gt;
    With JAXB out of the way, I turned to creating an internal API that could be used by another application. Spring
    Data was fresh in my mind after &lt;a href=&quot;http://shop.oreilly.com/product/0636920024767.do&quot;&gt;reading about it&lt;/a&gt; last
    summer. I created classes for entities I wanted to persist, using &lt;a href=&quot;http://projectlombok.org/&quot;&gt;Lombok&apos;s&lt;/a&gt;
    @Data to reduce boilerplate.
&lt;/p&gt;
&lt;p&gt;
    I read the &lt;a href=&quot;https://spring.io/guides/gs/accessing-data-jpa/&quot;&gt;Accessing Data with JPA&lt;/a&gt; guide, created
    a couple repositories and wrote some tests to prove they worked. I ran into an issue trying to persist
    Joda&apos;s DateTime and found &lt;a href=&quot;http://jadira.sourceforge.net/usertype-userguide.html&quot;&gt;Jadira&lt;/a&gt; provided a
    solution.
&lt;/p&gt;
&lt;p&gt;
    I added its usertype.core as a dependency to my pom.xml:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.jadira.usertype&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;usertype.core&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.2.0.GA&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;... and annotated DateTime variables accordingly.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Column(name = &quot;last_modified&quot;, nullable = false)
@Type(type=&quot;org.jadira.usertype.dateandtime.joda.PersistentDateTime&quot;)
private DateTime lastModified;
&lt;/pre&gt;
&lt;p&gt;With JPA working, I turned to exposing REST endpoints. I used &lt;a
        href=&quot;https://spring.io/guides/gs/accessing-data-rest/&quot;&gt;Accessing JPA Data with REST&lt;/a&gt;
    as a guide and was looking at JSON in my browser in a matter of minutes. I was surprised to see a &quot;profile&quot; service
    listed next to mine, and posted &lt;a href=&quot;https://github.com/spring-projects/spring-boot/issues/1718&quot;&gt;a question&lt;/a&gt;
    to the Spring Boot team. Oliver Gierke &lt;a
            href=&quot;https://github.com/spring-projects/spring-boot/issues/1718#issuecomment-59329942&quot;&gt;provided an
        excellent answer&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;swagger&quot;&gt;Swagger&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/martypitt/swagger-springmvc&quot;&gt;Spring MVC&apos;s integration for Swagger&lt;/a&gt; has greatly
    improved
    since I &lt;a href=&quot;http://raibledesigns.com/rd/entry/documenting_your_spring_api_with&quot;&gt;last wrote about it&lt;/a&gt;.
    Now you can enable it with a &lt;code&gt;@EnableSwagger&lt;/code&gt; annotation. Below
    is the &lt;code&gt;SwaggerConfig&lt;/code&gt; class I used to configure Swagger and read properties from
    &lt;code&gt;application.yml&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Configuration
@EnableSwagger
public class SwaggerConfig implements EnvironmentAware {
	public static final String DEFAULT_INCLUDE_PATTERN = &quot;/api/.*&quot;;

	private RelaxedPropertyResolver propertyResolver;

	@Override
	public void setEnvironment(Environment environment) {
		this.propertyResolver = new RelaxedPropertyResolver(environment, &quot;swagger.&quot;);
	}

	/**
	 * Swagger Spring MVC configuration
	 */
	@Bean
	public SwaggerSpringMvcPlugin swaggerSpringMvcPlugin(SpringSwaggerConfig springSwaggerConfig) {
		return new SwaggerSpringMvcPlugin(springSwaggerConfig)
				.apiInfo(apiInfo())
				.genericModelSubstitutes(ResponseEntity.class)
				.includePatterns(DEFAULT_INCLUDE_PATTERN);
	}

	/**
	 * API Info as it appears on the swagger-ui page
	 */
	private ApiInfo apiInfo() {
		return new ApiInfo(
				propertyResolver.getProperty(&quot;title&quot;),
				propertyResolver.getProperty(&quot;description&quot;),
				propertyResolver.getProperty(&quot;termsOfServiceUrl&quot;),
				propertyResolver.getProperty(&quot;contact&quot;),
				propertyResolver.getProperty(&quot;license&quot;),
				propertyResolver.getProperty(&quot;licenseUrl&quot;));
	}
}
&lt;/pre&gt;
&lt;p&gt;After getting Swagger to work, I discovered that endpoints published with &lt;code&gt;@RepositoryRestResource&lt;/code&gt; aren&apos;t
    picked up by Swagger. There is an &lt;a href=&quot;https://github.com/martypitt/swagger-springmvc/issues/238&quot;&gt;open issue&lt;/a&gt;
    for Spring Data support in the swagger-springmvc project.&lt;/p&gt;

&lt;h3 id=&quot;liquibase&quot;&gt;Liquibase Integration&lt;/h3&gt;
&lt;p&gt;
    I configured this project to use H2 in development and PostgreSQL in production. I used Spring profiles to do this
    and copied XML/YAML (for Maven and application*.yml files) from a previously created &lt;a href=&quot;https://jhipster.github.io&quot;&gt;JHipster&lt;/a&gt;
    project.
&lt;/p&gt;
&lt;p&gt;Next, I needed to create a database. I decided to use &lt;a href=&quot;http://www.liquibase.org/&quot;&gt;Liquibase&lt;/a&gt; to
    create tables, rather than Hibernate&apos;s schema-export. I chose Liquibase
    over &lt;a href=&quot;http://flywaydb.org/&quot;&gt;Flyway&lt;/a&gt; based of discussions in the &lt;a
            href=&quot;https://github.com/jhipster/generator-jhipster/issues/588&quot;&gt;JHipster project&lt;/a&gt;. To use Liquibase with
    Spring Boot is dead simple: add the following dependency to pom.xml, then place changelog files in
    &lt;code&gt;src/main/resources/db/changelog&lt;/code&gt;.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.liquibase&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;liquibase-core&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;&lt;p&gt;
    I started by using Hibernate&apos;s schema-export and changing &lt;code&gt;hibernate.ddl-auto&lt;/code&gt; to &quot;create-drop&quot; in
    &lt;code&gt;application-dev.yml&lt;/code&gt;. I also commented out the liquibase-core dependency.
    Then I setup a PostgreSQL database and started the app with &quot;mvn spring-boot:run -Pprod&quot;.
&lt;/p&gt;
&lt;p&gt;I generated the liquibase changelog from an existing schema using the following command (after
    &lt;a href=&quot;http://www.liquibase.org/download/&quot;&gt;downloading&lt;/a&gt; and installing Liquibase). &lt;/p&gt;
&lt;pre&gt;
liquibase --driver=org.postgresql.Driver --classpath=&quot;/Users/mraible/.m2/repository/org/postgresql/postgresql/9.3-1102-jdbc41/postgresql-9.3-1102-jdbc41.jar:/Users/mraible/snakeyaml-1.11.jar&quot; --changeLogFile=/Users/mraible/dev/spring-app/src/main/resources/db/changelog/db.changelog-02.yaml --url=&quot;jdbc:postgresql://localhost:5432/mydb&quot; --username=user --password=pass generateChangeLog
&lt;/pre&gt;

&lt;p&gt;I did find one bug - the generateChangeLog command &lt;a href=&quot;https://liquibase.jira.com/browse/CORE-2056&quot;&gt;generates
    too many constraints in version 3.2.2&lt;/a&gt;. I was able to fix this by manually editing the generated YAML file.
&lt;/p&gt;
&lt;div class=&quot;alert alert-success&quot;&gt;&lt;p style=&quot;margin-top: 5px&quot;&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you want to drop all tables in your database to verify
    Liquibase creation is working in PostgeSQL, run the following commands:&lt;/p&gt;
&lt;pre style=&quot;margin-bottom: 5px&quot;&gt;psql -d mydb
drop schema public cascade;
create schema public;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;After writing minimal code for Spring Data and configuring Liquibase to create tables/relationships, I relaxed
    a bit, documented how everything worked and added a &lt;a href=&quot;https://github.com/isrsal/spring-mvc-logger&quot;&gt;LoggingFilter&lt;/a&gt;.
    The LoggingFilter was handy for viewing API requests and responses.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
@Bean
public FilterRegistrationBean loggingFilter() {
    LoggingFilter filter = new LoggingFilter();
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(filter);
    registrationBean.setUrlPatterns(Arrays.asList(&quot;/api/*&quot;));
    return registrationBean;
}
&lt;/pre&gt;
&lt;h3 id=&quot;resttemplate&quot;&gt;Accessing API with RestTemplate&lt;/h3&gt;
&lt;p&gt;The final step I needed to do was figure out how to access my new and fancy API with
    &lt;a href=&quot;http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html&quot;&gt;RestTemplate&lt;/a&gt;.
    At first, I thought it would be easy. Then I realized that Spring Data produces a
    &lt;a href=&quot;http://stateless.co/hal_specification.html&quot;&gt;HAL&lt;/a&gt;-compliant API, so its content is embedded inside an
    &quot;_embedded&quot; JSON key.
&lt;/p&gt;
&lt;p&gt;After much trial and error, I discovered I needed to create a &lt;code&gt;RestTemplate&lt;/code&gt; with HAL and Joda-Time
    awareness.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Bean
public RestTemplate restTemplate() {
	ObjectMapper mapper = new ObjectMapper();
	mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
	mapper.registerModule(new Jackson2HalModule());
	mapper.registerModule(new JodaModule());

	MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
	converter.setSupportedMediaTypes(MediaType.parseMediaTypes(&quot;application/hal+json&quot;));
	converter.setObjectMapper(mapper);
	StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
	stringConverter.setSupportedMediaTypes(MediaType.parseMediaTypes(&quot;application/xml&quot;));

	List&amp;lt;HttpMessageConverter&amp;lt;?&amp;gt;&amp;gt; converters = new ArrayList&amp;lt;&amp;gt;();
	converters.add(converter);
	converters.add(stringConverter);

	return new RestTemplate(converters);
}
&lt;/pre&gt;
&lt;p&gt;
    The &lt;code&gt;JodaModule&lt;/code&gt; was provided by the following dependency:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.fasterxml.jackson.datatype&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jackson-datatype-joda&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;With the configuration complete, I was able to write a &lt;code&gt;MessagesApiITest&lt;/code&gt; integration test that posts a
    request
    and retrieves it using the API. The API was secured using basic authentication, so it took me a bit to figure out
    how
    to make that work with RestTemplate. Willie Wheeler&apos;s
    &lt;a href=&quot;http://springinpractice.com/2013/10/02/quick-tip-basic-authentication-with-spring-resttemplate&quot;&gt;Basic
        Authentication With Spring RestTemplate&lt;/a&gt; was a big help.&lt;/p&gt;

&lt;pre class=&quot;brush: java&quot;&gt;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = IntegrationTestConfig.class)
public class MessagesApiITest {
    private final static Log log = LogFactory.getLog(MessagesApiITest.class);
    @Value(&quot;http://${app.host}/api/initiate&quot;)
    private String initiateAPI;
    @Value(&quot;http://${app.host}/api/messages&quot;)
    private String messagesAPI;
    @Value(&quot;${app.host}&quot;)
    private String host;
    @Inject
    private RestTemplate restTemplate;

    @Before
    public void setup() throws Exception {
        String request = new Scanner(new ClassPathResource(&quot;sample-request.xml&quot;).getFile()).useDelimiter(&quot;\\Z&quot;).next();

        ResponseEntity&amp;lt;org.ncpdp.schema.transport.Message&amp;gt; response = restTemplate.exchange(getTestUrl(initiateAPI),
                HttpMethod.POST, getBasicAuthHeaders(request), org.ncpdp.schema.transport.Message.class,
                Collections.emptyMap());
        assertEquals(HttpStatus.OK, response.getStatusCode());
    }

    @Test
    public void testGetMessages() {
        HttpEntity&amp;lt;String&amp;gt; request = getBasicAuthHeaders(null);

        ResponseEntity&amp;lt;PagedResources&amp;lt;Message&amp;gt;&amp;gt; result = restTemplate.exchange(getTestUrl(messagesAPI), HttpMethod.GET,
                request, new ParameterizedTypeReference&amp;lt;PagedResources&amp;lt;Message&amp;gt;&amp;gt;() {});
        HttpStatus status = result.getStatusCode();
        Collection&amp;lt;Message&amp;gt; messages = result.getBody().getContent();

        log.debug(&quot;messages found: &quot; + messages.size());
        assertEquals(HttpStatus.OK, status);
        for (Message message : messages) {
            log.debug(&quot;message.id: &quot; + message.getId());
            log.debug(&quot;message.dateCreated: &quot; + message.getDateCreated());
        }
    }

    private HttpEntity&amp;lt;String&amp;gt; getBasicAuthHeaders(String body) {
        String plainCreds = &quot;user:pass&quot;;
        byte&amp;#91;&amp;#93; plainCredsBytes = plainCreds.getBytes();
        byte&amp;#91;&amp;#93; base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
        String base64Creds = new String(base64CredsBytes);

        HttpHeaders headers = new HttpHeaders();
        headers.add(&quot;Authorization&quot;, &quot;Basic &quot; + base64Creds);
        headers.add(&quot;Content-type&quot;, &quot;application/xml&quot;);

        if (body == null) {
            return new HttpEntity&amp;lt;&amp;gt;(headers);
        } else {
            return new HttpEntity&amp;lt;&amp;gt;(body, headers);
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;To get Spring Data to populate the message id, I created a custom &lt;code&gt;RestConfig&lt;/code&gt; class to expose it. I learned how to do this from &lt;a href=&quot;http://tommyziegler.com/how-to-expose-the-resourceid-with-spring-data-rest/&quot;&gt;Tommy Ziegler&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
/**
 * Used to expose ids for resources.
 */
@Configuration
public class RestConfig extends RepositoryRestMvcConfiguration {

    @Override
    protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(Message.class);
        config.setBaseUri(&quot;/api&quot;);
    }
}

&lt;/pre&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;
    This article explains how I built a REST API using JAXB, Spring Boot, Spring Data and Liquibase.
    It was relatively easy to build, but required some tricks to access it with Spring&apos;s RestTemplate. Figuring out
    how to customize JAXB&apos;s code generation was also essential to make things work.
&lt;/p&gt;&lt;p&gt;
    I started developing the project with Spring Boot 1.1.7, but upgraded to 1.2.0.M2 after I found it supported
    Log4j2 and configuring Spring Data REST&apos;s base URI in application.yml. When I handed the project off to my client
    last week, it was using 1.2.0.BUILD-SNAPSHOT because of a
    &lt;a href=&quot;https://github.com/spring-projects/spring-boot/issues/1719&quot;&gt;bug when running in Tomcat&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;This was an enjoyable project to work on. I especially liked how easy Spring Data makes it to expose JPA
    entities in an API. Spring Boot made things easy to configure once again and Liquibase seems like a nice
    tool for database migrations.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If someone asked me to develop a REST API on the JVM, which frameworks would I use?&lt;/em&gt; Spring Boot, Spring Data, Jackson, Joda-Time, Lombok and Liquibase. These frameworks worked really well for me on this particular project.&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/getting_started_with_jhipster_on</id>
        <title type="html">Getting Started with JHipster on OS X</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/getting_started_with_jhipster_on"/>
        <published>2014-09-08T11:30:33-06:00</published>
        <updated>2014-10-30T14:30:12-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="jhipster" scheme="http://roller.apache.org/ns/tags/" />
        <category term="mac" scheme="http://roller.apache.org/ns/tags/" />
        <category term="nvm" scheme="http://roller.apache.org/ns/tags/" />
        <category term="docker" scheme="http://roller.apache.org/ns/tags/" />
        <category term="yeoman" scheme="http://roller.apache.org/ns/tags/" />
        <category term="npm" scheme="http://roller.apache.org/ns/tags/" />
        <category term="node" scheme="http://roller.apache.org/ns/tags/" />
        <category term="osx" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;
&lt;a href=&quot;http://jhipster.github.io/&quot;&gt;&lt;img src=&quot;http://jhipster.github.io/images/logo-jhipster2x.png&quot; class=&quot;picture&quot; width=&quot;187&quot;&gt;&lt;/a&gt;
    Last week I was tasked with developing a quick prototype that used AngularJS for its client and Spring MVC
    for its server. A colleague developed the same application using Backbone.js and Spring MVC.
    At first, I considered using my &lt;a href=&quot;https://github.com/mraible/boot-ionic&quot;&gt;boot-ionic&lt;/a&gt;
    project as a starting point. Then I realized I didn&apos;t need to develop a native mobile app, but rather a
    responsive web app.&lt;/p&gt;

&lt;p&gt;
    My colleague mentioned he was going to use &lt;a href=&quot;http://resthub.org/&quot;&gt;RESThub&lt;/a&gt; as his starting point, so I
    figured I&apos;d use &lt;a href=&quot;http://jhipster.github.io/&quot;&gt;JHipster&lt;/a&gt; as mine. We allocated a day to get our
    environments setup with the tools we needed, then timeboxed our first feature spike to four hours.
&lt;/p&gt;

&lt;p&gt;
    My first experience with JHipster failed the &lt;em&gt;10-minute test&lt;/em&gt;. I spent a lot of time
    flailing about with various &quot;npm&quot; and &quot;yo&quot; commands, getting permissions issues along the way. After getting
    thinks to work with some &lt;em&gt;sudo&lt;/em&gt; action, I figured I&apos;d try its &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt;
    development environment. This experience was no better.
&lt;/p&gt;

&lt;p&gt;
    JHipster seems like a nice project, so I figured I&apos;d try to find the causes of my issues. This article is designed
    to save you the pain I had. If you&apos;d rather just see the steps to get up and running quickly, skip to the
    &lt;a href=&quot;http://raibledesigns.com/rd/entry/getting_started_with_jhipster_on#summary&quot;&gt;summary&lt;/a&gt;.
&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;
&lt;a href=&quot;http://jhipster.github.io/&quot;&gt;&lt;img src=&quot;http://jhipster.github.io/images/logo-jhipster2x.png&quot; class=&quot;picture&quot; width=&quot;187&quot;&gt;&lt;/a&gt;
    Last week I was tasked with developing a quick prototype that used AngularJS for its client and Spring MVC
    for its server. A colleague developed the same application using Backbone.js and Spring MVC.
    At first, I considered using my &lt;a href=&quot;https://github.com/mraible/boot-ionic&quot;&gt;boot-ionic&lt;/a&gt;
    project as a starting point. Then I realized I didn&apos;t need to develop a native mobile app, but rather a
    responsive web app.&lt;/p&gt;

&lt;p&gt;
    My colleague mentioned he was going to use &lt;a href=&quot;http://resthub.org/&quot;&gt;RESThub&lt;/a&gt; as his starting point, so I
    figured I&apos;d use &lt;a href=&quot;http://jhipster.github.io/&quot;&gt;JHipster&lt;/a&gt; as mine. We allocated a day to get our
    environments setup with the tools we needed, then timeboxed our first feature spike to four hours.
&lt;/p&gt;

&lt;p&gt;
    My first experience with JHipster failed the &lt;em&gt;10-minute test&lt;/em&gt;. I spent a lot of time
    flailing about with various &quot;npm&quot; and &quot;yo&quot; commands, getting permissions issues along the way. After getting
    thinks to work with some &lt;em&gt;sudo&lt;/em&gt; action, I figured I&apos;d try its &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt;
    development environment. This experience was no better.
&lt;/p&gt;

&lt;p&gt;
    JHipster seems like a nice project, so I figured I&apos;d try to find the causes of my issues. This article is designed
    to save you the pain I had. If you&apos;d rather just see the steps to get up and running quickly, skip to the
    &lt;a href=&quot;http://raibledesigns.com/rd/entry/getting_started_with_jhipster_on#summary&quot;&gt;summary&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
    The &quot;npm&quot; and &quot;yo&quot; issues I had seemed to be caused by a bad node/npm installation. To fix this, I
    &lt;a href=&quot;http://stackoverflow.com/questions/11177954/how-do-i-completely-uninstall-node-js-and-reinstall-from-beginning-mac-os-x&quot;&gt;removed
        node&lt;/a&gt; and installed &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt;. Here&apos;s the commands I needed to
    remove node and npm:
&lt;/p&gt;
&lt;pre&gt;
sudo rm -rf /usr/local/lib/node_modules
sudo rm -rf /usr/local/include/node
sudo rm /usr/local/bin/node

sudo rm -rf /usr/local/bin/npm
sudo rm /usr/local/share/man/man1/node.1
sudo rm -rf /usr/local/lib/dtrace/node.d
sudo rm -rf ~/.npm
&lt;/pre&gt;
&lt;p&gt;Next, I ran &quot;brew doctor&quot; to make sure Homebrew was still happy. It told me some things were broken:&lt;/p&gt;
&lt;pre&gt;
$ brew doctor
Warning: Broken symlinks were found. Remove them with `brew prune`:
  /usr/local/bin/yo
  /usr/local/bin/ionic
  /usr/local/bin/grunt
  /usr/local/bin/bower
&lt;/pre&gt;
&lt;p&gt;I ran &lt;code&gt;brew update &amp;&amp; brew prune&lt;/code&gt;, followed by &lt;code&gt;brew install nvm&lt;/code&gt;. Next, I added the following
    to my ~/.profile:&lt;/p&gt;
&lt;pre&gt;
source $(brew --prefix nvm)/nvm.sh
&lt;/pre&gt;
&lt;p&gt;To install the latest version of node, I ran the commands below and set the latest version as the default:&lt;/p&gt;
&lt;pre&gt;
nvm ls-remote
nvm install v0.11.13
nvm alias default v0.11.13
&lt;/pre&gt;
&lt;p&gt;
    Once I had a fresh version of Node.js, I was able to run JHipster&apos;s &lt;a
        href=&quot;http://jhipster.github.io/installation.html&quot;&gt;local installation&lt;/a&gt;
    instructions.
&lt;/p&gt;
&lt;pre&gt;
npm install -g yo
npm install -g generator-jhipster
&lt;/pre&gt;
&lt;p&gt;Then I created my project:&lt;/p&gt;
&lt;pre&gt;yo jhipster&lt;/pre&gt;
&lt;p&gt;
    I was disappointed to find this created all the project files in my current directory, rather than in a
    subdirectory. I&apos;d recommend you do the following instead:
&lt;/p&gt;
&lt;pre&gt;
mkdir ~/projectname &amp;&amp; cd ~/projectname &amp;&amp; yo jhipster
&lt;/pre&gt;
&lt;p&gt;Before creating your project, JHipster asks you a number of questions. To see what they are, see its documentation on
    &lt;a href=&quot;http://jhipster.github.io/creating_an_app.html&quot;&gt;creating an application&lt;/a&gt;. Two things to be aware of:
&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Hot reloading Java code doesn&apos;t work well (yet) with Java 8&lt;/li&gt;
    &lt;li&gt;Its &lt;a href=&quot;https://github.com/jhipster/generator-jhipster/issues/490&quot;&gt;OAuth2 implementation doesn&apos;t work with
        WebSockets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, I&apos;d recommend using Java 7 + (cookie-based authentication with websockets) or (oauth2 authentication
    w/o websockets).&lt;/p&gt;

&lt;p&gt;After creating my project, I was able to run it using &quot;mvn spring-boot:run&quot; and view it at &lt;a
        href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt;. To get hot-reloading for the client, I ran &quot;grunt
    server&quot;
    and opened my browser to &lt;a href=&quot;http://localhost:9000&quot;&gt;http://localhost:9000&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;a name=&quot;docker&quot;&gt;&lt;/a&gt;JHipster + Docker on OS X&lt;/h3&gt;

&lt;p&gt;I had no luck getting the Docker instructions to work initially. I spent a couple hours on it, then gave up.
    A couple of days ago, I decided to give it another good ol&apos; &lt;em&gt;college-try&lt;/em&gt;. To make sure I figured out
    everything
    from scratch, I started by
    &lt;a href=&quot;http://therealmarv.com/blog/how-to-fully-uninstall-the-offical-docker-os-x-installation/&quot;&gt;removing
        Docker&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;I re-installed Docker and pulled the JHipster image using the following:&lt;/p&gt;
&lt;pre&gt;
sudo docker pull jdubois/jhipster-docker
&lt;/pre&gt;
&lt;p&gt;The error I got from this was the following:&lt;/p&gt;
&lt;pre&gt;
2014/09/05 19:43:38 Post http:///var/run/docker.sock/images/create?fromImage=jdubois%2Fjhipster-docker&amp;tag=:
dial unix /var/run/docker.sock: no such file or directory
&lt;/pre&gt;
&lt;p&gt;After doing some research, I learned I needed to run &lt;code&gt;boot2docker init&lt;/code&gt; first. Next I ran &lt;code&gt;boot2docker
    up&lt;/code&gt; to start the Docker daemon.
    Then I copied/pasted &quot;export DOCKER_HOST=tcp://192.168.59.103:2375&quot; into my console and tried to run &lt;code&gt;docker
        pull&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;It failed with the same error. The solution was simpler than you might think: don&apos;t use &lt;code&gt;sudo&lt;/code&gt;.
&lt;/p&gt;

&lt;pre&gt;
$ docker pull jdubois/jhipster-docker
Pulling repository jdubois/jhipster-docker
01bdc74025db: Pulling dependent layers
511136ea3c5a: Download complete
...
&lt;/pre&gt;
&lt;p&gt;
    The next command that JHipster&apos;s documentation recommends is to run the Docker image, forward ports and share
    folders. When you run it, the terminal seems to hang and trying to ssh into it doesn&apos;t work. Others have
    &lt;a href=&quot;http://stackoverflow.com/questions/25559542/docker-hangs-when-starting-jdubois-jhipster-container-in-os-x/25582833&quot;&gt;recently
        reported a similar issue&lt;/a&gt;. I discovered the hanging is caused by a missing &quot;-d&quot; parameter and ssh doesn&apos;t
    work because you need to &lt;a href=&quot;http://stackoverflow.com/a/23021012/65681&quot;&gt;
    add a portmap to the VM to expose the port to your host&lt;/a&gt;. You can fix this by running the following:
&lt;/p&gt;
&lt;pre&gt;
boot2docker down
VBoxManage modifyvm &quot;boot2docker-vm&quot; --natpf1 &quot;containerssh,tcp,,4022,,4022&quot;
VBoxManage modifyvm &quot;boot2docker-vm&quot; --natpf1 &quot;containertomcat,tcp,,8080,,8080&quot;
VBoxManage modifyvm &quot;boot2docker-vm&quot; --natpf1 &quot;containergruntserver,tcp,,9000,,9000&quot;
VBoxManage modifyvm &quot;boot2docker-vm&quot; --natpf1 &quot;containergruntreload,tcp,,35729,,35729&quot;
boot2docker start
&lt;/pre&gt;
&lt;p&gt;After making these changes, I was able to start the image and ssh into it.&lt;/p&gt;
&lt;pre&gt;
docker run -d -v ~/jhipster:/jhipster -p 8080:8080 -p 9000:9000 -p 35729:35729 -p 4022:22 -t jdubois/jhipster-docker
ssh -p 4022 jhipster@localhost
&lt;/pre&gt;
&lt;p&gt;I tried creating a new project within the VM (&lt;code&gt;cd /jhipster &amp;&amp; yo jhipster&lt;/code&gt;), but it failed with the
    following error:&lt;/p&gt;
&lt;pre&gt;
/usr/lib/node_modules/generator-jhipster/node_modules/yeoman-generator/node_modules/mkdirp/index.js:89
                    throw err0;
                          ^
Error: EACCES, permission denied &apos;/jhipster/src&apos;
&lt;/pre&gt;
&lt;p&gt;The fix was giving the &quot;jhipster&quot; user ownership of the directory.&lt;/p&gt;
&lt;pre&gt;
sudo chown jhipster /jhipster
&lt;/pre&gt;
&lt;p&gt;After doing this, I was able to generate an app and run it using &quot;mvn spring-boot:run&quot; and access it from my Mac at
    &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt;. I was also able to run &quot;grunt server&quot; and see it at
    &lt;a href=&quot;http://localhost:9000&quot;&gt;http://localhost:9000&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;However, I was puzzled to see that there was nothing in my ~/jhipster directory. After doing some searching, I
    found that the &lt;a href=&quot;https://github.com/docker/docker/issues/4023&quot;&gt;docker run -v /host/path:/container/path
        doesn&apos;t work on OS X&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;David Gageot&apos;s &lt;a href=&quot;http://blog.javabien.net/2014/06/05/a-better-boot2docker-on-osx/&quot;&gt;A Better Boot2Docker on OSX&lt;/a&gt;
led me to &lt;a href=&quot;https://github.com/SvenDowideit/dockerfiles/tree/master/samba&quot;&gt;svendowideit/samba&lt;/a&gt;, which solved this problem.
The specifics are documented in boot2docker&apos;s &lt;a href=&quot;https://github.com/boot2docker/boot2docker#folder-sharing&quot;&gt;folder
        sharing&lt;/a&gt; section.
&lt;/p&gt;
&lt;p&gt;I shutdown my docker container by running &quot;docker ps&quot;, grabbing the first two characters of the id and then running:
    &lt;/p&gt;
&lt;pre&gt;
docker stop [2chars]
&lt;/pre&gt;
&lt;p&gt;
    I started the JHipster container without the -v parameter, used &quot;docker ps&quot; to find its name
    (&lt;em&gt;backstabbing_galileo&lt;/em&gt; in this case), then used that to add samba support.
&lt;/p&gt;
&lt;pre&gt;
docker run -d -p 8080:8080 -p 9000:9000 -p 35729:35729 -p 4022:22 -t jdubois/jhipster-docker
docker run --rm -v /usr/local/bin/docker:/docker -v /var/run/docker.sock:/docker.sock svendowideit/samba backstabbing_galileo
&lt;/pre&gt;
&lt;p&gt;Then I was able to connect using Finder &gt; Go &gt; Connect to Server, using the following for the server address:
&lt;/p&gt;
&lt;pre&gt;cifs://192.168.59.103/jhipster&lt;/pre&gt;
&lt;p&gt;To make this volume appear in my regular development area, I created a symlink:&lt;/p&gt;
&lt;pre&gt;ln -s /Volumes/jhipster ~/dev/jhipster&lt;/pre&gt;
&lt;p&gt;After doing this, all the files
were marked as read-only. To fix, I ran &quot;chmod -R 777 .&quot; in the directory on the server. I noticed that this also worked
    if I ran it from my Mac&apos;s terminal, but it took quite a while to traverse all the files. I noticed a similar delay
    when loading the project into IntelliJ.&lt;/p&gt;
&lt;h3&gt;&lt;a name=&quot;summary&quot;&gt;&lt;/a&gt;Summary&lt;/h3&gt;
&lt;p&gt;Phew! That&apos;s a lot of information that can be condensed down into four JHipster + Docker on OS X tips.&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Make sure your npm installation doesn&apos;t require sudo rights. If it does, reinstall using nvm.&lt;/li&gt;
    &lt;li&gt;Add portmaps to your VM to expose ports 4022, 8080, 9000 and 35729 to your host.&lt;/li&gt;
    &lt;li&gt;Change ownership on the /jhipster in the Docker image: sudo chown jhipster /jhipster.&lt;/li&gt;
    &lt;li&gt;Use svendowideit/samba to share your VM&apos;s directories with OS X.&lt;/li&gt;
&lt;/ol&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/documenting_your_spring_api_with</id>
        <title type="html">Documenting your Spring API with Swagger</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/documenting_your_spring_api_with"/>
        <published>2014-03-25T13:07:18-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="swagger" scheme="http://roller.apache.org/ns/tags/" />
        <category term="swagger-springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;
    Over the last several months, I&apos;ve been developing a &lt;a href=&quot;http://www.infoq.com/articles/webber-rest-workflow&quot;&gt;
    REST&lt;/a&gt; API using &lt;a href=&quot;http://projects.spring.io/spring-boot/&quot;&gt;Spring Boot&lt;/a&gt;.
    My client hired an outside company
    to develop a native iOS app, and my development team was responsible for developing its API. Our main task involved
    integrating with &lt;a href=&quot;http://www.epic.com/&quot;&gt;Epic&lt;/a&gt;, a popular software system used in Health care. We also
    developed a &lt;a href=&quot;https://www.atlassian.com/software/crowd/overview&quot;&gt;Crowd&lt;/a&gt;-backed authentication system,
    based loosely on &lt;a href=&quot;https://github.com/philipsorst/angular-rest-springsecurity&quot;&gt;Philip Sorst&apos;s Angular
    REST Security&lt;/a&gt;.

&lt;/p&gt;

&lt;p&gt;To document our API, we used &lt;a href=&quot;https://github.com/martypitt/swagger-springmvc&quot;&gt;Spring MVC integration for
    Swagger&lt;/a&gt; (a.k.a. swagger-springmvc). I briefly looked into &lt;a
        href=&quot;https://github.com/wkennedy/swagger4spring-web&quot;&gt;swagger4spring-web&lt;/a&gt;,
    but gave up quickly when it didn&apos;t recognize Spring&apos;s @RestController. We started with swagger-springmvc 0.6.5 and
    found it fairly easy to integrate. Unfortunately, it didn&apos;t allow us to annotate our model objects and tell clients
    which fields were required. We were quite pleased when a new version (0.8.2) was released that supports Swagger 1.3
    and its @ApiModelProperty.
&lt;/p&gt;
&lt;blockquote class=&quot;quote&quot;&gt;
    &lt;strong&gt;What is Swagger?&lt;/strong&gt;&lt;br/&gt;
    The goal of &lt;a href=&quot;https://helloreverb.com/developers/swagger&quot;&gt;Swagger&lt;/a&gt; is to define a standard, language-agnostic interface to REST APIs which allows both humans and
    computers to discover and understand the capabilities of the service without access to source code, documentation,
    or through network traffic inspection.
&lt;/blockquote&gt;
&lt;p&gt;
    To demonstrate how Swagger works, I integrated it into Josh Long&apos;s
    &lt;a href=&quot;https://github.com/joshlong/boot-examples/tree/master/x-auth-security&quot;&gt;x-auth-security&lt;/a&gt; project. If you
    have a Boot-powered project, you should be able to use the same steps.
&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;
    Over the last several months, I&apos;ve been developing a &lt;a href=&quot;http://www.infoq.com/articles/webber-rest-workflow&quot;&gt;
    REST&lt;/a&gt; API using &lt;a href=&quot;http://projects.spring.io/spring-boot/&quot;&gt;Spring Boot&lt;/a&gt;.
    My client hired an outside company
    to develop a native iOS app, and my development team was responsible for developing its API. Our main task involved
    integrating with &lt;a href=&quot;http://www.epic.com/&quot;&gt;Epic&lt;/a&gt;, a popular software system used in Health care. We also
    developed a &lt;a href=&quot;https://www.atlassian.com/software/crowd/overview&quot;&gt;Crowd&lt;/a&gt;-backed authentication system,
    based loosely on &lt;a href=&quot;https://github.com/philipsorst/angular-rest-springsecurity&quot;&gt;Philip Sorst&apos;s Angular
    REST Security&lt;/a&gt;.

&lt;/p&gt;

&lt;p&gt;To document our API, we used &lt;a href=&quot;https://github.com/martypitt/swagger-springmvc&quot;&gt;Spring MVC integration for
    Swagger&lt;/a&gt; (a.k.a. swagger-springmvc). I briefly looked into &lt;a
        href=&quot;https://github.com/wkennedy/swagger4spring-web&quot;&gt;swagger4spring-web&lt;/a&gt;,
    but gave up quickly when it didn&apos;t recognize Spring&apos;s @RestController. We started with swagger-springmvc 0.6.5 and
    found it fairly easy to integrate. Unfortunately, it didn&apos;t allow us to annotate our model objects and tell clients
    which fields were required. We were quite pleased when a new version (0.8.2) was released that supports Swagger 1.3
    and its @ApiModelProperty.
&lt;/p&gt;
&lt;blockquote class=&quot;quote&quot;&gt;
    &lt;strong&gt;What is Swagger?&lt;/strong&gt;&lt;br/&gt;
    The goal of &lt;a href=&quot;https://helloreverb.com/developers/swagger&quot;&gt;Swagger&lt;/a&gt; is to define a standard, language-agnostic interface to REST APIs which allows both humans and
    computers to discover and understand the capabilities of the service without access to source code, documentation,
    or through network traffic inspection.
&lt;/blockquote&gt;
&lt;p&gt;
    To demonstrate how Swagger works, I integrated it into Josh Long&apos;s
    &lt;a href=&quot;https://github.com/joshlong/boot-examples/tree/master/x-auth-security&quot;&gt;x-auth-security&lt;/a&gt; project. If you
    have a Boot-powered project, you should be able to use the same steps.
&lt;/p&gt;

&lt;p&gt;
    &lt;strong&gt;1. Add swagger-springmvc dependency to your project.&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.mangofactory&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;swagger-springmvc&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.8.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Note: on my client&apos;s project, we had to exclude &quot;org.slf4j:slf4j-log4j12&quot; and add &quot;jackson-module-scala_2.10:2.3.1&quot;
    as a dependency. I did not need to do either of these in this project.
&lt;/p&gt;

&lt;p&gt;
    &lt;strong&gt;2. Add a SwaggerConfig class to configure Swagger.&lt;/strong&gt;

&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/martypitt/swagger-springmvc&quot;&gt;swagger-springmvc documentation&lt;/a&gt; has an example of
    this
    with a bit more XML.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package example.config;

import com.mangofactory.swagger.configuration.JacksonScalaSupport;
import com.mangofactory.swagger.configuration.SpringSwaggerConfig;
import com.mangofactory.swagger.configuration.SpringSwaggerModelConfig;
import com.mangofactory.swagger.configuration.SwaggerGlobalSettings;
import com.mangofactory.swagger.core.DefaultSwaggerPathProvider;
import com.mangofactory.swagger.core.SwaggerApiResourceListing;
import com.mangofactory.swagger.core.SwaggerPathProvider;
import com.mangofactory.swagger.scanners.ApiListingReferenceScanner;
import com.wordnik.swagger.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;

@Configuration
@ComponentScan(basePackages = &quot;com.mangofactory.swagger&quot;)
public class SwaggerConfig {

    public static final List&amp;lt;String&amp;gt; DEFAULT_INCLUDE_PATTERNS = Arrays.asList(&quot;/news/.*&quot;);
    public static final String SWAGGER_GROUP = &quot;mobile-api&quot;;

    @Value(&quot;${app.docs}&quot;)
    private String docsLocation;

    @Autowired
    private SpringSwaggerConfig springSwaggerConfig;
    @Autowired
    private SpringSwaggerModelConfig springSwaggerModelConfig;

    /**
     * Adds the jackson scala module to the MappingJackson2HttpMessageConverter registered with spring
     * Swagger core models are scala so we need to be able to convert to JSON
     * Also registers some custom serializers needed to transform swagger models to swagger-ui required json format
     */
    @Bean
    public JacksonScalaSupport jacksonScalaSupport() {
        JacksonScalaSupport jacksonScalaSupport = new JacksonScalaSupport();
        //Set to false to disable
        jacksonScalaSupport.setRegisterScalaModule(true);
        return jacksonScalaSupport;
    }


    /**
     * Global swagger settings
     */
    @Bean
    public SwaggerGlobalSettings swaggerGlobalSettings() {
        SwaggerGlobalSettings swaggerGlobalSettings = new SwaggerGlobalSettings();
        swaggerGlobalSettings.setGlobalResponseMessages(springSwaggerConfig.defaultResponseMessages());
        swaggerGlobalSettings.setIgnorableParameterTypes(springSwaggerConfig.defaultIgnorableParameterTypes());
        swaggerGlobalSettings.setParameterDataTypes(springSwaggerModelConfig.defaultParameterDataTypes());
        return swaggerGlobalSettings;
    }

    /**
     * API Info as it appears on the swagger-ui page
     */
    private ApiInfo apiInfo() {
        ApiInfo apiInfo = new ApiInfo(
                &quot;News API&quot;,
                &quot;Mobile applications and beyond!&quot;,
                &quot;https://helloreverb.com/terms/&quot;,
                &quot;matt@raibledesigns.com&quot;,
                &quot;Apache 2.0&quot;,
                &quot;http://www.apache.org/licenses/LICENSE-2.0.html&quot;
        );
        return apiInfo;
    }

    /**
     * Configure a SwaggerApiResourceListing for each swagger instance within your app. e.g. 1. private  2. external apis
     * Required to be a spring bean as spring will call the postConstruct method to bootstrap swagger scanning.
     *
     * @return
     */
    @Bean
    public SwaggerApiResourceListing swaggerApiResourceListing() {
        //The group name is important and should match the group set on ApiListingReferenceScanner
        //Note that swaggerCache() is by DefaultSwaggerController to serve the swagger json
        SwaggerApiResourceListing swaggerApiResourceListing = new SwaggerApiResourceListing(springSwaggerConfig.swaggerCache(), SWAGGER_GROUP);

        //Set the required swagger settings
        swaggerApiResourceListing.setSwaggerGlobalSettings(swaggerGlobalSettings());

        //Use a custom path provider or springSwaggerConfig.defaultSwaggerPathProvider()
        swaggerApiResourceListing.setSwaggerPathProvider(apiPathProvider());

        //Supply the API Info as it should appear on swagger-ui web page
        swaggerApiResourceListing.setApiInfo(apiInfo());

        //Global authorization - see the swagger documentation
        swaggerApiResourceListing.setAuthorizationTypes(authorizationTypes());

        //Every SwaggerApiResourceListing needs an ApiListingReferenceScanner to scan the spring request mappings
        swaggerApiResourceListing.setApiListingReferenceScanner(apiListingReferenceScanner());
        return swaggerApiResourceListing;
    }

    @Bean
    /**
     * The ApiListingReferenceScanner does most of the work.
     * Scans the appropriate spring RequestMappingHandlerMappings
     * Applies the correct absolute paths to the generated swagger resources
     */
    public ApiListingReferenceScanner apiListingReferenceScanner() {
        ApiListingReferenceScanner apiListingReferenceScanner = new ApiListingReferenceScanner();

        //Picks up all of the registered spring RequestMappingHandlerMappings for scanning
        apiListingReferenceScanner.setRequestMappingHandlerMapping(springSwaggerConfig.swaggerRequestMappingHandlerMappings());

        //Excludes any controllers with the supplied annotations
        apiListingReferenceScanner.setExcludeAnnotations(springSwaggerConfig.defaultExcludeAnnotations());

        //
        apiListingReferenceScanner.setResourceGroupingStrategy(springSwaggerConfig.defaultResourceGroupingStrategy());

        //Path provider used to generate the appropriate uri&apos;s
        apiListingReferenceScanner.setSwaggerPathProvider(apiPathProvider());

        //Must match the swagger group set on the SwaggerApiResourceListing
        apiListingReferenceScanner.setSwaggerGroup(SWAGGER_GROUP);

        //Only include paths that match the supplied regular expressions
        apiListingReferenceScanner.setIncludePatterns(DEFAULT_INCLUDE_PATTERNS);

        return apiListingReferenceScanner;
    }

    /**
     * Example of a custom path provider
     */
    @Bean
    public ApiPathProvider apiPathProvider() {
        ApiPathProvider apiPathProvider = new ApiPathProvider(docsLocation);
        apiPathProvider.setDefaultSwaggerPathProvider(springSwaggerConfig.defaultSwaggerPathProvider());
        return apiPathProvider;
    }


    private List&amp;lt;AuthorizationType&amp;gt; authorizationTypes() {
        ArrayList&amp;lt;AuthorizationType&amp;gt; authorizationTypes = new ArrayList&amp;lt;&amp;gt;();

        List&amp;lt;AuthorizationScope&amp;gt; authorizationScopeList = newArrayList();
        authorizationScopeList.add(new AuthorizationScope(&quot;global&quot;, &quot;access all&quot;));

        List&amp;lt;GrantType&amp;gt; grantTypes = newArrayList();

        LoginEndpoint loginEndpoint = new LoginEndpoint(apiPathProvider().getAppBasePath() + &quot;/user/authenticate&quot;);
        grantTypes.add(new ImplicitGrant(loginEndpoint, &quot;access_token&quot;));

        return authorizationTypes;
    }

    @Bean
    public SwaggerPathProvider relativeSwaggerPathProvider() {
        return new ApiRelativeSwaggerPathProvider();
    }

    private class ApiRelativeSwaggerPathProvider extends DefaultSwaggerPathProvider {
        @Override
        public String getAppBasePath() {
            return &quot;/&quot;;
        }

        @Override
        public String getSwaggerDocumentationBasePath() {
            return &quot;/api-docs&quot;;
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;ApiPathProvider&lt;/code&gt; class referenced above is as follows:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package example.config;

import com.mangofactory.swagger.core.SwaggerPathProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.ServletContext;

public class ApiPathProvider implements SwaggerPathProvider {
    private SwaggerPathProvider defaultSwaggerPathProvider;
    @Autowired
    private ServletContext servletContext;

    private String docsLocation;

    public ApiPathProvider(String docsLocation) {
        this.docsLocation = docsLocation;
    }

    @Override
    public String getApiResourcePrefix() {
        return defaultSwaggerPathProvider.getApiResourcePrefix();
    }

    public String getAppBasePath() {
        return UriComponentsBuilder
                .fromHttpUrl(docsLocation)
                .path(servletContext.getContextPath())
                .build()
                .toString();
    }

    @Override
    public String getSwaggerDocumentationBasePath() {
        return UriComponentsBuilder
                .fromHttpUrl(getAppBasePath())
                .pathSegment(&quot;api-docs/&quot;)
                .build()
                .toString();
    }

    @Override
    public String getRequestMappingEndpoint(String requestMappingPattern) {
        return defaultSwaggerPathProvider.getRequestMappingEndpoint(requestMappingPattern);
    }

    public void setDefaultSwaggerPathProvider(SwaggerPathProvider defaultSwaggerPathProvider) {
        this.defaultSwaggerPathProvider = defaultSwaggerPathProvider;
    }
}
&lt;/pre&gt;
&lt;p&gt;In &lt;em&gt;src/main/resources/application.properties&lt;/em&gt;, add an &quot;app.docs&quot; property. This will need
    to be changed as you move your application from local -&gt; test -&gt; staging -&gt; production. Spring Boot&apos;s
    &lt;a href=&quot;http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-external-config-application-property-files&quot;&gt;externalized
        configuration&lt;/a&gt; makes this fairly simple.
&lt;/p&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;
app.docs=http://localhost:8080
&lt;/pre&gt;
&lt;p&gt;
    &lt;strong&gt;3. Verify Swagger produces JSON.&lt;/strong&gt; 
&lt;/p&gt;
&lt;p&gt;
After completing the above steps, you should be able
    to see the JSON Swagger generates for your API. Open &lt;a href=&quot;http://localhost:8080/api-docs&quot;&gt;http://localhost:8080/api-docs&lt;/a&gt;
    in your browser or &lt;code&gt;curl http://localhost:8080/api-docs&lt;/code&gt;.
&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
{
    &quot;apiVersion&quot;: &quot;1&quot;,
    &quot;swaggerVersion&quot;: &quot;1.2&quot;,
    &quot;apis&quot;: [
        {
            &quot;path&quot;: &quot;http://localhost:8080/api-docs/mobile-api/example_NewsController&quot;,
            &quot;description&quot;: &quot;example.NewsController&quot;
        }
    ],
    &quot;info&quot;: {
        &quot;title&quot;: &quot;News API&quot;,
        &quot;description&quot;: &quot;Mobile applications and beyond!&quot;,
        &quot;termsOfServiceUrl&quot;: &quot;https://helloreverb.com/terms/&quot;,
        &quot;contact&quot;: &quot;matt@raibledesigns.com&quot;,
        &quot;license&quot;: &quot;Apache 2.0&quot;,
        &quot;licenseUrl&quot;: &quot;http://www.apache.org/licenses/LICENSE-2.0.html&quot;
    }
}
&lt;/pre&gt;
&lt;p&gt;
    &lt;strong&gt;4. Copy Swagger UI into your project.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/wordnik/swagger-ui&quot;&gt;Swagger UI&lt;/a&gt; is a good-looking JavaScript client for Swagger&apos;s
    JSON. I integrated it using the following steps:
&lt;/p&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;
git clone https://github.com/wordnik/swagger-ui
cp -r swagger-ui/dist ~/dev/x-auth-security/src/main/resources/public/docs
&lt;/pre&gt;
&lt;p&gt;
    I modified docs/index.html, deleting its header (&amp;lt;div id=&apos;header&apos;&gt;) element, as well as made its url
    dynamic.
&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
...
$(function () {
  var apiUrl = window.location.protocol + &quot;//&quot; + window.location.host;
  if (window.location.pathname.indexOf(&apos;/api&apos;) &gt; 0) {
    apiUrl += window.location.pathname.substring(0, window.location.pathname.indexOf(&apos;/api&apos;))
  }
  apiUrl += &quot;/api-docs&quot;;
  log(&apos;API URL: &apos; + apiUrl);
  window.swaggerUi = new SwaggerUi({
    url: apiUrl,
    dom_id: &quot;swagger-ui-container&quot;,
...
&lt;/pre&gt;
&lt;p&gt;
    After making these changes, I was able to open fire up the app with &quot;mvn spring-boot:run&quot; and view
    &lt;a href=&quot;http://localhost:8080/docs/index.html&quot;&gt;http://localhost:8080/docs/index.html&lt;/a&gt; in my browser.
&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;http://farm4.staticflickr.com/3732/13409312164_feb72e7b8f_b.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/13409312164/&quot; title=&quot;Swagger UI News by mraible, on Flickr&quot;
       rel=&quot;lightbox[swagger]&quot;&gt;&lt;img
            src=&quot;//farm4.staticflickr.com/3732/13409312164_feb72e7b8f.jpg&quot; width=&quot;500&quot; height=&quot;278&quot;
            alt=&quot;Swagger UI News&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;strong&gt;5. Annotate your API.&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;There are two services in x-auth-security: one for authentication and one for
    news. To provide more
    information to the &quot;news&quot; service&apos;s documentation, add @Api and @ApiOperation annotations. These annotations aren&apos;t
    necessary to get a service
    to show up in Swagger UI, but if you don&apos;t specify the @Api(&quot;user&quot;), you&apos;ll end up with an ugly-looking class name
    instead
    (e.g. example_xauth_UserXAuthTokenController).
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@RestController
@Api(value = &quot;news&quot;, description = &quot;News API&quot;)
class NewsController {

    Map&amp;lt;Long, NewsEntry&amp;gt; entries = new ConcurrentHashMap&amp;lt;Long, NewsEntry&amp;gt;();

    @RequestMapping(value = &quot;/news&quot;, method = RequestMethod.GET)
    @ApiOperation(value = &quot;Get News&quot;, notes = &quot;Returns news items&quot;)
    Collection&amp;lt;NewsEntry&amp;gt; entries() {
        return this.entries.values();
    }

    @RequestMapping(value = &quot;/news/{id}&quot;, method = RequestMethod.DELETE)
    @ApiOperation(value = &quot;Delete News item&quot;, notes = &quot;Deletes news item by id&quot;)
    NewsEntry remove(@PathVariable Long id) {
        return this.entries.remove(id);
    }

    @RequestMapping(value = &quot;/news/{id}&quot;, method = RequestMethod.GET)
    @ApiOperation(value = &quot;Get a news item&quot;, notes = &quot;Returns a news item&quot;)
    NewsEntry entry(@PathVariable Long id) {
        return this.entries.get(id);
    }

    @RequestMapping(value = &quot;/news/{id}&quot;, method = RequestMethod.POST)
    @ApiOperation(value = &quot;Update News&quot;, notes = &quot;Updates a news item&quot;)
    NewsEntry update(@RequestBody NewsEntry news) {
        this.entries.put(news.getId(), news);
        return news;
    }
...
}
&lt;/pre&gt;
&lt;p&gt;
    You might notice
    the screenshot above only shows news. This is because &lt;code&gt;SwaggerConfig.DEFAULT_INCLUDE_PATTERNS&lt;/code&gt; only
    specifies news. The following
    will include all APIs.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public static final List&amp;lt;String&gt; DEFAULT_INCLUDE_PATTERNS = Arrays.asList(&quot;/.*&quot;);
&lt;/pre&gt;
&lt;p&gt;After adding these annotations and modifying &lt;code&gt;SwaggerConfig&lt;/code&gt;, you should see all available services.&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;http://farm8.staticflickr.com/7366/13408960855_8407d286a8_b.jpg&quot; rel=&quot;lightbox[swagger]&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/13408960855/&quot; title=&quot;Swagger UI Complete by mraible, on Flickr&quot;&gt;&lt;img
            src=&quot;//farm8.staticflickr.com/7366/13408960855_8407d286a8.jpg&quot; width=&quot;500&quot; height=&quot;325&quot;
            alt=&quot;Swagger UI Complete&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;In swagger-springmvc 0.8.x, the ability to use @ApiModel and @ApiModelProperty annotations was added. This means you
    can annotate &lt;code&gt;NewsEntry&lt;/code&gt; to specify which fields are required.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@ApiModel(&quot;News Entry&quot;)
public static class NewsEntry {
    @ApiModelProperty(value = &quot;the id of the item&quot;, required = true)
    private long id;
    @ApiModelProperty(value = &quot;content&quot;, required = true)
    private String content;

    // getters and setters
}
&lt;/pre&gt;
&lt;p&gt;This results in the model&apos;s documentation showing up in Swagger UI. If &quot;required&quot; isn&apos;t specified, a property shows
    up as &lt;em&gt;optional&lt;/em&gt;.&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;http://farm4.staticflickr.com/3771/13409312244_27f72688d1_b.jpg&quot;
       data-href=&quot;https://www.flickr.com/photos/mraible/13409312244/&quot; title=&quot;Swagger UI Model by mraible, on Flickr&quot;
       rel=&quot;lightbox[swagger]&quot;&gt;&lt;img
            src=&quot;//farm4.staticflickr.com/3771/13409312244_27f72688d1_n.jpg&quot; width=&quot;320&quot; height=&quot;247&quot;
            alt=&quot;Swagger UI Model&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;strong&gt;Parting Thoughts&lt;/strong&gt;&lt;br/&gt;
    The QA Engineers and 3rd Party iOS Developers have been very pleased with our API documentation. I believe this is
    largely
    due to Swagger and its nice-looking UI. The Swagger UI also provides an interface to test
    the endpoints by entering parameters (or JSON) into HTML forms and clicking buttons. This could benefit those QA
    folks
    that prefer using Selenium to test HTML (vs. raw REST endpoints).
&lt;/p&gt;

&lt;p&gt;I&apos;ve been quite pleased with swagger-springmvc, so kudos to its developers. They&apos;ve been very responsive in
    &lt;a href=&quot;https://github.com/martypitt/swagger-springmvc/issues/created_by/mraible?page=1&amp;amp;state=closed&quot;&gt;fixing
        issues I&apos;ve reported&lt;/a&gt;.
    The only thing I&apos;d like is support for recognizing JSR303 annotations (e.g. @NotNull) as required fields.
&lt;/p&gt;

&lt;p&gt;To see everything running locally, checkout my modified &lt;a
        href=&quot;https://github.com/mraible/boot-examples/tree/master/x-auth-security&quot;&gt;x-auth-security project on
    GitHub&lt;/a&gt;
    and the &lt;a href=&quot;https://github.com/mraible/boot-examples/commits/master&quot;&gt;associated commits&lt;/a&gt; for this article.
&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/comparing_jvm_web_frameworks_at</id>
        <title type="html">Comparing JVM Web Frameworks at vJUG</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/comparing_jvm_web_frameworks_at"/>
        <published>2014-02-06T10:54:17-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="jsf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="playframework" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="vaadin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tapestry" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="angularjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="wicket" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jvm" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;A couple months ago, I was invited to &lt;a href=&quot;http://www.meetup.com/virtualJUG/events/153096902/&quot;&gt;speak at Virtual JUG&lt;/a&gt; - an online-only Java User Group organized by the &lt;a href=&quot;http://zeroturnaround.com/&quot;&gt;ZeroTurnaround&lt;/a&gt; folks. They chose my Comparing JVM Web Frameworks presentation and we agreed I&apos;d speak yesterday morning. They used a combination of Google Hangouts, live streaming on YouTube and IRC to facilitate the meeting. It all went pretty smoothly and produced a comfortable speaking environment. To practice for vJUG, I delivered the same talk on Tuesday night at the &lt;a href=&quot;http://www.meetup.com/DOSUG1/events/155080452/&quot;&gt;Denver Open Source Users Group&lt;/a&gt;.
&lt;p&gt;
The last time I delivered this talk was at &lt;a href=&quot;http://raibledesigns.com/rd/entry/devoxx_france_a_great_conference&quot;&gt;Devoxx France&lt;/a&gt; in March 2013. I didn&apos;t change any of the format this time, keeping with referencing the Paradox of Choice and encouraging people to define constraints to help them make their decision. I did add a few new slides regarding RebelLabs&apos; &lt;a href=&quot;http://zeroturnaround.com/rebellabs/the-curious-coders-java-web-frameworks-comparison-spring-mvc-grails-vaadin-gwt-wicket-play-struts-and-jsf/&quot;&gt;Curious Coder&#8217;s Java Web Frameworks Comparison: Spring MVC, Grails, Vaadin, GWT, Wicket, Play, Struts and JSF&lt;/a&gt; and &lt;a href=&quot;http://zeroturnaround.com/rebellabs/the-2014-decision-makers-guide-to-java-web-frameworks/&quot;&gt;The 2014 Decision Maker&#8217;s Guide to Java Web Frameworks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also updated all the pretty graphs (which may or may not have any significance) with the latest stats from Dice.com, LinkedIn, StackOverflow and respective mailing lists. Significant changes I found compared to one year ago:&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;A couple months ago, I was invited to &lt;a href=&quot;http://www.meetup.com/virtualJUG/events/153096902/&quot;&gt;speak at Virtual JUG&lt;/a&gt; - an online-only Java User Group organized by the &lt;a href=&quot;http://zeroturnaround.com/&quot;&gt;ZeroTurnaround&lt;/a&gt; folks. They chose my Comparing JVM Web Frameworks presentation and we agreed I&apos;d speak yesterday morning. They used a combination of Google Hangouts, live streaming on YouTube and IRC to facilitate the meeting. It all went pretty smoothly and produced a comfortable speaking environment. To practice for vJUG, I delivered the same talk on Tuesday night at the &lt;a href=&quot;http://www.meetup.com/DOSUG1/events/155080452/&quot;&gt;Denver Open Source Users Group&lt;/a&gt;.
&lt;p&gt;
The last time I delivered this talk was at &lt;a href=&quot;http://raibledesigns.com/rd/entry/devoxx_france_a_great_conference&quot;&gt;Devoxx France&lt;/a&gt; in March 2013. I didn&apos;t change any of the format this time, keeping with referencing the Paradox of Choice and encouraging people to define constraints to help them make their decision. I did add a few new slides regarding RebelLabs&apos; &lt;a href=&quot;http://zeroturnaround.com/rebellabs/the-curious-coders-java-web-frameworks-comparison-spring-mvc-grails-vaadin-gwt-wicket-play-struts-and-jsf/&quot;&gt;Curious Coder&#8217;s Java Web Frameworks Comparison: Spring MVC, Grails, Vaadin, GWT, Wicket, Play, Struts and JSF&lt;/a&gt; and &lt;a href=&quot;http://zeroturnaround.com/rebellabs/the-2014-decision-makers-guide-to-java-web-frameworks/&quot;&gt;The 2014 Decision Maker&#8217;s Guide to Java Web Frameworks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also updated all the pretty graphs (which may or may not have any significance) with the latest stats from Dice.com, LinkedIn, StackOverflow and respective mailing lists. Significant changes I found compared to one year ago:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Job Listings on Dice.com
&lt;ul&gt;
&lt;li&gt;Play Framework job listings increased almost 4x&lt;/li&gt;
&lt;li&gt;Tapestry jobs are 1/3 of what they were a year ago&lt;/li&gt;
&lt;li&gt;Wicket jobs are 1/2 of what they were a year ago&lt;/li&gt;
&lt;li&gt;JavaScript framework jobs are up quite a bit: Ember.js up ~300%, AngularJS up 900%, Backbone up 160%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn Skills
&lt;ul&gt;
&lt;li&gt;Rails down ~30%&lt;/li&gt;
&lt;li&gt;Grails up 25%&lt;/li&gt;
&lt;li&gt;Play Framework up 200%&lt;/li&gt;
&lt;li&gt;Spring Roo up 40%&lt;/li&gt;
&lt;li&gt;Ember.js up 300%&lt;/li&gt;
&lt;li&gt;AngularJS up 840%&lt;/li&gt;
&lt;li&gt;Backbone up 200%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can tell from these findings, AngularJS has gained quite a bit of mindshare in the last year. There&apos;s a lot of companies looking for JavaScript skills and quite a few folks have added JavaScript frameworks to their LinkedIn profiles.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&quot;https://www.youtube.com/watch?v=ygW8fJVlDxQ&quot;&gt;watch the recording on YouTube&lt;/a&gt; or click play in the embedded video below.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/ygW8fJVlDxQ&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;You can also quickly browse the slide deck below, &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/Comparing_JVM_Web_Frameworks_February2014.pdf&quot;&gt;download the PDF&lt;/a&gt; or &lt;a href=&quot;http://www.slideshare.net/mraible/comparing-jvm-web-frameworks-february-2014&quot;&gt;view it on SlideShare&lt;/a&gt;.&lt;/li&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/30861557?rel=0&quot; width=&quot;512&quot; height=&quot;325&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px&quot; allowfullscreen webkitallowfullscreen mozallowfullscreen&gt; &lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;Thanks to all the folks who attended these talks. And thanks to &lt;a href=&quot;http://twitter.com/dosug&quot;&gt;@dosug&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/virtualjug&quot;&gt;@virtualjug&lt;/a&gt; for giving me the opportunity to speak.&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/a_webapp_makeover_with_spring</id>
        <title type="html">A Webapp Makeover with Spring 4 and Spring Boot</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/a_webapp_makeover_with_spring"/>
        <published>2013-12-11T12:47:15-07:00</published>
        <updated>2013-12-13T14:54:52-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="spring4" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jersey" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springboot" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;A typical Maven and Spring web application has a fair amount of XML and 
verbosity to it. Add in Jersey and Spring Security and you can have hundreds of lines of 
XML before you even start to write your Java code. As part of a recent project,
I was tasked with upgrading a webapp like this to use Spring 4 and 
&lt;a href=&quot;http://projects.spring.io/spring-boot/&quot;&gt;Spring Boot&lt;/a&gt;. I also figured I&apos;d try to minimize the XML.&lt;/p&gt; 
&lt;p&gt;This is my story on how I upgraded to Spring 4, Jersey 2, Java 8 and Spring Boot 0.5.0 M6. 
&lt;/p&gt;
&lt;p&gt;When I started, the app was using Spring 3.2.5, Spring Security 3.1.4 and Jersey 1.18. The
pom.xml had four Jersey dependencies, three Spring dependencies and three Spring Security
dependencies, along with a number of exclusions for &quot;jersey-spring&quot;.&lt;/p&gt;
&lt;p id=&quot;spring4&quot;&gt;&lt;strong&gt;Upgrading to Spring 4&lt;/strong&gt;&lt;br/&gt;
Upgrading to Spring 4 was easy, I changed the version property to 4.0.0.RC2 and added the new 
Spring &lt;a href=&quot;http://spring.io/blog/2013/12/03/spring-framework-4-0-rc2-available&quot;&gt;bill of materials&lt;/a&gt;
to my pom.xml. I also add the Spring milestone repo since Spring 4 won&apos;t be released to Maven central
until tomorrow.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-framework-bom&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${spring.framework.version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
            &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&amp;lt;/dependencyManagement&amp;gt;

&amp;lt;repositories&amp;gt;
    &amp;lt;repository&amp;gt;
        &amp;lt;id&amp;gt;spring-milestones&amp;lt;/id&amp;gt;
        &amp;lt;url&amp;gt;http://repo.spring.io/milestone&amp;lt;/url&amp;gt;
        &amp;lt;snapshots&amp;gt;
            &amp;lt;enabled&amp;gt;true&amp;lt;/enabled&amp;gt;
        &amp;lt;/snapshots&amp;gt;
    &amp;lt;/repository&amp;gt;
&amp;lt;/repositories&amp;gt;
&lt;/pre&gt;</summary>
        <content type="html">&lt;p&gt;A typical Maven and Spring web application has a fair amount of XML and 
verbosity to it. Add in Jersey and Spring Security and you can have hundreds of lines of 
XML before you even start to write your Java code. As part of a recent project,
I was tasked with upgrading a webapp like this to use Spring 4 and 
&lt;a href=&quot;http://projects.spring.io/spring-boot/&quot;&gt;Spring Boot&lt;/a&gt;. I also figured I&apos;d try to minimize the XML.&lt;/p&gt; 
&lt;p&gt;This is my story on how I upgraded to Spring 4, Jersey 2, Java 8 and Spring Boot 0.5.0 M6. 
&lt;/p&gt;
&lt;p&gt;When I started, the app was using Spring 3.2.5, Spring Security 3.1.4 and Jersey 1.18. The
pom.xml had four Jersey dependencies, three Spring dependencies and three Spring Security
dependencies, along with a number of exclusions for &quot;jersey-spring&quot;.&lt;/p&gt;
&lt;p id=&quot;spring4&quot;&gt;&lt;strong&gt;Upgrading to Spring 4&lt;/strong&gt;&lt;br/&gt;
Upgrading to Spring 4 was easy, I changed the version property to 4.0.0.RC2 and added the new 
Spring &lt;a href=&quot;http://spring.io/blog/2013/12/03/spring-framework-4-0-rc2-available&quot;&gt;bill of materials&lt;/a&gt;
to my pom.xml. I also add the Spring milestone repo since Spring 4 won&apos;t be released to Maven central
until tomorrow.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-framework-bom&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${spring.framework.version}&amp;lt;/version&amp;gt;
            &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
            &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&amp;lt;/dependencyManagement&amp;gt;

&amp;lt;repositories&amp;gt;
    &amp;lt;repository&amp;gt;
        &amp;lt;id&amp;gt;spring-milestones&amp;lt;/id&amp;gt;
        &amp;lt;url&amp;gt;http://repo.spring.io/milestone&amp;lt;/url&amp;gt;
        &amp;lt;snapshots&amp;gt;
            &amp;lt;enabled&amp;gt;true&amp;lt;/enabled&amp;gt;
        &amp;lt;/snapshots&amp;gt;
    &amp;lt;/repository&amp;gt;
&amp;lt;/repositories&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Next, I removed all the references to ${spring.framework.version} in dependencies since it&apos;d 
be controlled by &lt;a href=&quot;http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management&quot;&gt;
Maven&apos;s dependency management feature&lt;/a&gt;. 
&lt;/p&gt;
&lt;pre class=&quot;brush: diff&quot;&gt;
     &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-web&amp;lt;/artifactId&amp;gt;
-        &amp;lt;version&amp;gt;${spring.framework.version}&amp;lt;/version&amp;gt;
     &amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
I also changed to use Maven 3&apos;s &lt;a href=&quot;http://maven.apache.org/pom.html#Exclusions&quot;&gt;wildcard syntax&lt;/a&gt; to exclude multiple 
dependencies.&lt;/p&gt;
&lt;pre class=&quot;brush: diff&quot;&gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;com.sun.jersey.contribs&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;jersey-spring&amp;lt;/artifactId&amp;gt;
        &amp;lt;exclusions&amp;gt;
             &amp;lt;exclusion&amp;gt;
                 &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
-                    &amp;lt;artifactId&amp;gt;spring&amp;lt;/artifactId&amp;gt;
-                &amp;lt;/exclusion&amp;gt;
-                &amp;lt;exclusion&amp;gt;
-                    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
-                    &amp;lt;artifactId&amp;gt;spring-core&amp;lt;/artifactId&amp;gt;
-                &amp;lt;/exclusion&amp;gt;
-                &amp;lt;exclusion&amp;gt;
-                    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
-                    &amp;lt;artifactId&amp;gt;spring-web&amp;lt;/artifactId&amp;gt;
-                &amp;lt;/exclusion&amp;gt;
-                &amp;lt;exclusion&amp;gt;
-                    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
-                    &amp;lt;artifactId&amp;gt;spring-beans&amp;lt;/artifactId&amp;gt;
-                &amp;lt;/exclusion&amp;gt;
-                &amp;lt;exclusion&amp;gt;
-                    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
-                    &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
+                    &amp;lt;artifactId&amp;gt;*&amp;lt;/artifactId&amp;gt;
             &amp;lt;/exclusion&amp;gt;
         &amp;lt;/exclusions&amp;gt;
     &amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;I confirmed the upgrade worked by running &quot;mvn dependency:tree | grep spring&quot;, followed by &quot;mvn jetty:run&quot; and viewing the app in my browser. &lt;/p&gt;
&lt;p id=&quot;jersey2&quot;&gt;&lt;strong&gt;Upgrading to Jersey 2&lt;/strong&gt;&lt;br/&gt;
The next item I tackled was upgrading to Jersey 2.4.1. I changed the version number in my pom.xml, then added the Jersey BOM.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.glassfish.jersey&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jersey-bom&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${jersey.version}&amp;lt;/version&amp;gt;
    &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
    &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
You might ask &quot;why Jersey?&quot; if we already have Spring MVC and its REST support? You might also ask why not Play or Grails instead of a Java + Spring stack? For this particular project, I recommended technology options, and these were certainly among them. However, the team chose differently and I support their decision. The project is 
creating an iOS app, as well as a responsive HTML5 mobile/desktop app. We figured we had enough risk with new technologies on the front-end that we should play it a bit safer on the backend. To make the backend work a bit sexier, we&apos;ve decided to allow Spring 4, Java 8 and possibly some reactive principles.&lt;/p&gt;
&lt;p&gt;Next, I changed from the old &lt;i&gt;com.sun.jersey&lt;/i&gt; dependencies to &lt;i&gt;org.glassfish.jersey&lt;/i&gt; and removed jersey-spring. &lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.glassfish.jersey.containers&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jersey-container-servlet&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.glassfish.jersey.media&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jersey-media-json-jackson&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
The last thing I needed to do was change the servlet-class and param-name in web.xml:&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;servlet&amp;gt;
    &amp;lt;servlet-name&amp;gt;jersey-servlet&amp;lt;/servlet-name&amp;gt;
    &amp;lt;servlet-class&amp;gt;org.glassfish.jersey.servlet.ServletContainer&amp;lt;/servlet-class&amp;gt;
    &amp;lt;init-param&amp;gt;
        &amp;lt;param-name&amp;gt;jersey.config.server.provider.packages&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;com.raibledesigns.boot.service&amp;lt;/param-value&amp;gt;
    &amp;lt;/init-param&amp;gt;
    &amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;
&amp;lt;/servlet&amp;gt;
&lt;/pre&gt;
&lt;p id=&quot;java8&quot;&gt;&lt;strong&gt;Requiring Java 8&lt;/strong&gt;&lt;br/&gt;
Requiring Java 8 to compile was easy enough. I added the maven-compiler-plugin to enforce a minimum version.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.1&amp;lt;/version&amp;gt;
    &amp;lt;configuration&amp;gt;
        &amp;lt;source&amp;gt;1.8&amp;lt;/source&amp;gt;
        &amp;lt;target&amp;gt;1.8&amp;lt;/target&amp;gt;
    &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;&lt;p&gt;I &lt;a href=&quot;https://jdk8.java.net/download.html&quot;&gt;downloaded the latest Java 8 SDK&lt;/a&gt; and installed it. Then I set my JAVA_HOME to use it.&lt;/p&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;
export JAVA_HOME=`/usr/libexec/java_home -v 1.8`
&lt;/pre&gt;
&lt;p id=&quot;boot&quot;&gt;&lt;strong&gt;Integrating Spring Boot&lt;/strong&gt;&lt;br/&gt;
I learned about Spring Boot a few weeks ago &lt;a href=&quot;http://raibledesigns.com/rd/entry/devoxx_2013_a_nordic_countries&quot;&gt;at Devoxx&lt;/a&gt;. &lt;a href=&quot;http://www.joshlong.com/&quot;&gt;Josh Long&lt;/a&gt; gave me a 3-minute demo at the speaker&apos;s dinner and showed me enough to pique my interest. To integrate it into my project, I started with the &lt;a href=&quot;http://projects.spring.io/spring-boot/#quick-start&quot;&gt;Quick Start&lt;/a&gt;. I added the boot-parent, dependencies for web, security and actuator (logging, metrics, etc.) and the Maven plugin. I removed all the Spring and Spring Security dependencies.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;parent&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.5.0.M6&amp;lt;/version&amp;gt;
&amp;lt;/parent&amp;gt;
...
&amp;lt;pluginRepositories&amp;gt;
    &amp;lt;pluginRepository&amp;gt;
        &amp;lt;id&amp;gt;spring-milestones&amp;lt;/id&amp;gt;
        &amp;lt;url&amp;gt;http://repo.spring.io/milestone&amp;lt;/url&amp;gt;
    &amp;lt;/pluginRepository&amp;gt;
&amp;lt;/pluginRepositories&amp;gt;
...
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-security&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-actuator&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
...
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Upon restarting my app, I got an error about spring-security.xml using a 3.1 XSD. I fixed it by changing to 3.2. Next, I wanted to eliminate web.xml. First of all, I created an &lt;code&gt;ApplicationInitializer&lt;/code&gt; so the WAR could be started from the command line.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package com.raibledesigns.boot.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class ApplicationInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ApplicationInitializer.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(ApplicationInitializer.class, args);
    }
}
&lt;/pre&gt;
&lt;p&gt;However, after adding this, I received the following error on startup:&lt;/p&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
&apos;org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor&apos;: 
Invocation of init method failed; nested exception is 
java.lang.AbstractMethodError: org.hibernate.validator.internal.engine.ConfigurationImpl
.getDefaultParameterNameProvider()Ljavax/validation/ParameterNameProvider;
&lt;/pre&gt;
&lt;p&gt;Adding hibernate-validator as a dependency solved this problem:&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.hibernate&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;hibernate-validator&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;To configure Spring Security without web.xml and spring-security.xml, I created &lt;code&gt;WebSecurityConfig.java&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package com.raibledesigns.boot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
@Order(Ordered.LOWEST_PRECEDENCE - 6)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers(&quot;/&quot;, &quot;/home&quot;).permitAll()
                .antMatchers(&quot;/v1.0/**&quot;).hasRole(&quot;USER&quot;)
                .anyRequest().authenticated();
        http.httpBasic().realmName(&quot;My API&quot;);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
        authManagerBuilder.inMemoryAuthentication()
                .withUser(&quot;test&quot;).password(&quot;test123&quot;).roles(&quot;USER&quot;);
    }
}
&lt;/pre&gt;
&lt;p&gt;To configure Jersey without web.xml, I created a &lt;code&gt;JerseyConfig&lt;/code&gt; class:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package com.raibledesigns.boot.config;

import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;

import javax.ws.rs.ApplicationPath;

@ApplicationPath(&quot;/v1.0&quot;)
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        packages(&quot;com.raibledesigns.boot.service&quot;);
        property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
        property(ServerProperties.JSON_PROCESSING_FEATURE_DISABLE, false);
        property(ServerProperties.MOXY_JSON_FEATURE_DISABLE, true);
        property(ServerProperties.WADL_FEATURE_DISABLE, true);
        register(LoggingFilter.class);
        register(JacksonFeature.class);
    }
}
&lt;/pre&gt;
&lt;p&gt;Finally, I created &lt;code&gt;MvcConfig.java&lt;/code&gt; to set the welcome page.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package com.raibledesigns.boot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController(&quot;/&quot;).setViewName(&quot;index&quot;);
    }
}
&lt;/pre&gt;
&lt;p&gt;To cleanup, I deleted &lt;code&gt;src/main/webapp/WEB-INF&lt;/code&gt; and created &lt;code&gt;src/main/resources/logback.xml&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;configuration&amp;gt;
    &amp;lt;include resource=&quot;org/springframework/boot/logging/logback/base.xml&quot;/&amp;gt;
    &amp;lt;logger name=&quot;org.springframework.boot&quot; level=&quot;INFO&quot;/&amp;gt;
    &amp;lt;logger name=&quot;org.springframework.security&quot; level=&quot;ERROR&quot;/&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/pre&gt;&lt;p&gt;Since Boot doesn&apos;t support JSP out-of-the-box, I renamed my index.jsp file to index.html and changed the URL in it to point to &quot;/v1.0/hello&quot;. I was pleased to see that everything worked nicely. I learned shortly after that I could remove the Spring BOM since Spring Boot &lt;a href=&quot;https://twitter.com/rob_winch/status/410609696639184896&quot;&gt;uses a &amp;lt;spring.version&amp;gt; property to control its Spring version&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;The only issue I found is when started the app with &quot;mvn package &amp;&amp; java -jar target/app.war&quot;, it failed to initialize Jersey. I tried adding a @Bean for the servlet:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Bean
public ServletRegistrationBean jerseyServlet() {
    ServletRegistrationBean registration = new ServletRegistrationBean(new ServletContainer(), &quot;/v1.0/*&quot;);
    registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, JerseyConfig.class.getName());
    return registration;
}
&lt;/pre&gt;
&lt;p&gt;Unfortunately, when running it using &quot;java -jar&quot;, I get the following error:
&lt;/p&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;
org.glassfish.hk2.api.MultiException: A MultiException has 1 exceptions.  They are:
1. org.glassfish.jersey.server.internal.scanning.ResourceFinderException: 
java.io.FileNotFoundException: /.../target/app.war!/WEB-INF/classes (No such file or directory)
	at org.jvnet.hk2.internal.Utilities.justCreate(Utilities.java:869)
	at org.jvnet.hk2.internal.ServiceLocatorImpl.create(ServiceLocatorImpl.java:814)
	at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:906)
	at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:898)
	at org.glassfish.jersey.server.ApplicationHandler.createApplication(ApplicationHandler.java:300)
	at org.glassfish.jersey.server.ApplicationHandler.&amp;lt;init&amp;gt;(ApplicationHandler.java:279)
	at org.glassfish.jersey.servlet.WebComponent.&amp;lt;init&amp;gt;(WebComponent.java:302)
&lt;/pre&gt;
&lt;p&gt;
This seems strange since there is a WEB-INF/classes in my WAR. Regardless, this is not a Boot problem per se, but more of a Jersey issue. From one of the Boot developers:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
The whole idea with Boot is that servlets are just a transport - they are a means to an end, and hopefully not the only one - the &quot;container&quot; is Spring, not the servlet container. We probably could add some form of support for SCI but only by hacking the containers since the spec really doesn&apos;t allow for much control of their lifecycle. It hasn&apos;t been a priority so far.
&lt;/p&gt;
&lt;p id=&quot;summary&quot;&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
I hope this article is useful to see how you to upgrade your Java webapps to use Spring 4 and Spring Boot. I&apos;ve created a &lt;a href=&quot;https://github.com/mraible/boot-makeover&quot;&gt;boot-makeover project on GitHub&lt;/a&gt; with all the code mentioned. You can also &lt;a href=&quot;https://github.com/mraible/boot-makeover/commits/master&quot;&gt;view the commits&lt;/a&gt; for each step. &lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/the_modern_java_web_developer1</id>
        <title type="html">The Modern Java Web Developer Bootcamp at Devoxx</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/the_modern_java_web_developer1"/>
        <published>2013-10-29T10:21:49-06:00</published>
        <updated>2013-10-29T16:22:39-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="webdevelopment" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jvm" scheme="http://roller.apache.org/ns/tags/" />
        <category term="dv13-javaweb$" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">At this year&apos;s &lt;a href=&quot;http://www.devoxx.be/&quot;&gt;Devoxx&lt;/a&gt;, I&apos;ll be delivering &lt;a href=&quot;http://www.devoxx.be/dv13-matt-raible.html?presId=3648&quot;&gt;my first University session&lt;/a&gt;. University talks are in depth presentations of 3 hours (= 75m + 30m break + 75m). I&apos;m calling it The Modern Java Web Developer Bootcamp and my goal is to teach people some new concepts and techniques that&apos;ll make them more valuable developers. My session&apos;s hashtag is &lt;a href=&quot;https://twitter.com/search?q=%23dv13-javaweb%24&quot;&gt;#dv13-javaweb$&lt;/a&gt; to exemplify the important takeaways: &lt;a href=&quot;http://www.infoq.com/articles/javaone2013-roundup&quot;&gt;Java is back&lt;/a&gt;, web development is fun and you can make more money.
&lt;/p&gt;
&lt;p&gt;Three hours is quite a bit longer than I&apos;m used to, but I&apos;m confident I can fill the time with lots of knowledge. My plan is to enhance my &lt;a href=&quot;http://raibledesigns.com/rd/entry/javaone_2013_my_presentations&quot;&gt;presentation from JavaOne&lt;/a&gt; and add a few demos. Currently, I&apos;m thinking of developing the following additional content:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP Overview (with SPDY)&lt;/li&gt;
&lt;li&gt;Polymer and Web Components&lt;/li&gt;
&lt;li&gt;Bootstrap 3 Overview&lt;/li&gt;
&lt;li&gt;HTML5 Storage&lt;/li&gt;
&lt;li&gt;API Framework Comparison (Play, Grails, Dropwizard)&lt;/li&gt;
&lt;li&gt;Load Testing&lt;/li&gt;
&lt;li&gt;Performance Monitoring (including RUM)&lt;/li&gt;
&lt;li&gt;Internal Cloud Options&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For demos, I&apos;d like to show a few that provide real value to attendees and teach them how to do something they haven&apos;t done before. The ones below are candidates I&apos;m thinking of, and I&apos;d like to pick three for the final presentation.&lt;/p&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;Browser Tools Demo&lt;/li&gt;
&lt;li&gt;Developing with Bootstrap Demo&lt;/li&gt;
&lt;li&gt;AngularJS Demo&lt;/li&gt;
&lt;li&gt;Refactor an app from Spring to Java EE, no XML, all Java 8&lt;/li&gt;
&lt;li&gt;Page Speed Improvement Demo&lt;/li&gt;
&lt;li&gt;Security Demo (add LDAP to Angular app + OWASP ZAP)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you could pick three real-time tutorials from the choices above, which ones would you choose?&lt;/p&gt;
&lt;p&gt;I&apos;m also thinking of adding some stories about impressive loads served with very little hardware and real-time dashboard development. If you have a story about either of these, please let me know. I&apos;d be happy to credit you (or your company) and talk about any technical implementation details you&apos;re willing to provide.&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/video_of_comparing_jvm_web</id>
        <title type="html">Video of Comparing JVM Web Frameworks from Devoxx France</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/video_of_comparing_jvm_web"/>
        <published>2013-06-24T09:10:45-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="devoxxfr" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx" scheme="http://roller.apache.org/ns/tags/" />
        <category term="parleys" scheme="http://roller.apache.org/ns/tags/" />
        <category term="video" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="comparison" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jvm" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Whenever I do a talk, I get requests for a recording of it. It&apos;s rare that recordings are made, but when they are, I like to share them. In March of this year, I &lt;a href=&quot;http://raibledesigns.com/rd/entry/devoxx_france_a_great_conference&quot;&gt;traveled to Devoxx France&lt;/a&gt; and had a great time. One of the talks I delivered was Comparing JVM Web Frameworks, with a bit of a twist from prior versions.
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/The_Paradox_of_Choice:_Why_More_Is_Less&quot; title=&quot;The Paradox of Choice&quot;&gt;&lt;img src=&quot;//farm9.staticflickr.com/8102/8600235023_dc4753c0aa_t.jpg&quot; width=&quot;65&quot; height=&quot;100&quot; alt=&quot;The Paradox of Choice&quot; class=&quot;picture&quot;&gt;&lt;/a&gt;
I started reading &lt;a href=&quot;http://en.wikipedia.org/wiki/The_Paradox_of_Choice:_Why_More_Is_Less&quot;&gt;The Paradox of Choice&lt;/a&gt; and found many parallels to the agony that developers experience with choosing a web framework. I described how I didn&apos;t think good framework decisions were based on the many, many features that frameworks have, but often on pre-defined constraints. There&apos;s those lucky developers that get to choose a Full Stack Framework because they&apos;re doing greenfield development. Then there&apos;s those that want a better &lt;em&gt;Pure&lt;/em&gt; Web Framework that replaces something (e.g. Struts) that&apos;s not satisfying their needs. And lastly, there&apos;s those that&apos;ve found it possible to leverage a &lt;abbr title=&quot;Service Oriented Front End Architecture&quot;&gt;SOFEA&lt;/abbr&gt; and use a JavaScript MVC framework with an API Framework on the backend. I don&apos;t think it makes sense to compare &lt;em&gt;all&lt;/em&gt; web frameworks and I tried to use these pre-defined constraints (language, platform and application type) argument to separate into categories and help make choosing easier. 
&lt;/p&gt;
&lt;p&gt;The good folks at Parleys have &lt;a href=&quot;http://www.parleys.com/play/51b27df5e4b0065193d63016&quot;&gt;published the video of this talk&lt;/a&gt;. If you haven&apos;t heard of Parleys, it&apos;s an awesome platform for watching conference talks. As their &lt;a href=&quot;http://parleys.com/info&quot;&gt;Mission Statement&lt;/a&gt; says: &lt;em&gt;If YouTube and Slideshare would make a baby then it would be named Parleys.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Below is an embedded video of this presentation - I hope you enjoy watching it as much as I did delivering it!&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe type=&quot;text/html&quot; width=&quot;670&quot; height=&quot;360&quot; mozallowfullscreen=&quot;true&quot; webkitallowfullscreen=&quot;true&quot; src=&quot;//www.parleys.com/share.html#play/51b27df5e4b0065193d63016&quot; frameborder=&quot;0&quot;&gt;&amp;lt;br /&amp;gt;&lt;/iframe&gt;&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/developing_with_angularjs_part_ii</id>
        <title type="html">Developing with AngularJS - Part II: Dialogs and Data</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/developing_with_angularjs_part_ii"/>
        <published>2013-06-20T08:45:13-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/The Web" label="The Web" />
        <category term="angularui" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jqueryui" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jquery" scheme="http://roller.apache.org/ns/tags/" />
        <category term="angularjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javascript" scheme="http://roller.apache.org/ns/tags/" />
        <category term="taleo" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;A couple of days ago, I wrote an article on &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_with_angularjs_part_i&quot;&gt;how I started developing with AngularJS&lt;/a&gt;. I used AngularJS for several months to develop a &quot;My Dashboard&quot; feature for a client&apos;s product and learned a whole bunch of stuff along the way. &lt;/p&gt;
&lt;p&gt;This article provides an overview of how I changed some of My Dashboard&apos;s features to use Angular instead of jQuery. After finishing the prototype work in January, we started moving bits and pieces into the main application. We kept the same file names for our Angular-related files and copied them into the project.
&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;http://www.flickr.com/photos/mraible/8904352343/&quot; title=&quot;Directory Structure&quot;&gt;&lt;img src=&quot;http://farm3.staticflickr.com/2856/8904352343_20beb87da8_o.png&quot; width=&quot;280&quot; height=&quot;268&quot; alt=&quot;Directory Structure&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;All these files are packaged up into a &lt;code&gt;dashboard.js&lt;/code&gt; file that&apos;s included at the bottom of our Dashboard page. While our prototype used jQuery 1.9 and jQuery UI 1.10, the application&apos;s codebase used jQuery 1.7.1 and jQuery UI 1.8.3. Luckily, this didn&apos;t present a problem as everything continued to work as expected.&lt;/p&gt;
&lt;p&gt;Around this time, we also had many discussions with the Product Team about charts. Since Highcharts required we purchase a license, we took at look at &lt;a href=&quot;http://www.anychart.com/&quot;&gt;AnyChart&lt;/a&gt;, which we were already using. We were able to get AnyChart to work with our existing &lt;em&gt;chart&lt;/em&gt; directive with minimal changes. Most changes were in the JSON itself. &lt;/p&gt;
&lt;p&gt;We committed the first pass (with sample data still hard-coded) in mid-February.&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;A couple of days ago, I wrote an article on &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_with_angularjs_part_i&quot;&gt;how I started developing with AngularJS&lt;/a&gt;. I used AngularJS for several months to develop a &quot;My Dashboard&quot; feature for a client&apos;s product and learned a whole bunch of stuff along the way. &lt;/p&gt;
&lt;p&gt;This article provides an overview of how I changed some of My Dashboard&apos;s features to use Angular instead of jQuery. After finishing the prototype work in January, we started moving bits and pieces into the main application. We kept the same file names for our Angular-related files and copied them into the project.
&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;http://www.flickr.com/photos/mraible/8904352343/&quot; title=&quot;Directory Structure&quot;&gt;&lt;img src=&quot;//farm3.staticflickr.com/2856/8904352343_20beb87da8_o.png&quot; width=&quot;280&quot; height=&quot;268&quot; alt=&quot;Directory Structure&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;All these files are packaged up into a &lt;code&gt;dashboard.js&lt;/code&gt; file that&apos;s included at the bottom of our Dashboard page. While our prototype used jQuery 1.9 and jQuery UI 1.10, the application&apos;s codebase used jQuery 1.7.1 and jQuery UI 1.8.3. Luckily, this didn&apos;t present a problem as everything continued to work as expected.&lt;/p&gt;
&lt;p&gt;Around this time, we also had many discussions with the Product Team about charts. Since Highcharts required we purchase a license, we took at look at &lt;a href=&quot;http://www.anychart.com/&quot;&gt;AnyChart&lt;/a&gt;, which we were already using. We were able to get AnyChart to work with our existing &lt;em&gt;chart&lt;/em&gt; directive with minimal changes. Most changes were in the JSON itself. &lt;/p&gt;
&lt;p&gt;We committed the first pass (with sample data still hard-coded) in mid-February.&lt;/p&gt;
&lt;h3 id=&quot;angular-ui-carousel&quot;&gt;Angular UI&apos;s Carousel&lt;/h3&gt;
&lt;p&gt;While finishing our initial prototype, I learned about Angular UI&apos;s &lt;a href=&quot;https://github.com/angular-ui/bootstrap/tree/master/src/carousel&quot;&gt;Carousel&lt;/a&gt;, an implementation of Bootstrap&apos;s Carousel. It required a 70% less HTML and is quite a bit easier to read. Below is the refactored carousel section.&lt;/p&gt;
&lt;pre class=&quot;brush: html&quot;&gt;
&amp;lt;carousel interval=&quot;-1&quot; class=&quot;oneup&quot;&amp;gt;
    &amp;lt;slide ng-repeat=&quot;widget in widgets | filter: {type: &apos;chart&apos;} | orderBy: &apos;order&apos;&quot; active=&quot;slide.active&quot; class=&quot;chart&quot;&amp;gt;
        &amp;lt;chart class=&quot;widget&quot; value=&quot;{{widget}}&quot; type=&quot;{{widget.chartType}}&quot;&amp;gt;&amp;lt;/chart&amp;gt;
    &amp;lt;/slide&amp;gt;
&amp;lt;/carousel&amp;gt;
&amp;lt;carousel interval=&quot;-1&quot; class=&quot;twoup&quot;&amp;gt;
    &amp;lt;slide ng-repeat=&quot;widget in widgets | filter: {type: &apos;chart&apos;} | chunk: 2 | orderBy: &apos;order&apos;&quot; active=&quot;slide.active&quot; class=&quot;chart&quot;&amp;gt;
        &amp;lt;chart class=&quot;widget&quot; value=&quot;{{widget&amp;#91;0&amp;#93;}}&quot; type=&quot;{{widget&amp;#91;0&amp;#93;.chartType}}&quot;&amp;gt;&amp;lt;/chart&amp;gt;
        &amp;lt;chart class=&quot;widget&quot; value=&quot;{{widget&amp;#91;1&amp;#93;}}&quot; type=&quot;{{widget&amp;#91;1&amp;#93;.chartType}}&quot;&amp;gt;&amp;lt;/chart&amp;gt;
    &amp;lt;/slide&amp;gt;
&amp;lt;/carousel&amp;gt;
&lt;/pre&gt;
&lt;p&gt;I was also able to remove the JavaScript that once initialized the carousel.&lt;/p&gt;
&lt;pre class=&quot;brush: diff&quot;&gt;
-    var carousel = $(&apos;.carousel&apos;);
-    $(carousel).carousel({
-        interval: 0
-    });
&lt;/pre&gt;
&lt;p&gt;While integrating this directive, I found a way to improve it by &lt;a href=&quot;https://github.com/angular-ui/bootstrap/commit/aedc05654b19342d96eabc4fc08d6a090765a48b&quot;&gt;hiding navigation indicators if there&apos;s only one slide&lt;/a&gt;. And thus my first contribution to Angular UI was born.&lt;/p&gt;
&lt;h3 id=&quot;angular-ui-sortable&quot;&gt;Angular UI&apos;s Sortable&lt;/h3&gt;
&lt;p&gt;Next, I switched from using JavaScript to Angular UI&apos;s &lt;a href=&quot;https://github.com/angular-ui/ui-sortable&quot;&gt;&lt;em&gt;sortable&lt;/em&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;to initialize drag-and-drop functionality. This was as simple as removing 5 lines of JavaScript and adding &quot;ui-sortable&quot; as an attribute to HTML tags.&lt;/p&gt;
&lt;pre class=&quot;brush: diff&quot;&gt;
&amp;lt;div class=&quot;container-widgets&quot; ng-controller=&quot;WidgetController&quot; ng-cloak&amp;gt;
     &amp;lt;div class=&quot;row-fluid&quot;&amp;gt;
         &amp;lt;div class=&quot;span9&quot;&amp;gt;
-                &amp;lt;ul class=&quot;widgets&quot;&amp;gt;
+                &amp;lt;ul class=&quot;widgets&quot; ui-sortable=&quot;{handle:&apos;.heading&apos;}&quot;&amp;gt;
                 &amp;lt;li id=&quot;summary-bar&quot;&amp;gt;
                     &amp;lt;div class=&quot;heading&quot;&amp;gt;Summary &amp;lt;a href=&apos;#&apos; class=&apos;configure&apos;&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
-                        &amp;lt;ul class=&quot;tiles&quot;&amp;gt;
+                        &amp;lt;ul class=&quot;tiles&quot; ui-sortable&amp;gt;
                         &amp;lt;li class=&quot;span3&quot; ng-repeat=&quot;widget in widgets | filter:{type: &apos;summary&apos;} | orderBy: &apos;order&apos;&quot;&amp;gt;
                             &amp;lt;h3&amp;gt;{{widget.value}}&amp;lt;/h3&amp;gt;
@@ -36,7 +36,7 @@
                 &amp;lt;/li&amp;gt;
                 &amp;lt;li id=&quot;task-bar&quot;&amp;gt;
                     &amp;lt;div class=&quot;heading&quot;&amp;gt;My Tasks &amp;lt;a href=&apos;#&apos; class=&apos;configure&apos;&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
-                        &amp;lt;ul class=&quot;tasks&quot;&amp;gt;
+                        &amp;lt;ul class=&quot;tasks&quot; ui-sortable&amp;gt;
@@ -151,55 +131,44 @@
-    $(&apos;.widgets&apos;).sortable({
-        cursor: &quot;move&quot;,
-        handle: &quot;.heading&quot;
-    }).disableSelection();
-    $(&apos;.tiles,.tasks&apos;).sortable();
&lt;/pre&gt;
&lt;p&gt;This directive uses jQuery UI under the covers, so it accepts all the same arguments you&apos;d normally use.&lt;/p&gt;
&lt;h3 id=&quot;dialogs-with-jquery&quot;&gt;Dialogs with jQuery&lt;/h3&gt;
&lt;p&gt;The next feature I implemented was a dialog that allowed end users to add/remove widgets from their dashboard. Since I knew how to do this with jQuery, that&apos;s the path I started down. I figured it&apos;d be easier to get something working quickly and then refactor to Angular later. I put the HTML for the dialog at the bottom of the page:
&lt;/p&gt;
&lt;pre class=&quot;brush: html&quot;&gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;js/move.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;js/upDown.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;div id=&quot;configure-widgets&quot; class=&quot;hidden&quot; data-title=&quot;Bar Configuration&quot; data-close=&quot;Close&quot;&amp;gt;
    &amp;lt;div class=&quot;row-fluid center&quot;&amp;gt;
        &lt;p&gt;Decide which items you would like to display and set the display order.&lt;/p&gt;
        &amp;lt;div class=&quot;span5&quot; style=&quot;margin-left: 25px&quot;&amp;gt;
            &amp;lt;label for=&quot;available-widgets&quot; class=&quot;bold&quot;&amp;gt;Available Widgets&amp;lt;/label&amp;gt;
            &amp;lt;select size=10 id=&quot;available-widgets&quot; multiple class=&quot;width100pr&quot;&amp;gt;&amp;lt;/select&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&quot;span1 arrows&quot; style=&quot;padding-top: 50px&quot;&amp;gt;
            &amp;lt;img src=&quot;images/arrow_up.png&quot; class=&quot;arrow arrow-up&quot; alt=&quot;Move Up&quot; onclick=&quot;return moveUp($(&apos;#assigned-widgets&apos;)&amp;#91;0&amp;#93;);&quot;/&amp;gt;
            &amp;lt;img src=&quot;images/arrow_right.png&quot; class=&quot;arrow arrow-right&quot; alt=&quot;Move Right&quot; onclick=&quot;return move($(&apos;#available-widgets&apos;)&amp;#91;0&amp;#93;, $(&apos;#assigned-widgets&apos;)&amp;#91;0&amp;#93;);&quot;/&amp;gt;
            &amp;lt;img src=&quot;images/arrow_left.png&quot; class=&quot;arrow arrow-left&quot; alt=&quot;Move Left&quot; onclick=&quot;return move($(&apos;#assigned-widgets&apos;)&amp;#91;0&amp;#93;, $(&apos;#available-widgets&apos;)&amp;#91;0&amp;#93;);&quot;/&amp;gt;
            &amp;lt;img src=&quot;images/arrow_down.png&quot; class=&quot;arrow arrow-down&quot; alt=&quot;Move Down&quot; onclick=&quot;return moveDown($(&apos;#assigned-widgets&apos;)&amp;#91;0&amp;#93;);&quot;/&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&quot;span5&quot;&amp;gt;
            &amp;lt;label for=&quot;assigned-widgets&quot; class=&quot;bold&quot;&amp;gt;Assigned Widgets&amp;lt;/label&amp;gt;
            &amp;lt;select size=10 id=&quot;assigned-widgets&quot; multiple class=&quot;width100pr&quot;&amp;gt;&amp;lt;/select&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Then I changed the &lt;code&gt;WidgetController&lt;/code&gt; to split the &lt;code&gt;widgets&lt;/code&gt; variable into variables for each widget type.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
+    var filter = $filter(&apos;filter&apos;);
+    var orderBy = $filter(&apos;orderBy&apos;);
+
+    $scope.summaryWidgets = filterData($scope.widgets, {type: &apos;summary&apos;}, filter, orderBy);
+    $scope.taskWidgets = filterData($scope.widgets, {type: &apos;task&apos;}, filter, orderBy);
+    $scope.chartWidgets = filterData($scope.widgets, {type: &apos;chart&apos;}, filter, orderBy);
+}
+
+function filterData(array, query, filter, orderBy) {
+    var data = filter(array, query);
+    return orderBy(data, &apos;order&apos;);
+}
&lt;/pre&gt;
&lt;p&gt;Finally, I added a new &lt;em&gt;config&lt;/em&gt; directive and hooked it into the page by adding &lt;em&gt;config=&quot;type&quot; &lt;/em&gt;to each heading (e.g. &lt;code&gt;&amp;lt;div class=&quot;heading&quot; config=&quot;task&quot;&amp;gt;My Tasks&amp;lt;/div&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;

.directive(&apos;config&apos;, function ($sanitize, $filter) {
    return {
        restrict: &apos;A&apos;,
        link: function (scope, element, attrs) {
            var configBtn = $(&apos;&amp;lt;a href=&quot;#&quot;/&amp;gt;&apos;).addClass(&apos;configure&apos;);
            configBtn.appendTo(element);
            var widgets = scope&amp;#91;attrs.config + &apos;Widgets&apos;&amp;#93;;
             
            // availableWidgets is defined as a global variable embedded in the page
            var allWidgets = availableWidgets; 
            $(configBtn).on(&apos;click&apos;, function (e) {
                e.preventDefault();
                var configDialog = $(&apos;#configure-widgets&apos;);
                var availableWidgets = $(&apos;#available-widgets&apos;);
                availableWidgets.empty();
                var filter = $filter(&apos;filter&apos;);
                var orderBy = $filter(&apos;orderBy&apos;);
                allWidgets = filter(allWidgets, {type: attrs.config});
                allWidgets = orderBy(allWidgets, &apos;order&apos;);
                var unselectedWidgets = jQuery.grep(allWidgets, function(item) {
                    return jQuery.inArray(item, widgets) &amp;lt; 0;
                });
                $.each(unselectedWidgets, function(index, item) {
                    var title = (item.title) ? item.title.replace(/&amp;amp;quot;/g, &apos;&quot;&apos;) : &apos;No Title&apos;;
                    availableWidgets.append(new Option(title, item.id));
                });
                var assignedWidgets = $(&apos;#assigned-widgets&apos;);
                assignedWidgets.empty();
                $.each(widgets, function(index, item) {
                    var title = (item.title) ? item.title.replace(/&amp;amp;quot;/g, &apos;&quot;&apos;) : &apos;No Title&apos;;
                    assignedWidgets.append(new Option(title, item.id));
                });
                configDialog.dialog({
                    title: $(element).text() + &apos; &apos; + configDialog.attr(&apos;data-title&apos;),
                    width: 600,
                    modal: true,
                    buttons: &amp;#91;{
                            text: configDialog.attr(&apos;data-close&apos;),
                            &apos;class&apos;: &apos;btn&apos;,
                            click: function() {
                                $(this).dialog(&quot;close&quot;);
                            }
                        }&amp;#93;
                });
            });
        }
    }
})
&lt;/pre&gt;
&lt;p&gt;As you can tell, this is quite a bit of code, and it doesn&apos;t even show you the JavaScript in move.js and upDown.js (included at the top of the dialog HTML). While writing this code, I could tell that I was not doing things the &lt;em&gt;Angular Way&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To refactor, I did some research, found the &lt;a href=&quot;https://github.com/angular-ui/bootstrap/tree/master/src/dialog&quot;&gt;$dialogProvider&lt;/a&gt; service and went to work.&lt;/p&gt;
&lt;h3 id=&quot;dialogs-with-angular&quot;&gt;Dialogs with Angular&lt;/h3&gt;
&lt;p&gt;I started by refactoring the &lt;em&gt;config&lt;/em&gt; directive to be much shorter.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
.directive(&apos;config&apos;, function() {
    return {
        restrict: &apos;A&apos;,
        link: function (scope, element, attrs) {
            var configBtn = $(&apos;&amp;lt;a href=&quot;&quot;/&amp;gt;&apos;).addClass(&apos;configure&apos;);
            configBtn.appendTo(element);
            configBtn.bind(&apos;click&apos;, function(e) {
                e.preventDefault();
                e.stopPropagation();
                scope.$apply(scope.configureDialog(attrs.config, $(element).text()))
            });
        }
    }
})
&lt;/pre&gt;
&lt;p&gt;Line #10 that starts with &lt;code&gt;scope.$apply&lt;/code&gt; is what makes the magic happens.This calls the &lt;code&gt;configureDialog()&lt;/code&gt; function in &lt;code&gt;WidgetController&lt;/code&gt;. The &lt;code&gt;$dialog&lt;/code&gt; service you see below is injected by adding it as a parameter to the &lt;code&gt;WidgetController&lt;/code&gt; function.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;

$scope.configureDialog = function (type, title) {
    var dialog = $dialog.dialog({
        dialogClass: &apos;modal draggable&apos;,
        modalFade: false,
        backdropClick: true,
        controller: &apos;ConfigController&apos;,
        template: $(&apos;#configure-widgets&apos;).html(),
        resolve: {
            title: function() {
                return title;
            },
            hiddenItems: function () {
                return Widget.getHiddenWidgets(type);
            },
            items: function () {
                return angular.copy($scope&amp;#91;type + &apos;Widgets&apos;&amp;#93;);
            }
        }
    });
    dialog.open().then(function(results) {
        if (!angular.isUndefined(results)) {
            $scope&amp;#91;type + &apos;Widgets&apos;&amp;#93; = results.items;
            Preferences.saveWidgetPreferences(type, results);
        }
    });
};
&lt;/pre&gt;
&lt;div class=&quot;alert alert-info&quot;&gt;
&lt;p style=&quot;margin-top: 0&quot;&gt;&lt;strong&gt;draggable directive&lt;/strong&gt;&lt;br/&gt;
If you look closely, you&apos;ll see this dialog is initialized with a &apos;draggable&apos; class. I created a &lt;em&gt;draggable &lt;/em&gt;directive that gives draggability using jQuery UI to any elements with this class.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
.directive(&apos;draggable&apos;, function() {
    return {
        restrict: &apos;C&apos;,
        link: function(scope, elem, attr, ctrl) {
            elem.draggable({handle: &apos;.modal-header&apos;});
        }
    };
});
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The interesting parts of this file are the &lt;strong&gt;controller&lt;/strong&gt;, &lt;strong&gt;template&lt;/strong&gt;, and &lt;strong&gt;resolve&lt;/strong&gt; parameters. The &lt;strong&gt;controller&lt;/strong&gt; is just another function in &lt;em&gt;controllers.js&lt;/em&gt;, the &lt;strong&gt;template&lt;/strong&gt; is HTML in the page (so text could be i18n-ized) and &lt;strong&gt;resolve&lt;/strong&gt; has the variables to pass to the controller. &lt;code&gt;Widget&lt;/code&gt; and &lt;code&gt;Preferences&lt;/code&gt; are services I&apos;ll talk about in the Part 3. The reason angular.copy() is used is so the widget arrays aren&apos;t modified while the dialog is displayed (we want to wait until the user clicks &quot;Save&quot;).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ConfigController&lt;/code&gt; function started quite simply:&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
function ConfigController($scope, $sanitize, dialog, title, hiddenItems, items) {
    $scope.title = title;
    $scope.hiddenItems = hiddenItems;
    $scope.items = items;
}
&lt;/pre&gt;
&lt;p&gt;The HTML (defined by the aforementioned &lt;strong&gt;template&lt;/strong&gt; parameter) is as follows. You can see that &lt;em&gt;title&lt;/em&gt;, &lt;em&gt;hiddenItems&lt;/em&gt; and &lt;em&gt;items&lt;/em&gt; are the variables defined in $scope and used to render the data.&lt;/p&gt;
&lt;pre class=&quot;brush: html&quot;&gt;
&amp;lt;div id=&quot;configure-widgets&quot; class=&quot;modal hidden&quot;&amp;gt;
    &amp;lt;div class=&quot;modal-header&quot; style=&quot;border: 0&quot;&amp;gt;
        &amp;lt;button type=&quot;button&quot; class=&quot;close&quot; ng-click=&quot;close(false)&quot; aria-hidden=&quot;true&quot; style=&quot;margin-top: -3px&quot;&amp;gt;&amp;amp;times;&amp;lt;/button&amp;gt;
        &amp;lt;h4&amp;gt;{{title}} Bar Configuration&amp;lt;/h4&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;modal-body&quot;&amp;gt;
        &lt;p&gt;Decide which items you would like to display and set the display order.&lt;/p&gt;
        &amp;lt;div class=&quot;row-fluid center&quot;&amp;gt;
            &amp;lt;div class=&quot;span4&quot; style=&quot;width: 320px; margin-left: 25px&quot;&amp;gt;
                &amp;lt;label for=&quot;available-widgets&quot; class=&quot;bold&quot;&amp;gt;Available Widgets&amp;lt;/label&amp;gt;
                &amp;lt;select size=10 id=&quot;available-widgets&quot; ng-model=&quot;items.available&quot; ng-options=&quot;i.title for i in hiddenItems&quot;
                        class=&quot;width100pr&quot; multiple=&quot;multiple&quot;&amp;gt;&amp;lt;/select&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;span1 arrows&quot; style=&quot;padding-top: 50px&quot;&amp;gt;
                &amp;lt;img src=&quot;images/arrow_up.png&quot; class=&quot;arrow arrow-up&quot; alt=&quot;Move Up&quot; ng-click=&quot;moveUp(items.selected, items)&quot;/&amp;gt;
                &amp;lt;img src=&quot;images/arrow_right.png&quot; class=&quot;arrow arrow-right&quot; alt=&quot;Move Right&quot; ng-click=&quot;moveItem(items.available, hiddenItems, items)&quot;/&amp;gt;
                &amp;lt;img src=&quot;images/arrow_left.png&quot; class=&quot;arrow arrow-left&quot; alt=&quot;Move Left&quot; ng-click=&quot;moveItem(items.selected, items, hiddenItems)&quot;/&amp;gt;
                &amp;lt;img src=&quot;images/arrow_down.png&quot; class=&quot;arrow arrow-down&quot; alt=&quot;Move Down&quot; ng-click=&quot;moveDown(items.selected, items)&quot;/&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;span4&quot; style=&quot;width: 320px&quot;&amp;gt;
                &amp;lt;label for=&quot;assigned-widgets&quot; class=&quot;bold&quot;&amp;gt;Assigned Widgets&amp;lt;/label&amp;gt;
                &amp;lt;select size=10 id=&quot;assigned-widgets&quot; ng-model=&quot;items.selected&quot; ng-options=&quot;i.title for i in items&quot;
                        class=&quot;width100pr&quot; multiple=&quot;multiple&quot;&amp;gt;&amp;lt;/select&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;modal-footer&quot;&amp;gt;
        &amp;lt;button ng-click=&quot;close(true)&quot; class=&quot;btn btn-primary&quot;&amp;gt;Save and Close&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;There&apos;s a couple of new directives introduced by this code: &lt;em&gt;ngOptions&lt;/em&gt;&amp;nbsp;and &lt;em&gt;ngClick&lt;/em&gt;. The former is used to display options in a &amp;lt;select&amp;gt;, the latter to call functions in the controller. These functions are defined in &lt;code&gt;ConfigController&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
$scope.moveUp = function(items, list) {
    angular.forEach(items, function(item) {
        var idx = list.indexOf(item);
        if (idx != -1) {
            list.splice(idx - 1, 0, list.splice(idx, 1)[0]);
        }
    });
};

$scope.moveDown = function(items, list) {
    angular.forEach(items, function(item) {
        var idx = list.indexOf(item);
        if (idx != -1) {
            list.splice(idx + 1, 0, list.splice(idx, 1)[0]);
        }
    });
};

$scope.moveItem = function(items, from, to) {
    angular.forEach(items, function(item) {
        var idx = from.indexOf(item);
        if (idx != -1) {
            from.splice(idx, 1);
            to.push(item);
        }
    });
};

$scope.close = function(save) {
    if (save) {
        dialog.close({
            hidden: $scope.hiddenItems,
            items: $scope.items
        });
    } else {
        dialog.close();
    }
};
&lt;/pre&gt;
&lt;p&gt;As you can see, Angular allows you to easily access and manipulate the data. Its two-way binding feature is great because when you modify the object in JavaScript, it auto-updates the displayed HTML.The only thing you need to do to the HTML is to add the &lt;a href=&quot;http://docs.angularjs.org/api/ng.directive:ngModel&quot;&gt;&lt;em&gt;ngModel&lt;/em&gt;&lt;/a&gt; directive.&lt;/p&gt;
&lt;pre class=&quot;brush: html&quot;&gt;
&amp;lt;ul class=&quot;tasks&quot; ng-model=&quot;taskWidgets&quot; ui-sortable&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The dialog&apos;s &lt;code&gt;close()&lt;/code&gt; method is called in the header (where it passes false) and in the footer (where it passes true). The &lt;code&gt;configureDialog()&lt;/code&gt; function handles saving if the user indicates they wanted to do so. The 3rd line (starts with $scope) is all that&apos;s needed to update the UI. The Preferences service is covered in the next article.&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
dialog.open().then(function(results) {
    if (!angular.isUndefined(results)) {
        $scope[type + &apos;Widgets&apos;] = results.items;
        Preferences.saveWidgetPreferences(type, results);
    }
});
&lt;/pre&gt;
&lt;h3 id=&quot;modals-with-data&quot;&gt;Modals with Data&lt;/h3&gt;
&lt;p&gt;Displaying the widgets in a consolidated dashboard is a nice product feature, but we wanted to take it a step further and allow users to &quot;click through&quot; to see the data. To do this, I added an &quot;event&quot; directive that could read from our JSON data and act upon it accordingly. We decided on 2 types of events: &lt;strong&gt;function&lt;/strong&gt; and &lt;strong&gt;href&lt;/strong&gt;. The &lt;strong&gt;href&lt;/strong&gt; event type is for report widgets, because we want to allow users to click on the widget and it takes them directly to the report. For &lt;strong&gt;function&lt;/strong&gt;, we simply &lt;em&gt;eval()&lt;/em&gt; what&apos;s passed in. The function is expected to have a &lt;em&gt;container&lt;/em&gt; argument that it can use to render data in a modal window.&lt;/p&gt;
&lt;p&gt;Using the &lt;em&gt;event&lt;/em&gt; directive, you can attach this behavior to a widget simply by adding a class.&lt;/p&gt;
&lt;pre class=&quot;brush: html&quot;&gt;
&amp;lt;h3 class=&quot;events&quot;&amp;gt;{{widget.value}}&amp;lt;/h3&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;event&lt;/em&gt; directive that attaches click behavior is below:&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
directive(&apos;events&apos;, function () {
    // This is necessary because widgets may be chunked when charts are displayed 2-up
    function getWidget(element, widget, scope) {
        if (element.hasClass(&apos;chart-title&apos;)) {
            if (element.parent().hasClass(&apos;first&apos;)) {
                widget = scope.widget[0];
            } else if (element.parent().hasClass(&apos;second&apos;)) {
                widget = scope.widget[1];
            } else {
                widget = scope.widget;
            }
        } else {
            widget = scope.widget;
        }
        return widget;
    }
    return {
        restrict: &apos;C&apos;,
        link: function (scope, element, attrs) {
            var widget = getWidget(element, widget, scope);
            if (angular.isUndefined(widget)) {
                return;
            }
            var events = widget.events;
            if (!angular.isUndefined(events)) {
                for (var e in events) {
                    if (e === &apos;function&apos;) {
                        if ($(&apos;#dialog-frame&apos;).length === 0) {
                            $(&apos;&amp;lt;div id=&quot;dialog-frame&quot; class=&quot;modal hide&quot;/&amp;gt;&apos;).appendTo(&apos;body&apos;);
                            var header = $(&apos;&amp;lt;div class=&quot;modal-header&quot;&amp;gt;&apos;);
                            header.append($(&apos;&amp;lt;button type=&quot;button&quot; class=&quot;close&quot; data-dismiss=&quot;modal&quot;&amp;gt;&amp;times;&amp;lt;/button&amp;gt;&apos;));
                            header.append($(&apos;&amp;lt;h4/&amp;gt;&apos;).append(scope.widget.title));
                            header.appendTo(&apos;#dialog-frame&apos;);
                            $(&apos;&amp;lt;div class=&quot;modal-body&quot;/&amp;gt;&apos;).appendTo(&apos;#dialog-frame&apos;);
                        }
                        element.bind(&apos;click&apos;, function(event) {
                            event.preventDefault();
                            event.stopPropagation();
                            var dialog = $(&apos;#dialog-frame&apos;);
                            var title = widget.title;
                            dialog.find(&apos;h4&apos;).html(title);
                            var dialogBody = dialog.find(&apos;.modal-body&apos;);
                            dialogBody.empty();
 
                            // display a checking for new data message when widget&apos;s value is 0
                            var checkingMessage = $(&apos;#wait-checking&apos;).html();
                            if (scope.widget.value === &quot;0&quot;) {
                                dialogBody.html(checkingMessage);
                            // otherwise, display a loading message
                            } else {
                                dialogBody.html($(&apos;#wait-loading&apos;).html());
                            }
 
                            // center the dialog on the page
                            dialog.css({
                                width: &apos;560px&apos;,
                                &apos;margin-left&apos;: function() {
                                    return -($(this).width() / 2);
                                }
                            });
 
                            dialog.modal(&apos;show&apos;);
                            var container = dialogBody;
                            eval(events[e]);
                        });
                    } else if (e === &quot;href&quot;) {
                        element.bind(&apos;click&apos;, function() {
                            location.href = events[e];
                        })
                    } else {
                        console.log(&apos;Event type &quot;&apos; + e + &apos;&quot; not supported.&apos;);
                    }
                }
            }
        }
    }
})
&lt;/pre&gt;
&lt;h3 id=&quot;empty-widgets-message&quot;&gt;Empty Widgets Message&lt;/h3&gt;
&lt;p&gt;When there are no widgets for a particular type, we wanted to display a message telling the end user. To do this, I used the &lt;a href=&quot;http://docs.angularjs.org/api/ng.directive:ngHide&quot;&gt;&lt;em&gt;ngHide&lt;/em&gt;&lt;/a&gt; directive and passed in the array&apos;s length as an expression. I originally had this on a &amp;lt;li&amp;gt; in the respective widget list, but noticed it causes issues when dragging and dropping.&lt;/p&gt;
&lt;pre class=&quot;brush: html&quot;&gt;
&amp;lt;div ng-hide=&quot;summaryWidgets.length&quot; class=&quot;widgets-empty&quot;&amp;gt;
    No Summary Bar Widgets currently visible
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;This article has provided an overview of how I changed some of My Dashboard&apos;s features to use Angular instead of jQuery. I hope it&apos;s helped to show how powerful directives can be and how MVC works in Angular. I particularly enjoyed learning how to use the $dialog service. As a word of warning, its usage might change in future releases since it is currently being &lt;a href=&quot;https://github.com/angular-ui/bootstrap/issues/441&quot;&gt;rewritten to be more maintainable&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_with_angularjs_part_iii&quot;&gt;next article&lt;/a&gt;, I&apos;ll talk about how I developed Services and integrated DWR. If you see any code that can be improved upon, or issues with the code/architecture in this article, please leave a comment.&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/devoxx_france_a_great_conference</id>
        <title type="html">Devoxx France: A Great Conference in a Magnificent City</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/devoxx_france_a_great_conference"/>
        <published>2013-03-29T13:14:30-06:00</published>
        <updated>2014-05-08T19:47:26-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="travel" scheme="http://roller.apache.org/ns/tags/" />
        <category term="paradoxofchoice" scheme="http://roller.apache.org/ns/tags/" />
        <category term="trish" scheme="http://roller.apache.org/ns/tags/" />
        <category term="france" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxxfr" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="play" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;a href=&quot;http://www.flickr.com/photos/mcginityphoto/8614997207/&quot; title=&quot;Red Eiffel flowers by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm9.staticflickr.com/8386/8614997207_7320dec749_t.jpg&quot; width=&quot;66&quot; height=&quot;100&quot; alt=&quot;Red Eiffel flowers&quot; class=&quot;picture&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

This week, my &lt;a href=&quot;http://mcginityphoto.com&quot;&gt;lovely fianc&#233;&lt;/a&gt; and I traveled to the &lt;a href=&quot;http://en.wikipedia.org/wiki/Paris&quot;&gt;City of Light&lt;/a&gt;. Our journey was designed around some speaking engagements at Devoxx France. Devoxx is one of my favorite conference franchises and Devoxx France has been special to me ever since the Devoxx (Belgium) I spoke at in 2011. 
&lt;/p&gt;
&lt;p&gt;
2011 was the year I spoke about &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_html5_with_play_scala&quot;&gt;my experience with Play, Scala, CoffeeScript and Jade&lt;/a&gt;. I wrote the presentation on my flight over, composed the demo video the night before and made it all happen in the nick of time. Of course, this was after 120 hours of research and preparation, so the presentation composition process had all the data I needed. You can imagine my sense of relief after pulling off that talk and getting an enthusiastic applause from the audience for my efforts. 
&lt;/p&gt;
&lt;p&gt;
One of the first audience questions I received was from &lt;a href=&quot;https://twitter.com/nmartignole&quot;&gt;Nicolas Martignole&lt;/a&gt;, asking if I&apos;d speak at Devoxx France the following year. I whole-heartedly agreed to do it and was excited for the opportunity. It was with great disappointment that I later found out I couldn&apos;t attend Devoxx France in 2012. My client didn&apos;t like me taking so much time off and I agreed to scale my two week vacation back to &lt;a href=&quot;http://raibledesigns.com/rd/entry/cruising_around_the_western_caribbean&quot;&gt;1 week&lt;/a&gt;. This year, I was determined to go, so I submitted some of my favorite talks: Comparing JVM Web Frameworks and The Play vs. Grails Smackdown with &lt;a href=&quot;http://www.jamesward.com/&quot;&gt;James Ward&lt;/a&gt;. I was extremely pleased when they both got accepted.
&lt;/p&gt;
&lt;p&gt;
Side Story: I met Martin Odersky shortly when he sat down next to me for the Java Posse presentation in Belgium in 2011. After shaking his hand and introducing myself, I had to politely ask him to leave because it was Trish&apos;s seat. Talk about awkward; but Martin was very gracious and promptly found a new seat close by.
&lt;/p&gt;
&lt;p id=&quot;comparing-jvm-web-frameworks&quot;&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/The_Paradox_of_Choice:_Why_More_Is_Less&quot; title=&quot;The Paradox of Choice&quot;&gt;&lt;img src=&quot;//farm9.staticflickr.com/8102/8600235023_dc4753c0aa_t.jpg&quot; width=&quot;65&quot; height=&quot;100&quot; alt=&quot;The Paradox of Choice&quot; class=&quot;picture&quot;&gt;&lt;/a&gt;
&lt;strong&gt;Comparing JVM Web Frameworks&lt;/strong&gt;&lt;br/&gt;
Both talks required a bit of updating. For Comparing JVM Web Frameworks, I started reading &lt;a href=&quot;http://en.wikipedia.org/wiki/The_Paradox_of_Choice:_Why_More_Is_Less&quot;&gt;The Paradox of Choice&lt;/a&gt; and found many parallels to the agony that developers experience with choosing a web framework. I described how I didn&apos;t think good framework decisions were based on the many, many features that frameworks have, but often on pre-defined constraints. There&apos;s those lucky developers that get to choose a Full Stack Framework because they&apos;re doing greenfield development. Then there&apos;s those that want a better &lt;em&gt;Pure&lt;/em&gt; Web Framework that replaces something (e.g. Struts) that&apos;s not satisfying their needs. And lastly, there&apos;s those that&apos;ve found it possible to leverage a &lt;abbr title=&quot;Service Oriented Front End Architecture&quot;&gt;SOFEA&lt;/abbr&gt; and use a JavaScript MVC framework with an API Framework on the backend. I don&apos;t think it makes sense to compare &lt;em&gt;all&lt;/em&gt; web frameworks and I tried to use these pre-defined constraints (language, platform and application type) argument to separate into categories and help make choosing easier. 
&lt;/p&gt;
&lt;p&gt;
I took out the parts of the presentation that&apos;ve pissed people off in the past - particular the JSF bashing by James Gosling, the Rails gushing from Craig McClanahan and the Pros and Cons sections of each framework. I added the &lt;a href=&quot;https://www.flickr.com/photos/mraible/8588701778&quot;&gt;history of web frameworks&lt;/a&gt; and research from &lt;a href=&quot;http://www.infoq.com/research/jvm-web-frameworks&quot;&gt;InfoQ&lt;/a&gt; and &lt;a href=&quot;http://devrates.com/project/list?query=%5Bweb+framework%5D&quot;&gt;devrates.com&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a data-url=&quot;http://www.flickr.com/photos/mraible/8588701778/&quot; href=&quot;https://farm9.staticflickr.com/8529/8588701778_91aeb65377_o.png&quot; title=&quot;History of Web Frameworks 2013&quot; rel=&quot;lightbox[devoxxfr-2013]&quot;&gt;&lt;img src=&quot;//farm9.staticflickr.com/8529/8588701778_0fb17b5612.jpg&quot; width=&quot;500&quot; height=&quot;223&quot; alt=&quot;History of Web Frameworks 2013&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
The best part of the JVM Web Frameworks talk was the audience&apos;s reaction and enthusiasm. Devoxx always seems to attract passionate developers and Devoxx France was no different. Developers packing the room, clapping after your intro, laughing at your jokes, signifying that they agree with you about JSF. As a speaker, it&apos;s an unbelievable experience.
&lt;/p&gt;
&lt;p&gt;
You can view my Comparing JVM Web Frameworks presentation below or &lt;a href=&quot;http://www.slideshare.net/mraible/comparing-jvm-web-frameworks-devoxx-france-2013&quot;&gt;on Slideshare.net&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/17868398?rel=0&quot; width=&quot;512&quot; height=&quot;325&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px&quot; allowfullscreen webkitallowfullscreen mozallowfullscreen&gt; &lt;/iframe&gt;
&lt;/p&gt;
&lt;p id=&quot;play-vs-grails-smackdown&quot;&gt;&lt;strong&gt;Play Frameworks vs. Grails Smackdown&lt;/strong&gt;&lt;br/&gt;
To prepare for James Ward and my Play vs. Grails Smackdown, we had a number of goals. First of all, we wanted to update our apps to use the latest versions of each framework. I &lt;a href=&quot;http://raibledesigns.com/rd/entry/upgrading_grails_from_2_0&quot;&gt;documented what it took for Grails&lt;/a&gt;, James just &lt;a href=&quot;https://github.com/jamesward/happytrails/commit/6b674e6b8998b0996869cf510dae71a199deec07&quot;&gt;checked in his code&lt;/a&gt; to GitHub. It was interesting to see that Grails 2.0.3 -&gt; 2.2.1 caused a number of issues with testing, while Play 2.0.3 -&gt; Play 2.1.0 required API changes, but nothing for tests. Secondly, we &lt;a href=&quot;https://github.com/jamesward/happytrails/commit/43795059fcd3d321ab93ea14dc149a3c762daf47&quot;&gt;updated all the stats&lt;/a&gt; for our pretty graphs and &lt;a href=&quot;https://github.com/jamesward/happytrails/commit/9654e74e61c03ccd916ee839885503e206339c81&quot;&gt;ran load tests again&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
This is where the fun started. On Tuesday evening, I decided to challenge the notion that Play was twice as fast as Grails. James had proven this with &lt;a href=&quot;http://httpd.apache.org/docs/2.2/programs/ab.html&quot;&gt;Apache Bench&lt;/a&gt; tests. With Play 2.0 and Grails 2.0 (last summer), we clocked Play at 251/requests per second and 198 for Grails. After upgrading each app to the latest releases, we found the numbers to be 233/second for Play and 118 for Grails. 
&lt;/p&gt;
&lt;p&gt;
However, Apache Bench only tests until the first byte is received. Since I&apos;ve done a lot of browser optimizations recently, I fired up &lt;a href=&quot;http://whichloadsfaster.com&quot;&gt;whichloadsfaster.com&lt;/a&gt;, captured a screenshot and &lt;a href=&quot;https://github.com/jamesward/happytrails/commit/5e867a85279d4be0736c4843704646d55e7eacd7&quot;&gt;added it to our presentation&lt;/a&gt;. The next day, James &lt;a href=&quot;https://github.com/jamesward/happytrails/commit/1f15b8c06a5b7b298b111f263f3c26197fbee096&quot;&gt;added a CDN&lt;/a&gt; and a &lt;a href=&quot;https://github.com/jamesward/happytrails/commit/ab532444258f494d40a7126716c6ac7190b80a98&quot;&gt;bunch of caching&lt;/a&gt; to his app and re-ran his AB tests. 
&lt;/p&gt;
&lt;p&gt;
Now he was &lt;em&gt;smoking&lt;/em&gt; Grails, so I &lt;a href=&quot;https://github.com/jamesward/happytrails/commit/ea911b60e17837a6d6b5359e1e616bec43013ddd&quot;&gt;added a CDN&lt;/a&gt; and &lt;a href=&quot;https://github.com/jamesward/happytrails/commit/da776a16ce6ac17eb65d66cb8a206b18a44a6536&quot;&gt;caching&lt;/a&gt; as well. However, the best I could do was just over 1000/requests per second, while he was around 2200/second. When he ran live tests during our talk, Play was around 2800/sec and Grails was around 900.
&lt;/p&gt;
&lt;p&gt;
It was great to see how much better performance we could get with caching and a CDN. The best part is this should be available to most applications, not just these frameworks. By adding a CDN (we used Amazon CloudFront) and caching, we were both able to 10x the performance of our apps. You can find our presentation &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/Play_vs_Grails_Smackdown_DevoxxFrance2013/&quot;&gt;here&lt;/a&gt; or view it below.
&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//static.raibledesigns.com/repository/presentations/Play_vs_Grails_Smackdown_DevoxxFrance2013/&quot; width=&quot;500&quot; height=&quot;375&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; allowfullscreen webkitallowfullscreen mozallowfullscreen style=&quot;border:1px solid #CCC;margin-bottom:5px&quot;&gt; &lt;/iframe&gt;
&lt;/p&gt;

&lt;p id=&quot;summary&quot;&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
This was a very enjoyable conference to attend as a speaker. First of all, it was in one of the most beautiful cities in the world, but it&apos;s also a very special place for Trish and I. &lt;a href=&quot;http://raibledesigns.com/rd/entry/our_engaging_trip_to_paris&quot;&gt;We got engaged just outside of Paris in Versailles&lt;/a&gt; after the &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_html5_with_play_scala&quot;&gt;last Devoxx conference&lt;/a&gt; I spoke at. Trish has some &lt;a href=&quot;http://www.mcginityphoto.com/Other/MattandTrishengagementPhotos&quot;&gt;amazing photos&lt;/a&gt; from that trip. Secondly, the Devoxx conference attracts a special kind of developer - one that is passionate about and eager for knowledge. Lastly, speaking with my good friend James, in an exotic city about something we love - that was special. Asking for beers and having them brought to us at the start of our Smackdown. That was magical (thanks Nicolas!). 
&lt;/p&gt;
&lt;p&gt;
To all the Devoxx organizers and crew - well done on a great show!&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/the_modern_java_web_developer</id>
        <title type="html">The Modern Java Web Developer and Java Web Security at Denver JUG</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/the_modern_java_web_developer"/>
        <published>2013-02-14T10:23:18-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="denverjug" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="denver" scheme="http://roller.apache.org/ns/tags/" />
        <category term="web" scheme="http://roller.apache.org/ns/tags/" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last night, I had the pleasure of delivering two talks at the &lt;a href=&quot;http://www.meetup.com/DenverJavaUsersGroup/events/93932082/&quot;&gt;Denver Java User Group&lt;/a&gt;. The first talk, The Modern Java Web Developer, was inspired by the book titled &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_well_grounded_java_developer&quot;&gt;The Well-Grounded Java Developer&lt;/a&gt;. &lt;a href=&quot;http://boxcatjunction.blogspot.com/&quot;&gt;Ben Evans&lt;/a&gt; and &lt;a href=&quot;http://martijnverburg.blogspot.com/&quot;&gt;Martijn Verburg&lt;/a&gt; mention in the beginning of the book that they wrote it as a training guide to get new Java developers up to speed. For my talk, I wanted to do something similar, but for Java Web Developers.&lt;/p&gt;
&lt;p&gt;I mentioned that the first thing you have to do to become modern is to change your title from a Java Web Developer to a &lt;em&gt;JVM&lt;/em&gt; Web Developer. After doing that, you have a whole slew of new and wonderful technologies at your disposal. From there, I believe the Modern JVM Web Developer: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Starts with Fast Hardware&lt;/li&gt;
&lt;li&gt;Uses IntelliJ IDEA&lt;/li&gt;
&lt;li&gt;Leverages jQuery, HTML5, and CSS3&lt;/li&gt;
&lt;li&gt;Creates High Performance Web Sites&lt;/li&gt;
&lt;li&gt;For Mobile Devices&lt;/li&gt;
&lt;li&gt;In the Cloud&lt;/li&gt;
&lt;li&gt;And cares about Security&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/16515789&quot; width=&quot;514&quot; height=&quot;422&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px; &quot; allowfullscreen webkitallowfullscreen mozallowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;You can also &lt;a href=&quot;http://www.slideshare.net/mraible/the-modern-java-web-developer-denver-jug-2013&quot;&gt;view this presentation on Slideshare&lt;/a&gt; or &lt;a href=&quot;http://raibledesigns.com/rd/page/publications&quot;&gt;download it from my presentations page&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;
The second talk was on Java Web Application Security and was largely an updated version of the talk I gave a couple years ago, starting with &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part&quot;&gt;an appearance at the Utah JUG&lt;/a&gt;. It was mostly a live demo session using my &lt;a href=&quot;https://github.com/mraible/ajax-login&quot;&gt;Ajax Login&lt;/a&gt; application. To prepare the project for this talk, I created &lt;a href=&quot;https://github.com/mraible/ajax-login/branches&quot;&gt;branches for each step&lt;/a&gt;. This means you can checkout the &quot;baseline&quot; branch and use Git to compare it with the &quot;javaee&quot; branch. You can also compare the &quot;spring-security&quot; branch vs. the &quot;apache-shiro&quot; branch. Finally, you could see &lt;a href=&quot;https://github.com/mraible/ajax-login/commit/9a45b74b0b1c85c3e02f3824bc57f0cf76423000&quot;&gt;what I needed to do&lt;/a&gt; to fix many of the vulnerabilities found by &lt;a href=&quot;https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project&quot;&gt;Zed Attack Proxy&lt;/a&gt;. &lt;/p&gt;

&lt;div style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/16515810&quot; width=&quot;514&quot; height=&quot;422&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px&quot; allowfullscreen webkitallowfullscreen mozallowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;You can also &lt;a href=&quot;http://www.slideshare.net/mraible/java-web-application-security-denver-jug-2013&quot;&gt;view this presentation on Slideshare&lt;/a&gt; or &lt;a href=&quot;http://raibledesigns.com/rd/page/publications&quot;&gt;download it from my presentations page&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Thanks to the DJUG and &lt;a href=&quot;http://www.businessatthrive.com/v3/&quot;&gt;Thrive&lt;/a&gt; folks for providing good beer (especially the Guinness!) and &lt;a href=&quot;http://www.fullcontact.com/&quot;&gt;FullContact&lt;/a&gt; for hosting. Also, I&apos;d like to thank Manning for the copies of &lt;a href=&quot;http://manning.com/evans/&quot;&gt;The Well-Grounded Java Developer&lt;/a&gt; they sent and No Starch Press for copies of Michal Zalewsky&apos;s &lt;a href=&quot;http://lcamtuf.coredump.cx/tangled/&quot;&gt;The Tangled Web: A Guide to Securing Modern Web Applications&lt;/a&gt;. Last, but certainly not least, thanks to all the good people who attended and listened to me ramble on about all this cool technology.&lt;/p&gt;
&lt;p&gt;
Future speaking engagements include &lt;a href=&quot;http://www.devoxx.com/display/FR13/Matt+Raible&quot;&gt;Devoxx France&lt;/a&gt; in March and Denver&apos;s &lt;a href=&quot;http://www.meetup.com/HTML5-Denver-Users-Group/events/93212272/&quot;&gt;HTML5 User Group&lt;/a&gt; in April.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/appfuse_light_2_2_1</id>
        <title type="html">AppFuse Light 2.2.1 Released!</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/appfuse_light_2_2_1"/>
        <published>2013-01-24T19:43:20-07:00</published>
        <updated>2013-01-25T01:47:18-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="hibernate" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse-light" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">In December, the &lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt; Team &lt;a href=&quot;http://raibledesigns.com/rd/entry/appfuse_2_2_1_released&quot;&gt;released 2.2.1&lt;/a&gt;. Right before that release, I decided to wait on enhancing its &quot;light&quot; modules, a.k.a. &lt;a href=&quot;https://github.com/appfuse/appfuse-light&quot;&gt;AppFuse Light&lt;/a&gt;. I&apos;m glad I did, because it took some effort to get jQuery and Bootstrap integrated, as well as to make it more secure. 
&lt;/p&gt;
&lt;p&gt;
The good news is AppFuse Light 2.2.1 is released and it&apos;s sitting out on the &lt;a href=&quot;http://search.maven.org/#search%7Cga%7C1%7Cappfuse-light&quot;&gt;Central Repository&lt;/a&gt;. This release is a refactoring of all  archetypes to be up-to-date with the AppFuse 2.2.1 release. This means Java 7 compatibility, Servlet 3, Bootstrap/jQuery integration, Tapestry 5.3.6 upgrade and security improvements. I integrated Bootstrap and jQuery using &lt;a href=&quot;http://www.webjars.org/documentation&quot;&gt;WebJars Servlet 3 support&lt;/a&gt; since it was simple and straightforward. 
&lt;/p&gt;
&lt;p&gt;
You can create projects using AppFuse&apos;s light archetypes using a command such as the following:
&lt;/p&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;
mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes 
  -DarchetypeArtifactId=appfuse-light-spring-freemarker-archetype -DarchetypeVersion=2.2.1 
  -DgroupId=com.mycompany -DartifactId=myproject 
&lt;/pre&gt;
&lt;p&gt;
The list of archetypes is as follows:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;appfuse-light-jsf-archetype&lt;/li&gt;
&lt;li&gt;appfuse-light-spring-archetype&lt;/li&gt;
&lt;li&gt;appfuse-light-spring-freemarker-archetype&lt;/li&gt;
&lt;li&gt;appfuse-light-spring-security-archetype&lt;/li&gt;
&lt;li&gt;appfuse-light-stripes-archetype&lt;/li&gt;
&lt;li&gt;appfuse-light-struts-archetype&lt;/li&gt;
&lt;li&gt;appfuse-light-tapestry-archetype&lt;/li&gt;
&lt;li&gt;appfuse-light-wicket-archetype&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The &lt;a href=&quot;http://appfuse.org/display/APF/AppFuse+QuickStart&quot;&gt;QuickStart Guide&lt;/a&gt; will help you get setup and demos are available at the following links:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://demo2.appfuse.org/appfuse-light-jsf&quot;&gt;JSF 2 + Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://demo2.appfuse.org/appfuse-light-spring&quot;&gt;Spring MVC 3 + Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://demo2.appfuse.org/appfuse-light-spring-freemarker&quot;&gt;Spring MVC 3 + FreeMarker + Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://demo2.appfuse.org/appfuse-light-spring-security&quot;&gt;Spring MVC 3 + Spring Security + Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://demo2.appfuse.org/appfuse-light-stripes&quot;&gt;Stripes + Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://demo2.appfuse.org/appfuse-light-struts&quot;&gt;Struts 2 + Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://demo2.appfuse.org/appfuse-light-tapestry&quot;&gt;Tapestry 5 + Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://demo2.appfuse.org/appfuse-light-wicket&quot;&gt;Wicket + Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have questions about AppFuse, we invite you to ask them on the &lt;a href=&quot;http://appfuse.org/display/APF/Mailing+Lists&quot;&gt;users mailing list&lt;/a&gt; or tweet using #appfuse. &lt;/p&gt;
&lt;p&gt;
For those enjoying &lt;a href=&quot;http://twitter.github.com/bootstrap/&quot;&gt;Bootstrap&lt;/a&gt; in your apps, I encourage you to check out &lt;a href=&quot;https://wrapbootstrap.com/&quot;&gt;{wrap}bootstrap&lt;/a&gt; and &lt;a href=&quot;http://bootswatch.com/&quot;&gt;Bootswatch&lt;/a&gt;.&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/what_s_the_best_way4</id>
        <title type="html">What&apos;s the best way to compare JVM Web Frameworks?</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/what_s_the_best_way4"/>
        <published>2013-01-09T08:29:17-07:00</published>
        <updated>2013-01-14T15:03:01-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="dzone" scheme="http://roller.apache.org/ns/tags/" />
        <category term="infoq" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;
I&apos;ve been comparing web frameworks ever since 2004. It was the first time I&apos;d ever proposed a talk for a conference. ApacheCon was in Vegas that year and my buddy Bruce suggested I speak at it. I submitted the talk, &lt;a href=&quot;http://raibledesigns.com/rd/entry/going_to_apachecon&quot;&gt;got accepted&lt;/a&gt; and went to work learning the frameworks I was talking about. At the time, I had a lot of Struts experience and I&apos;d made a good living learning it, consulting on it and blogging about it. However, there was a new kid on the block (Spring MVC) that was garnishing attention and some other frameworks (WebWork and Tapestry) that had a lot of high praise from developers. I was inspired to learn why so many people hated Struts. 
&lt;/p&gt;
&lt;p&gt;
Fast forward 8 years and I&apos;m still comparing web frameworks. Why? Because there still seems to be a large audience that&apos;s interested in the topic. Witness InfoQ&apos;s &lt;a href=&quot;http://www.infoq.com/research/jvm-web-frameworks&quot;&gt;Top 20 JVM Web Frameworks&lt;/a&gt;, which was one of their most-read articles for two months in a row. One of the beauties of the Java Community is that it&apos;s very diverse. There&apos;s &lt;em&gt;tons&lt;/em&gt; of folks that are part of this community and, like it or not, several folks that are &lt;em&gt;former&lt;/em&gt; Java Developers. However, these developers still seem to maintain an interest in the community and it&apos;s still one of the largest pools of talent out there. Java is still &lt;a href=&quot;http://redmonk.com/sogrady/2012/02/08/language-rankings-2-2012/&quot;&gt;quite viable&lt;/a&gt; and only seems to be &lt;a href=&quot;http://frankhinkel.blogspot.de/2012/11/java-8-closures-lambda-expressions.html&quot;&gt;getting better with age&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
So the topic of web frameworks on the JVM is still hot, and I still &lt;a href=&quot;http://raibledesigns.com/rd/entry/why_the_bias_against_jsf&quot;&gt;like to write about it&lt;/a&gt;. For those of you still enthusiastic about the topic, you&apos;re in luck. The two best websites for the Java Community, &lt;a href=&quot;http://infoq.com&quot;&gt;InfoQ&lt;/a&gt; and &lt;a href=&quot;http://java.dzone.com&quot;&gt;DZone&lt;/a&gt; (formerly Javalobby) are still very interested in the topic too!&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;
I&apos;ve been comparing web frameworks ever since 2004. It was the first time I&apos;d ever proposed a talk for a conference. ApacheCon was in Vegas that year and my buddy Bruce suggested I speak at it. I submitted the talk, &lt;a href=&quot;http://raibledesigns.com/rd/entry/going_to_apachecon&quot;&gt;got accepted&lt;/a&gt; and went to work learning the frameworks I was talking about. At the time, I had a lot of Struts experience and I&apos;d made a good living learning it, consulting on it and blogging about it. However, there was a new kid on the block (Spring MVC) that was garnishing attention and some other frameworks (WebWork and Tapestry) that had a lot of high praise from developers. I was inspired to learn why so many people hated Struts.
&lt;/p&gt;
&lt;p&gt;
Fast forward 8 years and I&apos;m still comparing web frameworks. Why? Because there still seems to be a large audience that&apos;s interested in the topic. Witness InfoQ&apos;s &lt;a href=&quot;http://www.infoq.com/research/jvm-web-frameworks&quot;&gt;Top 20 JVM Web Frameworks&lt;/a&gt;, which was one of their most-read articles for two months in a row. One of the beauties of the Java Community is that it&apos;s very diverse. There&apos;s &lt;em&gt;tons&lt;/em&gt; of folks that are part of this community and, like it or not, several folks that are &lt;em&gt;former&lt;/em&gt; Java Developers. However, these developers still seem to maintain an interest in the community and it&apos;s still one of the largest pools of talent out there. Java is still &lt;a href=&quot;http://redmonk.com/sogrady/2012/02/08/language-rankings-2-2012/&quot;&gt;quite viable&lt;/a&gt; and only seems to be &lt;a href=&quot;http://frankhinkel.blogspot.de/2012/11/java-8-closures-lambda-expressions.html&quot;&gt;getting better with age&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
So the topic of web frameworks on the JVM is still hot, and I still &lt;a href=&quot;http://raibledesigns.com/rd/entry/why_the_bias_against_jsf&quot;&gt;like to write about it&lt;/a&gt;. For those of you still enthusiastic about the topic, you&apos;re in luck. The two best websites for the Java Community, &lt;a href=&quot;http://infoq.com&quot;&gt;InfoQ&lt;/a&gt; and &lt;a href=&quot;http://java.dzone.com&quot;&gt;DZone&lt;/a&gt; (formerly Javalobby) are still very interested in the topic too!&lt;/p&gt;
&lt;!--p style=&quot;font-style: italic&quot;&gt;Sorry &lt;a href=&quot;http://theserverside.com&quot;&gt;TheServerSide.com&lt;/a&gt;, you were awesome at one time. Remember when Dion was pumping out the good content and there weren&apos;t ads in your face? Those where the days...&lt;/p--&gt; 
&lt;p&gt;
Both sites emailed me in November to get my advice for their research on the subject. InfoQ (specifically Dio Synodinos) was mostly interested in 1) having me analyze &lt;a href=&quot;http://www.infoq.com/research/jvm-web-frameworks&quot;&gt;their recently-gathered data&lt;/a&gt;, or 2) helping them create a new version. DZone (specifically Mitch Pronschinske) emailed about doing a similar survey to InfoQ&apos;s, but with more relevant data points (include GWT, specifying Struts 2 vs. Struts 1, etc.).
&lt;/p&gt;
&lt;p&gt;
My response to Mitch at DZone:
&lt;/p&gt;
&lt;div class=&quot;quote&quot;&gt;
&lt;p&gt;
Interestingly enough, the folks at InfoQ contacted me as well as they&apos;re thinking of doing a new survey. One of the things I mentioned to them is it&apos;d be interesting to see what folks are using AND which frameworks they admire. Often, devs don&apos;t get to choose their web framework at work. I wonder if it&apos;d be possible to collaborate with InfoQ to gather data from developers so it&apos;s not being done on two different sites?
&lt;/p&gt;
&lt;p&gt;
I submitted a talk for ApacheCon NA (in February) called Comparing Apache Web Frameworks. When choosing Web Frameworks, I&apos;ve often found it helps to eliminate frameworks and narrow the scope. Obviously, this makes sense for an Apache Conference, but not for all developers. However, I do plan on analyzing each framework based on a limited set of criteria. Here&apos;s what I have so far:
&lt;/p&gt;
&lt;p&gt;
Community, HTML5, REST, Mobile, Performance, Web Performance Optimization
&lt;/p&gt;
&lt;p&gt;
Obviously, community is important for Apache projects, but might not be for the wider audience. It might be good to limit to these 5 criteria, or expand it to 10, but not more. I think it&apos;d be interesting to get the community to rank the various frameworks on these criteria, and also try to find developer&apos;s biases while doing it. For example, I wonder if people would be willing to admit they&apos;re biased for/against certain frameworks and then take that into account as part of gathering the data?&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Unfortunately, ApacheCon denied my submission. This make sense since their &lt;a href=&quot;http://na.apachecon.com/schedule/&quot;&gt;schedule&lt;/a&gt; seems to be concentrating on &lt;a href=&quot;http://httpd.apache.org/&quot;&gt;HTTPD&lt;/a&gt;, &lt;a href=&quot;http://incubator.apache.org/cloudstack/&quot;&gt;Cloud&lt;/a&gt; and &lt;a href=&quot;http://hadoop.apache.org/&quot;&gt;Big Data&lt;/a&gt;.&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;
For InfoQ, Dio asked for a list of web frameworks to include. Below is a list we started with, followed by my response.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring MVC&lt;/li&gt;
&lt;li&gt;Play&lt;/li&gt;
&lt;li&gt;Grails&lt;/li&gt;
&lt;li&gt;JSF&lt;/li&gt;
&lt;li&gt;Struts 2&lt;/li&gt;
&lt;li&gt;Wicket&lt;/li&gt;
&lt;li&gt;Lift&lt;/li&gt;
&lt;li&gt;Tapestry 5&lt;/li&gt;
&lt;li&gt;Seam&lt;/li&gt;
&lt;li&gt;JRuby on Rails&lt;/li&gt;
&lt;li&gt;Wicket&lt;/li&gt;
&lt;li&gt;GWT&lt;/li&gt;
&lt;li&gt;Vaadin&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;quote&quot;&gt;
&lt;p&gt;
I would add Stripes, vert.x and maybe something like Apache Click. VRaptor is probably a good one to add too. There&apos;s always a few less-used frameworks that get a lot of complainers if you don&apos;t include them. 
&lt;/p&gt;
&lt;p&gt;
Comparing to your previous list, I don&apos;t think Seam should be in here since they&apos;ve &lt;a href=&quot;http://www.infoq.com/news/2012/04/seam-deltaspike&quot;&gt;split the project into separate bundles&lt;/a&gt; and are no longer developing Seam as a whole. JRuby on Rails is a tough one because if you say Ruby on Rails, you&apos;ll get a ton of responses, but probably not from the Java community. The Ruby community might chime it quite a bit if you can get in touch with them though.
&lt;/p&gt;
&lt;p&gt;
I believe you should include Clojure web frameworks, but I&apos;ve only heard of one of them: Compojure.
&lt;/p&gt;
&lt;p&gt;
SiteMesh, Netty, etc. - remove them.
&lt;/div&gt;
&lt;p&gt;
I also offered my advice on instructions:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
I actually like the two coordinates you used before, importance and adoptability. However, I don&apos;t know that everyone read the instructions this way. Most people didn&apos;t rank all frameworks and I believe that&apos;s part of the point. I only ranked the ones I&apos;d used, but I think it&apos;d be better if people ranked all of them. I also think having these two criteria opens it up to more than just developers. Project/Product Managers and stakeholders that&apos;ve been successful with certain frameworks should be able to vote too.
&lt;/p&gt;
&lt;p&gt;
For DZone, they wanted to include a set of criteria for ranking:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Project maturity, community support, and documentation quality (one criteria)&lt;/li&gt;
&lt;li&gt;UI Features Capability (maybe some are more graphics driven or form driven?)&lt;/li&gt;
&lt;li&gt;Code readability&lt;/li&gt;
&lt;li&gt;Flexibility (maybe this could be broken down into what types of projects the framework can handle) or several criteria that ask if it is &quot;Good for &apos;x&apos; type of project&quot;&lt;/li&gt;
&lt;li&gt;Performance/Speed&lt;/li&gt;
&lt;li&gt;Cross platform support&lt;/li&gt;
&lt;li&gt;Extensibility, Plugins, Community Libraries&lt;/li&gt;
&lt;li&gt;Architecture (this may just be information for later, not an opinion question)&lt;/li&gt;
&lt;li&gt;Web standards support&lt;/li&gt;
&lt;li&gt;REST support (is this something you would just rate a yes or no?  In that case it wouldn&apos;t need to be an opinion question)&lt;/li&gt;
&lt;li&gt;Mobile support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
My response:&lt;/p&gt;

&lt;div class=&quot;quote&quot;&gt;
    &lt;p&gt;
For web frameworks, I believe the 5 I mentioned (Community, HTML5, REST, Mobile, Performance, Web Performance Optimization) are most important, with Security become more and more of a concern. For web standards support, I&apos;d almost change it to &quot;HTML5&quot; and to see how the various frameworks stack up. I think REST is very important, and I think it&apos;s cool that Struts 2, Spring MVC and Grails all have great support for it. It&apos;d be interesting to see how the component-based frameworks think of having REST support in the framework (vs. external like Jersey, CXF, etc.).
&lt;/p&gt;&lt;p&gt;
Of the list you provided, I don&apos;t know about Code readability or Flexibility. Code readability is kinda like Learnability. One of the nice things about Spring MVC and Grails is that you can learn how they work very quickly. Then you can use that knowledge and don&apos;t have to look things up much. Tapestry and Wicket might be similar for those writing large apps, but I haven&apos;t found that to be as true. The more traditional MVC Frameworks just make more sense to me.
&lt;/p&gt;
&lt;p&gt;
UI Feature Capability is a good one because frameworks with widgets are often popular with developers. Flex, GWT, jQuery UI, Sencha all do this very well.
&lt;/p&gt;
&lt;/div&gt;
&lt;p id=&quot;summary&quot;&gt;
&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;The reason for this post is to add some transparency to the process of Comparing JVM Web Frameworks. I like to think that I&apos;ve tried to do this in the past (especially with my &lt;a href=&quot;http://raibledesigns.com/rd/entry/how_i_calculated_ratings_for&quot;&gt;reasons for rankings&lt;/a&gt;). Now, we&apos;d like to hear from you, the community that uses these web frameworks. 
&lt;/p&gt;
&lt;p&gt;&lt;em&gt;What&apos;s the best way to compare JVM Web Frameworks?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;While it&apos;s nice to hear from the generous folks that create and maintain JVM Web Frameworks, we&apos;re mostly interested in hearing from the developers that are using these things on a day-to-day basis. The Blue Collar Developers, if you will. If you could design a JVM Web Framework comparison that answered your questions, how would it look? What questions would it ask? What conclusions would make you happy? Should commercial frameworks like ZK be included?
    &lt;/p&gt;
    &lt;p&gt;Your responses are very greatly appreciated.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/why_the_bias_against_jsf</id>
        <title type="html">Why the bias against JSF?</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/why_the_bias_against_jsf"/>
        <published>2012-11-08T09:24:27-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jvm" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">In my last post about &lt;a href=&quot;http://raibledesigns.com/rd/entry/infoq_s_top_20_web&quot;&gt;InfoQ&apos;s Top 20 Web Frameworks for the JVM&lt;/a&gt;, I received a thought-provoking &lt;a href=&quot;http://raibledesigns.com/rd/entry/infoq_s_top_20_web#comment-1352305197000&quot;&gt;comment&lt;/a&gt; from &lt;a href=&quot;http://henk53.wordpress.com/&quot;&gt;henk53&lt;/a&gt;:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
There is one little thing that does bother me in those presentations, and that&apos;s your fairly obvious bias against JSF. &lt;br/&gt;...&lt;br/&gt;
If you are presenting yourself as, more or less, an authority on comparing web frameworks, then having a fairly obvious biased against one of them is just peculiar. I, all of my team, and various clients distrust your ranking of JSF. We do look at your data if the choice is between other frameworks, but as soon as JSF comes into the picture we just look elsewhere.
&lt;br/&gt;&lt;br/&gt;
I&apos;m not really sure where this bias comes from. Yes, JSF 1.0 sucked and 1.2 was only marginally better, but 2.0 is really cool and productive and there are SUPERB component and utility libraries now like PrimeFaces and OmniFaces. As a researcher of this topic I think you should keep up the date and not stick to some old grudge.
&lt;/p&gt;
&lt;p&gt;This is true, I am biased against JSF. It all started with my &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_jsf_experience&quot;&gt;first JSF experience&lt;/a&gt; back in August 2004. If you remember correctly, 2004 was a big year: JSF 1.0, Spring 1.0 and Flex 1.0 were all released. The &quot;AJAX&quot; term was coined in &lt;a href=&quot;http://www.adaptivepath.com/ideas/ajax-new-approach-web-applications&quot;&gt;early 2005&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://www.flickr.com/photos/mraible/4378559350/&quot; title=&quot;History of Web Frameworks by mraible, on Flickr&quot;&gt;&lt;img src=&quot;//farm5.staticflickr.com/4067/4378559350_13f0755403.jpg&quot; width=&quot;500&quot; height=&quot;234&quot; alt=&quot;History of Web Frameworks&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;http://raibledesigns.com/rd/entry/jsf_still_sucks&quot;&gt;2007&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/what_s_wrong_with_jsf&quot;&gt;2008&lt;/a&gt;, JSF still hadn&apos;t gotten any better. In late 2009, JSF 2.0 was released and &lt;a href=&quot;http://raibledesigns.com/rd/entry/upgrading_to_jsf_2&quot;&gt;I upgraded in March 2011&lt;/a&gt;. As you can see from the aforementioned post, I ran into quite a few issues upgrading. JSF was also the &lt;a href=&quot;http://raibledesigns.com/rd/entry/implementing_extensionless_urls_with_tapestry&quot;&gt;hardest one to get working with extension-less URLs&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Most of my issues with JSF come from having maintained an application built with it since 2004. If I were to start a new application without any legacy migration issues, I imagine it wouldn&apos;t be as difficult. However, if you compare it to Struts 2 and Spring MVC, I&apos;ve had little-to-no issues upgrading those applications over the years. &lt;/p&gt;
&lt;p&gt;Also, I&apos;m not just biased against JSF, but most component-based web frameworks. Just ask the Tapestry and Wicket folks. They&apos;ve felt my criticisms over the years. My reason for preferring request-based frameworks like Struts 2/Spring MVC and Grails/Play has been because I&apos;ve never seen the appeal in component-based frameworks. Often I&apos;ve found that their components are just widgets that you can get from any decent JavaScript framework. And chances are that JavaScript framework can work with &lt;em&gt;any&lt;/em&gt; web framework. Also, I&apos;ve worked on a lot of high-traffic web applications that require statelessness for scalability.&lt;/p&gt;
&lt;p&gt;I see the value in component-based frameworks, I just don&apos;t think components should be authored on the server-side. Most of the Java-based component frameworks require 2+ files for components (one for the component, one for the view, possibly one for the config). I love GWT&apos;s component concept in that you can just extract a class and re-use it. With JS frameworks, you can often just include a script. These days, when I think of good component-based frameworks, I think of jQuery UI and Twitter Bootstrap.&lt;/p&gt;
&lt;p&gt;All that being said, there&apos;s a lot of folks praising JSF 2 (and &lt;a href=&quot;http://primefaces.org/&quot;&gt;PrimeFaces&lt;/a&gt; moreso). That&apos;s why I&apos;ll be integrating it (or merging your pull request) into the 2.3 release of AppFuse. Since PrimeFaces contains a Bootstrap theme, I hope this is a pleasant experience and my overall opinion of JSF improves.&lt;/p&gt;
&lt;p&gt;In other component-based frameworks in AppFuse news, Tapestry 5 has gotten &lt;em&gt;really fast&lt;/em&gt; in the last year. I imagine this is because we have a Tapestry expert, &lt;a href=&quot;http://www.linkedin.com/in/sergeeby&quot;&gt;Serge Eby&lt;/a&gt;, working on it. And we&apos;re planning on adding Wicket in the 2.3 release. &lt;/p&gt;
&lt;p&gt;So even though I &lt;em&gt;prefer&lt;/em&gt; request-based frameworks with REST support and Bootstrap, that doesn&apos;t mean everyone does. I&apos;ll do my best to be less-biased in the future. However, please remember that my view on web frameworks is as a developer, not an analyst. And aren&apos;t developers &lt;em&gt;supposed&lt;/em&gt; to be opinionated? &lt;img src=&quot;https://raibledesigns.com/images/smileys/wink.gif&quot; class=&quot;smiley&quot; alt=&quot;;)&quot; title=&quot;;)&quot; /&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/infoq_s_top_20_web</id>
        <title type="html">InfoQ&apos;s Top 20 Web Frameworks for the JVM</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/infoq_s_top_20_web"/>
        <published>2012-11-06T12:04:28-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="infoq" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jvm" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Back in early October, InfoQ.com published a community research article titled &lt;a href=&quot;http://www.infoq.com/research/jvm-web-frameworks&quot;&gt;Top 20 Web Frameworks for the JVM&lt;/a&gt;. Their goal seemed to be fairly simple:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
Using the new community research tool, we at InfoQ want to get YOUR opinions on the relative importance and maturity of a variety of web frameworks that are targeted for the JVM. Please vote by dragging each practice across two dimensions &#8211; how important is the framework relative to the other frameworks, and how much is it actually used in real teams and projects.
&lt;/p&gt;
&lt;p&gt;When I first saw this article, I noticed some strange web frameworks listed. Namely, Netty, SiteMesh and Spark. I haven&apos;t heard of many folks using &lt;a href=&quot;https://netty.io/&quot;&gt;Netty&lt;/a&gt; for a web framework, but I&apos;m sure it&apos;s possible. SiteMesh is certainly not a web framework and I&apos;ve never even heard of Spark. And where is GWT and Vaadin? Regardless of the choices, I went ahead and voted.&lt;/p&gt;
&lt;p&gt;Last week, InfoQ posted their top content for October on Facebook. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/research/jvm-web-frameworks&quot;&gt;Top 20 Web Frameworks for the JVM&lt;/a&gt; 25,992 PV&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/news/2012/10/Ruby-on-Rails-Node-js-LinkedIn&quot;&gt;Ruby on Rails vs. Node.js at LinkedIn&lt;/a&gt; 11,904 PV&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/presentations/Mobile-Web-Development&quot;&gt;Mobile Webdev: The Horror&lt;/a&gt; 11,150 PV&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/articles/rest-introduction&quot;&gt;A Brief Introduction to REST&lt;/a&gt; 8,872 PV
&lt;li&gt;&lt;a href=&quot;http://www.infoq.com/minibooks/kanban-scrum-minibook&quot;&gt;Kanban and Scrum - making the most of both&lt;/a&gt; 7,665 PV&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First of all, it&apos;s interesting to see that JVM Web Frameworks is still a hot topic for developers. Whenever I do my Comparing JVM Web Frameworks talk at conferences, I always see a few jabs about &quot;he&apos;s &lt;em&gt;still&lt;/em&gt; doing that talk!?&quot; Yes, it seems strange that a talk I first did in 2004 is still in high demand. &lt;/p&gt;
&lt;p&gt;Secondly, I think InfoQ does good in showing how the frameworks ranked and showing their &lt;em&gt;heatmaps&lt;/em&gt;. Below are their rankings from 1109 participants. &lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://www.flickr.com/photos/mraible/8161758257/&quot; title=&quot;InfoQ&apos;s Top 20 Web Frameworks for the JVM&quot;&gt;&lt;img src=&quot;//farm9.staticflickr.com/8197/8161758257_ef6d919f5d.jpg&quot; width=&quot;500&quot; height=&quot;395&quot; alt=&quot;InfoQ&apos;s Top 20 Web Frameworks for the JVM&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;According to this research, the top 5 web frameworks for the JVM are Spring MVC, Play, Grails, JSF and Struts (I hope those surveyed meant Struts 2, not Struts 1).&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;http://www.slideshare.net/mraible/comparing-jvm-web-frameworks-jfokus-2012&quot;&gt;my research from last February&lt;/a&gt; (slide 21), I ranked them (with no particular weightings) as Grails, GWT, JRuby on Rails, Spring MVC and Vaadin. So I guess you could say I got 2 out of 5 right (Grails and Spring MVC). Not bad considering InfoQ didn&apos;t even consider GWT and Vaadin.&lt;/p&gt;
&lt;p&gt;Another intriguing data point in this study is each frameworks&apos; heatmap. For example, below are heatmaps for the top 4 frameworks. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rev=&quot;http://www.flickr.com/photos/mraible/8161758501/&quot; href=&quot;http://farm8.staticflickr.com/7247/8161758501_151b1a839c.jpg&quot; title=&quot;Spring MVC Heatmap&quot; rel=&quot;lightbox[infotop20webframeworks]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7247/8161758501_151b1a839c_m.jpg&quot; width=&quot;240&quot; height=&quot;215&quot; alt=&quot;Spring MVC Heatmap&quot;&gt;&lt;/a&gt;

&lt;a rev=&quot;http://www.flickr.com/photos/mraible/8161762845/&quot; href=&quot;http://farm8.staticflickr.com/7125/8161762845_12cfdc076c.jpg&quot; title=&quot;Grails Heatmap&quot; rel=&quot;lightbox[infotop20webframeworks]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7125/8161762845_12cfdc076c_m.jpg&quot; width=&quot;240&quot; height=&quot;215&quot; alt=&quot;Grails Heatmap&quot; style=&quot;margin-left: 10px&quot;&gt;&lt;/a&gt;
&lt;p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rev=&quot;http://www.flickr.com/photos/mraible/8161758399/&quot; href=&quot;http://farm8.staticflickr.com/7255/8161758399_505e8cf4db.jpg&quot; title=&quot;Play Heatmap&quot; rel=&quot;lightbox[infotop20webframeworks]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7255/8161758399_505e8cf4db_m.jpg&quot; width=&quot;240&quot; height=&quot;215&quot; alt=&quot;Play Heatmap&quot;&gt;&lt;/a&gt;

&lt;a rev=&quot;http://www.flickr.com/photos/mraible/8161758341/&quot; href=&quot;http://farm8.staticflickr.com/7256/8161758341_7e1d37e1ea.jpg&quot; title=&quot;JSF Heatmap&quot; rel=&quot;lightbox[infotop20webframeworks]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7256/8161758341_7e1d37e1ea_m.jpg&quot; width=&quot;240&quot; height=&quot;215&quot; alt=&quot;JSF Heatmap&quot; style=&quot;margin-left: 10px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Notice how Grails and Spring MVC are both &lt;em&gt;hotter&lt;/em&gt; in the bottom right corner? It seems the community&apos;s overall opinions of these two frameworks are more aligned than JSF and Play, which a fair amount of folks rank as hyped and unimportant. &lt;/p&gt;
&lt;p&gt;What I really like about this research is it&apos;s the community&apos;s opinions, visualized. It also confirms that some of my favorite frameworks are still on top. I don&apos;t know if JSF belongs as a top framework, however it seems a lot of folks do. I recently &lt;a href=&quot;http://appfuse.547863.n4.nabble.com/Drop-JSF-Support-td4655648.html&quot;&gt;thought about removing it from AppFuse&lt;/a&gt;, but decided to keep it (at least for the next release). I hope InfoQ does more research projects like this, especially if they get their list of web frameworks right. </content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/play_vs_grails_smackdown_at</id>
        <title type="html">Play vs. Grails Smackdown at &#220;berConf</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/play_vs_grails_smackdown_at"/>
        <published>2012-06-25T07:10:57-06:00</published>
        <updated>2013-10-04T17:28:17-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="playframework" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="uberconf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="comparison" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">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&apos; 2.0 releases. That&apos;s why &lt;a href=&quot;http://jamesward.com&quot;&gt;James Ward&lt;/a&gt; and I decided to do a presentation at &lt;a href=&quot;http://uberconf.com&quot;&gt;&#220;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=&quot;how&quot;&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=&quot;http://www.wynkoop.com/&quot;&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 &#8220;Happy Trails&#8221; 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=&quot;https://github.com/jamesward/happytrails&quot;&gt;source code on GitHub&lt;/a&gt;, continuously tested on &lt;a href=&quot;http://www.cloudbees.com/&quot;&gt;CloudBees&lt;/a&gt; and deployed to &lt;a href=&quot;http://heroku.com&quot;&gt;Heroku&lt;/a&gt;. Two weeks ago, when we were finishing up our apps, we hired a friend (&lt;a href=&quot;http://www.linkedin.com/pub/linsay-shirley/1/5a0/b4&quot;&gt;Linsay Shirley&lt;/a&gt;) to do QA. 
&lt;/p&gt;
&lt;p&gt;
After fixing bugs, I emailed &lt;a href=&quot;http://blog.lightbody.net/&quot;&gt;Patrick Lightbody&lt;/a&gt;, got some &#8220;cloud dollars&#8221; for &lt;a href=&quot;https://browsermob.com/performance-testing&quot;&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=&quot;https://wm2-testscripts-scripts-prod.s3.amazonaws.com/script/b1b78d4286054d159888bc4135379b86/script.js?versionId=J4E28EFR5PzDNnAgPPPfoelw3AhMqI9A&quot;&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=&quot;http://static.raibledesigns.com/repository/presentations/Play_vs_Grails_Smackdown_UberConf2012/&quot;&gt;our smackdown presentation&lt;/a&gt;. We used &lt;a href=&quot;http://lab.hakim.se/reveal-js/&quot;&gt;reveal.js&lt;/a&gt;, &lt;a href=&quot;http://www.jamesward.com/2012/06/15/dynamically-rendering-github-files-in-web-pages&quot;&gt;GitHub Files&lt;/a&gt; and &lt;a href=&quot;https://developers.google.com/chart/&quot;&gt;Google Charts&lt;/a&gt; to make things more dynamic.
&lt;/p&gt;
&lt;p id=&quot;conclusions&quot;&gt;&lt;strong&gt;What we found&lt;/strong&gt;&lt;br/&gt;
We arrived at a number of &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/Play_vs_Grails_Smackdown_UberConf2012/#/10&quot;&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&apos;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=&quot;margin-bottom: 0&quot;&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=&quot;margin-bottom: 0&quot;&gt;
&lt;li style=&quot;text-decoration:line-through&quot;&gt;Play: ~10% failed requests, Grails: 0&lt;/li&gt;
&lt;li style=&quot;text-decoration:line-through&quot;&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=&quot;margin-bottom: 0&quot;&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;&quot;Play&quot; 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&apos;s all open source! This means you can &lt;a href=&quot;https://github.com/jamesward/happytrails&quot;&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&#8217;d love to tune our apps to handle more requests per second. In fact, we already had a contributor &lt;a href=&quot;http://twitter.com/pk11/status/216186997126070272&quot;&gt;discover an issue&lt;/a&gt; and &lt;a href=&quot;https://gist.github.com/2973705&quot;&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&apos;t tried them yourself, we encourage you to do so.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/comparing_web_frameworks_and_html5</id>
        <title type="html">Comparing Web Frameworks and HTML5 with Play Scala at Jfokus 2012</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/comparing_web_frameworks_and_html5"/>
        <published>2012-02-16T00:01:05-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jfokus" scheme="http://roller.apache.org/ns/tags/" />
        <category term="html5" scheme="http://roller.apache.org/ns/tags/" />
        <category term="scala" scheme="http://roller.apache.org/ns/tags/" />
        <category term="playframework" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;a href=&quot;http://www.flickr.com/photos/mcginityphoto/8355301175/&quot; title=&quot;Riddenholm Church by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm9.staticflickr.com/8330/8355301175_36050ce11c_t.jpg&quot; width=&quot;66&quot; height=&quot;100&quot; alt=&quot;Riddenholm Church&quot; class=&quot;picture&quot;&gt;&lt;/a&gt;
Stockholm seems a lot like Denver this time of year. Cold, snowy and beautiful. &lt;a href=&quot;http://www.mcginityphoto.com/&quot;&gt;Trish&lt;/a&gt; and I arrived in Stockholm (Sweden) on Monday for the &lt;a href=&quot;http://jfokus.se&quot;&gt;Jfokus&lt;/a&gt; conference and we&apos;re traveling to Madrid today for the &lt;a href=&quot;http://springio.net/&quot;&gt;Spring I/O&lt;/a&gt; conference. I was invited to Jfokus within minutes of delivering my &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_html5_with_play_scala&quot;&gt;HTML5 with Play Scala talk at Devoxx&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
Both the Jfokus and Spring I/O Organizers were interested in my Comparing JVM Web Frameworks talk, so I updated it to reflect my latest thoughts. First of all, I mentioned that there&apos;s a lot of great frameworks out there and I think the reason people are so apprehensive to choose one is because they&apos;ve chosen badly at one point. This might&apos;ve been Struts back in the day (even thought it was one of the best frameworks at the time) or it might be because a vendor talked them into it. However, if you look at the modern JVM frameworks today, you should be able to see that they&apos;re all pretty awesome.
&lt;/p&gt;
&lt;p&gt;
I mentioned how I think &lt;em&gt;Web&lt;/em&gt; developers should know JavaScript and CSS. If you&apos;re a &lt;em&gt;Java&lt;/em&gt; developer and you call yourself a web developer, you&apos;re letting your framework do too much of the work for you. I mentioned Rich Manalang&apos;s &lt;a href=&quot;http://blogs.atlassian.com/2012/01/modern-principles-in-web-development/&quot;&gt;Modern Principles in Web Development&lt;/a&gt;, where he talks about his core web development principles.
&lt;ul&gt;
&lt;li&gt;Designing for mobile first (even if you&#8217;re not building a mobile app)&lt;/li&gt;
&lt;li&gt;Build only single page apps&lt;/li&gt;
&lt;li&gt;Create and use your own REST API&lt;/li&gt;
&lt;li&gt;&#8220;Sex sells&#8221; applies to web apps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&apos;ve found these principles to be true in my own experience and suggested that if you want to be a web developer, the frameworks you might want to learn are not traditional JVM web frameworks, but rather &lt;a href=&quot;http://paulhammant.com/2012/02/13/client-side-mvc-frameworks-compared/&quot;&gt;client-side MVC frameworks&lt;/a&gt;. For those Java developers that don&apos;t want to be web developers, I suggest they strengthen their services development knowledge by reading &lt;a href=&quot;http://www.infoq.com/articles/webber-rest-workflow&quot;&gt;Hot to GET a Cup of Coffee&lt;/a&gt;.
&lt;/p&gt;
You can see my updated presentation below, &lt;a href=&quot;http://www.slideshare.net/mraible/comparing-jvm-web-frameworks-jfokus-2012&quot;&gt;on Slideshare&lt;/a&gt; or as a &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/Comparing_JVM_Web_Frameworks_Jfokus2012.pdf&quot;&gt;downloadable PDF&lt;/a&gt;. You can also &lt;a href=&quot;http://www.jfokus.se/jfokus/video.jsp?v=3084&quot;&gt;watch the video&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt; &lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/11581955?rel=0&quot; width=&quot;510&quot; height=&quot;426&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;I delivered my 2nd presentation on HTML5 with Play Scala, CoffeeScript and Jade on Wednesday morning. This talk is one of my favorites and I prepared for it over the last several weeks by adding &lt;a href=&quot;http://raibledesigns.com/rd/entry/secure_json_services_with_play&quot;&gt;JSON CRUD Services and SecureSocial&lt;/a&gt; to my HTML5 Fitness Tracking application. Right before we left for Jfokus, I was able to get everything to work, but didn&apos;t spend as much time as I&apos;d like working on the mobile client. If this talk gets accepted for &lt;a href=&quot;http://www.devoxx.com/display/FR12/Accueil&quot;&gt;Devoxx France&lt;/a&gt;, I plan on spending most of my time enhancing the mobile client. After my latest experience developing, I can see how Rich&apos;s first principle (above) makes a lot of sense.
&lt;/p&gt;
&lt;p&gt;Below is my presentation for this talk. Of course, it&apos;s &lt;a href=&quot;http://www.slideshare.net/mraible/html5-with-play-scala-coffeescript-and-jade-jfokus-2012&quot;&gt;on Slideshare&lt;/a&gt; and &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/HTML5_with_Play_Scala_CoffeeScript_and_Jade_Jfokus2012.pdf&quot;&gt;downloadable as a PDF&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/11582395?rel=0&quot; width=&quot;510&quot; height=&quot;426&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;I also updated the &lt;a href=&quot;http://vimeo.com/36826202&quot;&gt;Developing Play More demo video&lt;/a&gt; to show my latest efforts.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//player.vimeo.com/video/36826202?title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; width=&quot;510&quot; height=&quot;287&quot; frameborder=&quot;0&quot; webkitAllowFullScreen mozallowfullscreen allowFullScreen&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;Delivering these talks at Jfokus was a lot of fun. Yes, it was a lot of work and stress to prepare them. However, I also learned a lot creating them and I hope the audience benefitted from that. 
&lt;/p&gt;
&lt;p&gt;  
&lt;a href=&quot;http://www.flickr.com/photos/mcginityphoto/8350751579/&quot; title=&quot;Jfokus 2012 by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm9.staticflickr.com/8371/8350751579_33fe72872a_t.jpg&quot; width=&quot;67&quot; height=&quot;100&quot; alt=&quot;Jfokus 2012&quot; style=&quot;border: 1px solid black; float: left; margin: 0 10px 0 0&quot;&gt;&lt;/a&gt;
The conference itself was incredible. I got to meet &lt;a href=&quot;https://twitter.com/peterhilton&quot;&gt;Peter Hilton&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/javahelena&quot;&gt;Helena Hjert&#233;n&lt;/a&gt; as I was registering.
The speaker&apos;s dinner at &lt;a href=&quot;http://f12.se/&quot;&gt;F12&lt;/a&gt; was off-the-hook good and I had the pleasure of finally meeting &lt;a href=&quot;http://rickardoberg.wordpress.com/&quot;&gt;Rickard &#214;berg&lt;/a&gt;. 

&lt;/p&gt;
&lt;p&gt;I also attended some fantastic presentations, including Peter Hilton&apos;s &lt;a href=&quot;http://raibledesigns.com/rd/entry/play_framework_2_0_with&quot;&gt;Play Framework 2.0&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/bodiltv&quot;&gt;Bodil Stokke&apos;s&lt;/a&gt; &lt;a href=&quot;http://bodil.github.com/coffeescript/#landing-slide&quot;&gt;CoffeeScript: JavaScript without the Fail&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/pamelafox&quot;&gt;Pamela Fox&apos;s&lt;/a&gt; &lt;a href=&quot;http://client-side-storage.appspot.com&quot;&gt;Client-side Storage&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/hseeberger&quot;&gt;Heiko Seeberger&apos;s&lt;/a&gt; Scala in Action. I don&apos;t know if Heiko has published any slides, but I&apos;m guessing not since most of his presentation was live coding. 
&lt;/p&gt;
&lt;p&gt;I have lots of good memories from Jfokus. Many thanks to &lt;a href=&quot;http://twitter.com/matkar&quot;&gt;Mattias&lt;/a&gt; for inviting me!</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/refreshing_appfuse_s_ui_with</id>
        <title type="html">Refreshing AppFuse&apos;s UI with Twitter Bootstrap</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/refreshing_appfuse_s_ui_with"/>
        <published>2012-01-31T17:12:17-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="twitter" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="bootstrap" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ui" scheme="http://roller.apache.org/ns/tags/" />
        <category term="css" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">The last time AppFuse had an update done to its look and feel was in way back in 2006. I&apos;ve done a lot of consulting since then, which has included a fair bit of page speed optimization, HTML5 development and integrating smarter CSS. It was way back in &apos;05 when we first started looking at adding a CSS Framework to AppFuse.  It was Mike Stenhouse&apos;s &lt;a href=&quot;http://www.contentwithstyle.co.uk/content/a-css-framework/&quot;&gt;CSS Framework&lt;/a&gt; that provided the &lt;a href=&quot;http://raibledesigns.com/rd/entry/a_css_framework&quot;&gt;inspiration&lt;/a&gt; and my &lt;a href=&quot;http://raibledesigns.com/rd/entry/css_framework_design_contest_final&quot;&gt;CSS Framework Design Contest&lt;/a&gt; that provided its current themes (&lt;a href=&quot;http://css.appfuse.org/themes/puzzlewithstyle&quot;&gt;puzzlewithstyle&lt;/a&gt;, &lt;a href=&quot;http://css.appfuse.org/themes/andreas01&quot;&gt;andreas01&lt;/a&gt; and &lt;a href=&quot;http://css.appfuse.org/themes/simplicity&quot;&gt;simplicity&lt;/a&gt;).
&lt;/p&gt;
&lt;p&gt;Since then, a lot of CSS Frameworks have been invented, including &lt;a href=&quot;http://www.blueprintcss.org/&quot;&gt;Blueprint&lt;/a&gt; in 2007 and &lt;a href=&quot;http://compass-style.org/&quot;&gt;Compass&lt;/a&gt; in 2008. However, neither has taken the world by storm like &lt;a href=&quot;http://twitter.github.com/bootstrap/&quot;&gt;Twitter Bootstrap&lt;/a&gt;. From &lt;a href=&quot;http://www.alistapart.com/articles/building-twitter-bootstrap/&quot;&gt;Building Twitter Bootstrap&lt;/a&gt;:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
A year-and-a-half ago, a small group of Twitter employees set out to improve our team&#8217;s internal analytical and administrative tools. After some early meetings around this one product, we set out with a higher ambition to create a toolkit for anyone to use within Twitter, and beyond. Thus, we set out to build a system that would help folks like us build new projects on top of it, and Bootstrap was conceived.&lt;br/&gt;
...&lt;br/&gt;
Today, it has grown to include dozens of components and has become the most popular project on GitHub with more than 13,000 watchers and 2,000 forks.&lt;/p&gt;
&lt;p&gt;&lt;p&gt;The fact that Bootstrap has become the most popular project on GitHub says a lot. For &lt;a href=&quot;http://appfuse.547863.n4.nabble.com/AppFuse-next-td3634415.html&quot;&gt;AppFuse.next&lt;/a&gt;, I&apos;d like to integrate a lot of my learnings over the past few years, as well as support HTML5 and modern browsers as best we can. This means &lt;a href=&quot;http://code.google.com/speed/page-speed/docs/rules_intro.html&quot;&gt;page speed optimizations&lt;/a&gt;, getting rid of Prototype and Scriptaculous in favor of jQuery, adding &lt;a href=&quot;http://code.google.com/p/wro4j/&quot;&gt;wro4j&lt;/a&gt; for resource optimization and integrating &lt;a href=&quot;http://html5boilerplate.com/&quot;&gt;HTML5 Boilerplate&lt;/a&gt;. I&apos;ve used Twitter Bootstrap for my &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_html5_with_play_scala&quot;&gt;&lt;em&gt;Play More!&lt;/em&gt; app&lt;/a&gt;, as well as some recent client projects. Its excellent documentation has made it easy to use and I love the way you can simply add classes to elements to make them transform into something beautiful.
&lt;/p&gt;
&lt;p&gt;Last week, I spent a couple late nights integrating &lt;a href=&quot;http://thinkvitamin.com/design/twitter-bootstrap-2-0/&quot;&gt;Twitter Bootstrap 2.0&lt;/a&gt; into the Struts 2 and Spring MVC versions of AppFuse. The layout was pretty straightforward thanks to &lt;a href=&quot;http://markdotto.com/bs2/docs/scaffolding.html&quot;&gt;Scaffolding&lt;/a&gt;. Creating the Struts Menu Velocity template to produce &lt;a href=&quot;http://markdotto.com/bs2/docs/javascript.html#dropdowns&quot;&gt;dropdowns&lt;/a&gt; wasn&apos;t too difficult. I added &lt;a href=&quot;http://markdotto.com/bs2/docs/base-css.html#tables&quot;&gt;class=&quot;table table-condensed&quot;&lt;/a&gt; to the list screen tables, &lt;a href=&quot;http://markdotto.com/bs2/docs/base-css.html#forms&quot;&gt;class=&quot;well form-horizontal&quot;&lt;/a&gt; to forms and &lt;a href=&quot;http://markdotto.com/bs2/docs/base-css.html#buttons&quot;&gt;class=&quot;btn primary&quot;&lt;/a&gt; to buttons. 
&lt;/p&gt;
&lt;p&gt;  
I also added validation errors with the &quot;help-inline&quot; class. This is also where things got tricky with Struts and Spring MVC. For the form elements in Bootstrap, they recommend you use a &quot;control-group&quot; element that contains your label and a &quot;controls&quot; element. The control contains the input/select/textarea and also the error message if there is one. Here&apos;s a sample element waiting for data: 
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;div class=&quot;control-group&quot;&amp;gt;
    &amp;lt;label for=&quot;name&quot; class=&quot;control-label&quot;&amp;gt;Name&amp;lt;/label&amp;gt;
    &amp;lt;div class=&quot;controls&quot;&amp;gt;
        &amp;lt;input type=&quot;text&quot; id=&quot;name&quot; name=&quot;name&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Below is what that element should look like to display a validation error:&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;div class=&quot;control-group error&quot;&amp;gt;
    &amp;lt;label for=&quot;name&quot; class=&quot;control-label&quot;&amp;gt;Name&amp;lt;/label&amp;gt;
    &amp;lt;div class=&quot;controls&quot;&amp;gt;
        &amp;lt;input type=&quot;text&quot; id=&quot;name&quot; name=&quot;name&quot; value=&quot;&quot;&amp;gt;
        &amp;lt;span class=&quot;help-inline&quot;&amp;gt;Please enter your name.&amp;lt;/span&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;You can see this markup is pretty easy, you just need to add an &quot;error&quot; class to &lt;em&gt;control-group&lt;/em&gt; and span to show the error message. With Struts 2, this was pretty easy thanks to its customizable templates for its &lt;a href=&quot;http://struts.apache.org/2.x/docs/struts-tags.html&quot;&gt;tags&lt;/a&gt;. All I had to do was create a &quot;template/css_xhtml&quot; directory in &lt;em&gt;src/main/webapp&lt;/em&gt; and modify checkbox.ftl, controlfooter.ftl, controlheader-core.ftl and controlheader.ftl to match Bootstrap&apos;s conventions. 
&lt;/p&gt;
&lt;p&gt;
Spring MVC was a bit trickier. Since its tags don&apos;t have the concept of writing an entire control (label and field), I had to do a bit of finagling to get things to work. In the current implementation, Struts 2 forms have a single line for a &lt;em&gt;control-group&lt;/em&gt; and its &lt;em&gt;control-label&lt;/em&gt; and &lt;em&gt;controls&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;&amp;lt;s:textfield key=&quot;user.firstName&quot; required=&quot;true&quot;/&gt;&lt;/pre&gt;
&lt;p&gt;With Spring MVC, it&apos;s a bit more complex:&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;spring:bind path=&quot;user.firstName&quot;&amp;gt;
&amp;lt;fieldset class=&quot;control-group${(not empty status.errorMessage) ? &apos; error&apos; : &apos;&apos;}&quot;&amp;gt;
&amp;lt;/spring:bind&amp;gt;
    &amp;lt;appfuse:label styleClass=&quot;control-label&quot; key=&quot;user.firstName&quot;/&amp;gt;
    &amp;lt;div class=&quot;controls&quot;&amp;gt;
        &amp;lt;form:input path=&quot;firstName&quot; id=&quot;firstName&quot; maxlength=&quot;50&quot;/&amp;gt;
        &amp;lt;form:errors path=&quot;firstName&quot; cssClass=&quot;help-inline&quot;/&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/fieldset&amp;gt;
&lt;/pre&gt;
&lt;p&gt;You could probably overcome this verbosity with &lt;a href=&quot;http://today.java.net/pub/a/today/2003/11/14/tagfiles.html&quot;&gt;Tag Files&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
Figuring out if a &lt;em&gt;control-group&lt;/em&gt; needed an error class before the input tag was rendered was probably the hardest part of this exercise. This was mostly due to Bootstrap&apos;s great documentation and useful examples (viewed by inspecting the markup). Below are some screenshots of the old screens and new ones. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center; vertical-align: top&quot;&gt;
&lt;a href=&quot;http://farm8.staticflickr.com/7173/6787781357_c4c65c7c74_b.jpg&quot; title=&quot;Old UI - Login&quot; rel=&quot;lightbox[appfuse-bootstrap]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7173/6787781357_c4c65c7c74_t.jpg&quot; width=&quot;100&quot; height=&quot;60&quot; alt=&quot;Old UI - Login&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm8.staticflickr.com/7142/6787781421_0c7851b414_b.jpg&quot; title=&quot;Old UI - Users&quot; rel=&quot;lightbox[appfuse-bootstrap]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7142/6787781421_0c7851b414_t.jpg&quot; width=&quot;100&quot; height=&quot;60&quot; alt=&quot;Old UI - Users&quot; style=&quot;margin-left: 10px&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm8.staticflickr.com/7035/6787781725_3a1f0218c1_b.jpg&quot; title=&quot;Old UI - Edit Profile&quot; rel=&quot;lightbox[appfuse-bootstrap]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7035/6787781725_3a1f0218c1_t.jpg&quot; width=&quot;100&quot; height=&quot;82&quot; alt=&quot;Old UI - Edit Profile&quot; style=&quot;margin-left: 10px&quot;&gt;&lt;/a&gt;

&lt;p&gt;  
&lt;p style=&quot;text-align: center; vertical-align: top&quot;&gt;
&lt;a href=&quot;http://farm8.staticflickr.com/7025/6787781477_ec2ac7a93b_b.jpg&quot; title=&quot;New UI - Login&quot; rel=&quot;lightbox[appfuse-bootstrap]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7025/6787781477_ec2ac7a93b_t.jpg&quot; width=&quot;100&quot; height=&quot;60&quot; alt=&quot;New UI - Login&quot;&gt;&lt;/a&gt;
  
&lt;a href=&quot;http://farm8.staticflickr.com/7015/6787781597_6558d94bb5_b.jpg&quot; title=&quot;New UI - Users&quot; rel=&quot;lightbox[appfuse-bootstrap]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7015/6787781597_6558d94bb5_t.jpg&quot; width=&quot;100&quot; height=&quot;60&quot; alt=&quot;New UI - Users&quot; style=&quot;margin-left: 10px&quot;&gt;&lt;/a&gt;
  
  &lt;a href=&quot;http://farm8.staticflickr.com/7010/6787781681_81b7977414_b.jpg&quot; title=&quot;New UI - Edit Profile&quot; rel=&quot;lightbox[appfuse-bootstrap]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7010/6787781681_81b7977414_t.jpg&quot; width=&quot;100&quot; height=&quot;82&quot; alt=&quot;New UI - Edit Profile&quot; style=&quot;margin-left: 10px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #666; text-align: center&quot;&gt;Check out the &lt;a style=&quot;color: #666&quot; href=&quot;http://www.flickr.com/photos/mraible/sets/72157629094630763/&quot;&gt;full set on Flickr&lt;/a&gt; if you&apos;d like a closer look.
  &lt;/p&gt;
  &lt;p&gt;
Even though I like the look of the old UI, I can&apos;t help but think a lot of the themes are designed for blogs and content sites, not webapps. The old &lt;a href=&quot;http://wufoo.com/&quot;&gt;Wufoo&lt;/a&gt; forms were a lot better looking though. And if you&apos;re going to develop &lt;a href=&quot;http://blogs.atlassian.com/2012/01/modern-principles-in-web-development/&quot;&gt;kick-ass webapps&lt;/a&gt;, you need to make them look good. Bootstrap goes a long way in doing this, but it certainly doesn&apos;t replace a good UX Designer. Bootstap simply helps you get into HTML5-land, start using CSS3 and it takes the pain out of making things work cross-browser. Its fluid layouts and responsive web design seems to work great for business applications, which I&apos;m guessing AppFuse is used for the most. 
&lt;/p&gt;
&lt;p&gt;
I can&apos;t thank the Bootstrap developers enough for helping me make this all look good. With Bootstrap 2 &lt;a href=&quot;http://www.markdotto.com/2012/01/24/bootstrap-2-ready-for-testing-and-feedback/&quot;&gt;dropping this week&lt;/a&gt;, I can see myself using this more and more on projects. In the near future, I&apos;ll be helping integrate Bootstrap into AppFuse&apos;s &lt;a href=&quot;http://appfuse.547863.n4.nabble.com/Tapestry-5-3-2-td4339578.html&quot;&gt;Tapestry 5 and JSF versions&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;What do you think of this CSS change? Do you change your CSS and layout a fair bit when starting with AppFuse archetypes? What can we do to make AppFuse apps look better out-of-the-box?
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I &lt;a href=&quot;http://source.appfuse.org/changelog/appfuse/?cs=3593&quot;&gt;updated&lt;/a&gt; AppFuse to the final &lt;a href=&quot;http://raibledesigns.com/rd/entry/twitter_s_open_source_summit&quot;&gt;Bootstrap 2.0 release&lt;/a&gt;. Also, Johannes Geppert wrote a &lt;a href=&quot;http://www.jgeppert.com/2012/02/new-struts2-bootstrap-plugin-released/&quot;&gt;Struts 2 Bootstrap Plugin&lt;/a&gt;. I hope to integrate this into AppFuse in the near future.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/2011_a_year_in_review</id>
        <title type="html">2011 - A Year in Review</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/2011_a_year_in_review"/>
        <published>2012-01-11T09:45:20-07:00</published>
        <updated>2014-07-26T21:04:50-06:00</updated> 
        <category term="/Roller" label="Roller" />
        <category term="yearinreview" scheme="http://roller.apache.org/ns/tags/" />
        <category term="2011" scheme="http://roller.apache.org/ns/tags/" />
        <category term="blogging" scheme="http://roller.apache.org/ns/tags/" />
        <category term="roller" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;a href=&quot;http://raibledesigns.com/rd/entry/2010_a_year_in_review&quot;&gt;2010 was an awesome year&lt;/a&gt;, but 2011 rocked the house! At the end of last year, I kept my goals simple:&lt;/p&gt;
&lt;p class=&quot;quote&quot; style=&quot;color: #666&quot;&gt;
In 2011, I plan on doing two main things: keep rockin&apos; it with Trish and finishing The Bus. Everything else is gravy. 
&lt;/p&gt;
&lt;p&gt;As predicted, it &lt;em&gt;was&lt;/em&gt; a spectacular year, but I only accomplished 50% of my goals. That is, Trish and I had a great time skiing (especially in Utah), moving in together, traveling the world and getting engaged in Versailles. I even satisfied some 5-year goals: building a sauna in my basement and getting a ski shack in the mountains.&lt;/p&gt;
&lt;p&gt;However, I didn&apos;t get much done with The Bus. Or rather, the guys at &lt;a href=&quot;http://www.motorworksrestorations.com/&quot;&gt;MotorWorks Restorations&lt;/a&gt; didn&apos;t drain me for all I&apos;m worth in 2011. We did make good progress with estimating the final cost and obtaining many hard-to-find parts though. I now have a Porsche 911 Engine (1983 3.0L 6 cylinder), a Porsche 901 5 speed transmission, Porsche &quot;Turbo Twist&quot; wheels and a &lt;a href=&quot;https://www.facebook.com/media/set/?set=a.10150332577286054.392700.672811053&amp;amp;type=1&quot;&gt;Custom Air Ride Front Beam&lt;/a&gt; from &lt;a href=&quot;http://www.franklinsvwwerks.com/&quot;&gt;Franklin&apos;s VW Works&lt;/a&gt;. The thing that slowed our progress the most was the custom beam, as it took almost 6 months from order to delivery. When it arrived in September, I decided to put things on hold. I didn&apos;t want to get my bus back in the midst of winter and not be able to drive it.&lt;/p&gt;</summary>
        <content type="html">&lt;a href=&quot;http://raibledesigns.com/rd/entry/2010_a_year_in_review&quot;&gt;2010 was an awesome year&lt;/a&gt;, but 2011 rocked the house! At the end of last year, I kept my goals simple:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
In 2011, I plan on doing two main things: keep rockin&apos; it with Trish and finishing The Bus. Everything else is gravy. 
&lt;/p&gt;
&lt;p&gt;As predicted, it &lt;em&gt;was&lt;/em&gt; a spectacular year, but I only accomplished 50% of my goals. That is, Trish and I had a great time skiing (especially in Utah), moving in together, traveling the world and getting engaged in Versailles. I even satisfied some 5-year goals: building a sauna in my basement and getting a ski shack in the mountains.
&lt;/p&gt;
&lt;p&gt;However, I didn&apos;t get much done with The Bus. Or rather, the guys at &lt;a href=&quot;http://www.motorworksrestorations.com/&quot;&gt;MotorWorks Restorations&lt;/a&gt; didn&apos;t drain me for all I&apos;m worth in 2011. We did make good progress with estimating the final cost and obtaining many hard-to-find parts though. I now have a Porsche 911 Engine (1983 3.0L 6 cylinder), a Porsche 901 5 speed transmission, Porsche &quot;Turbo Twist&quot; wheels and a &lt;a href=&quot;https://www.facebook.com/media/set/?set=a.10150332577286054.392700.672811053&amp;amp;type=1&quot;&gt;Custom Air Ride Front Beam&lt;/a&gt; from &lt;a href=&quot;http://www.franklinsvwwerks.com/&quot;&gt;Franklin&apos;s VW Works&lt;/a&gt;. The thing that slowed our progress the most was the custom beam, as it took almost 6 months from order to delivery. When it arrived in September, I decided to put things on hold. I didn&apos;t want to get my bus back in the midst of winter and not be able to drive it.
&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;http://farm5.staticflickr.com/4136/5396188811_13d0eab8ae.jpg&quot; title=&quot;Welcome to Alta&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm5.staticflickr.com/4136/5396188811_13d0eab8ae_t.jpg&quot; width=&quot;100&quot; height=&quot;74&quot; alt=&quot;Welcome to Alta&quot; class=&quot;picture&quot; style=&quot;margin-top: 5px; border: 1px solid black&quot;&gt;&lt;/a&gt;
  
In January, I started working at &lt;a href=&quot;http://overstock.com&quot;&gt;Overstock.com&lt;/a&gt; and flew out to Salt Lake City the first two weeks to ramp up. In setting up my development environment, I discovered some inefficiencies and wrote about how I fixed them in &lt;a href=&quot;http://raibledesigns.com/rd/entry/making_code_generation_smarter_with&quot;&gt;Making Code Generation Smarter with Maven&lt;/a&gt;. I also discovered that JRebel slowed my build process down by almost 50% and stopped using it as part of my daily process. Now I simply run in debug mode or use &lt;a href=&quot;http://www.playframework.org/&quot;&gt;fancy frameworks&lt;/a&gt; that allow instant reload.
&lt;/p&gt;
&lt;p&gt;At the end of the month, I &lt;a href=&quot;http://raibledesigns.com/rd/entry/alta&quot;&gt;skied Alta&lt;/a&gt; for the first time on a blue bird day. That night, I flew back to Denver, had a gorgeous &lt;a href=&quot;http://farm5.static.flickr.com/4119/5396080419_7cd9f5cb87.jpg&quot; rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Dear Denver: You&apos;re the best.&quot;&gt;lunch ride&lt;/a&gt; in 70&amp;deg;F weather on Friday afternoon, then picked up my lovely girlfriend, Trish, and drove to Crested Butte for a &lt;a href=&quot;http://raibledesigns.com/rd/entry/crested_butte&quot;&gt;weekend of skiing with James Ward and friends&lt;/a&gt;. It was my first time visiting Crested Butte and I can see why people call it Paradise.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a data-href=&quot;http://www.flickr.com/photos/mraible/5407159019&quot; href=&quot;http://farm6.staticflickr.com/5096/5407159019_f65b19983d.jpg&quot; title=&quot;Crested Butte, The Town&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.staticflickr.com/5096/5407159019_f65b19983d_m.jpg&quot; width=&quot;240&quot; style=&quot;border: 1px solid black&quot; alt=&quot;Crested Butte, The Town&quot;&gt;&lt;/a&gt;
&lt;a data-href=&quot;http://www.flickr.com/photos/mraible/5407165843&quot; href=&quot;http://farm6.staticflickr.com/5094/5407165843_8c6328f2d9.jpg&quot; title=&quot;Top of Crested Butte&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.staticflickr.com/5094/5407165843_8c6328f2d9_m.jpg&quot; width=&quot;240&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Top of Crested Butte&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;As of February 1st, Trish and I both had 17 ski days. As I&apos;m writing this, we&apos;re both up to 14 for this season and very proud to say Abbie and Jack each have 10. Both kids are shredding like I&apos;ve always dreamed they would.
&lt;/p&gt;
&lt;p&gt;My parents (both retired) came to visit for the month of February and helped me start building a sauna in my basement. This was something I&apos;ve wanted to do for years, so it was a lot of fun getting things started. While we didn&apos;t finish construction, we did get the plumbing/electrical done, stove installed and walls framed. We also had a fun night with &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157626083451336/&quot;&gt;Chef Navarro and Friends&lt;/a&gt;.
&lt;p&gt;
The rest of my posts in February were purely technical. I wrote about how I &lt;a href=&quot;http://raibledesigns.com/rd/entry/implementing_extensionless_urls_with_tapestry&quot;&gt;implemented extensionless URLs with Tapestry, Spring MVC, Struts 2 and JSF&lt;/a&gt;. Then I started delving into &lt;a href=&quot;http://raibledesigns.com/rd/entry/integration_testing_with_http_https&quot;&gt;security-related topics&lt;/a&gt;, largely motivated by a new feature I was working on at Overstock. When I wrote about &lt;a href=&quot;http://raibledesigns.com/rd/entry/implementing_ajax_authentication_using_jquery&quot;&gt;Implementing Ajax Authentication using jQuery, Spring Security and HTTPS&lt;/a&gt;, I explained what I was trying to accomplish.&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
The feature hasn&apos;t been released yet, but basically boils down to allowing users to login without leaving a page. For example, if they want to leave a review on a product, they would click a link, be prompted to login, enter their credentials, then continue to leave their review. The login prompt and subsequent review would likely be implemented using a lightbox. While lightboxes are often seen in webapps these days because they look good, it&apos;s also possible Lightbox UIs provide a poor user experience.
&lt;/p&gt;
&lt;p&gt;I was able to get everything working, &lt;a href=&quot;http://demo.raibledesigns.com/ajax-login/&quot;&gt;posted a demo&lt;/a&gt; and wrote about &lt;a href=&quot;http://raibledesigns.com/rd/entry/upcoming_conferences_tssjs_in_las&quot;&gt;upcoming conferences in Las Vegas and Krak&amp;#243;w&lt;/a&gt;. In that article, I described a new talk I was going to create: &lt;em&gt;Webapp Security: Develop. Penetrate. Protect. Relax.&lt;/em&gt; I ended the month with a post on &lt;a href=&quot;http://raibledesigns.com/rd/entry/fixing_xss_in_jsp_2&quot;&gt;how to fix XSS in JSP 2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;p&gt;On February 25th, I experienced &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_greatest_snow_on_earth&quot;&gt;The Greatest Snow on Earth&lt;/a&gt; with thigh-deep powder and face shots on every run.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe width=&quot;500&quot; height=&quot;311&quot; frameborder=&quot;0&quot; src=&quot;//www.youtube.com/embed/viBBPot4WKY?rel=0&amp;amp;hd=1&quot; title=&quot;YouTube video player&quot;&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;That night, we saw &lt;a href=&quot;http://www.hotbutteredrum.net/&quot;&gt;Hot Buttered Rum&lt;/a&gt; and woke up early for 27&quot; of fresh powder at Alta. The picture of Trish free-heeling at Alta is one of my favorites of the year.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm6.staticflickr.com/5216/5490614643_00cb94c020.jpg&quot; title=&quot;Free Heeling at Alta&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.staticflickr.com/5216/5490614643_00cb94c020.jpg&quot; width=&quot;500&quot; height=&quot;375&quot; alt=&quot;Free Heeling at Alta&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;In early March, we experienced a &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157626199804847/&quot;&gt;suite night at the Avs game&lt;/a&gt;, then I kept it technical and &lt;a href=&quot;http://raibledesigns.com/rd/entry/upgraded_to_apache_roller_5&quot;&gt;upgraded this blog to Apache Roller 5.0, RC4&lt;/a&gt;. I &lt;a href=&quot;http://raibledesigns.com/rd/entry/upgrading_to_jsf_2&quot;&gt;upgraded AppFuse to JSF 2&lt;/a&gt;, wrote about &lt;a href=&quot;http://raibledesigns.com/rd/entry/jsr_303_and_web_framework&quot;&gt;JSR 303 and web framework support&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/adding_search_to_appfuse&quot;&gt;added search to AppFuse using Compass&lt;/a&gt;. When writing about JSF 2, I mentioned replacing Ajax4JSF with RichFaces. 9 months later, it seems like &lt;a href=&quot;http://primefaces.org/&quot;&gt;PrimeFaces&lt;/a&gt; has more momentum, so I may try that instead.
&lt;/p&gt;
&lt;p&gt;For St. Patrick&apos;s Day, we flew to Vegas for TSSJS and &lt;a href=&quot;http://raibledesigns.com/rd/entry/livin_it_up_in_vegas&quot;&gt;had a blast&lt;/a&gt;. Not only did my talks go well, but we had a bunch of friends in town and had much success gambling the nights away.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm6.static.flickr.com/5305/5550023760_e8f128457a.jpg&quot; title=&quot;Caesars Pool&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5305/5550023760_e8f128457a_m.jpg&quot; width=&quot;240&quot; height=&quot;159&quot; alt=&quot;Caesars Pool&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5053/5550024190_b272c2f012.jpg&quot; title=&quot;The Bellagio Fountains&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5053/5550024190_b272c2f012_m.jpg&quot; width=&quot;240&quot; height=&quot;159&quot; alt=&quot;The Bellagio Fountains&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;After delivering my Comparing JVM Web Frameworks talk, I had a very interesting conversation with &lt;a href=&quot;http://macstrac.blogspot.com/&quot;&gt;James Strachan&lt;/a&gt;. He recommended I take a look at &lt;a href=&quot;http://coffeescript.org/&quot;&gt;CoffeeScript&lt;/a&gt; and &lt;a href=&quot;http://jade-lang.com/&quot;&gt;Jade&lt;/a&gt;. A couple months later, when I was thinking of talks for &lt;a href=&quot;http://devoxx.com&quot;&gt;Devoxx&lt;/a&gt;, I added these to my list of technologies to learn and submitted a talk about HTML5 with Play Scala, CoffeeScript and Jade.
&lt;/p&gt;
&lt;p&gt;That Friday, we returned to Denver, got a good night&apos;s sleep then headed on a &lt;a href=&quot;http://raibledesigns.com/rd/entry/peter_estin_hut_trip_in&quot;&gt;hut trip in Colorado&apos;s High Country&lt;/a&gt;. The name of the hut was &lt;a href=&quot;http://www.huts.org/hut_details/peter_estin_hut_details.html&quot;&gt;Peter Estin Hut&lt;/a&gt; and it was a bit of a hike to get to. My friend, Joe, set my expectations correctly when he warned me it&apos;d be a &lt;em&gt;5 hour death march&lt;/em&gt;. It took us 4 hours, 30 minutes and we skied up 2200 vertical feet of switchbacks.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Livin&apos; it up, hut style&quot; href=&quot;http://farm6.static.flickr.com/5251/5549474427_56d389dc71.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;66&quot; style=&quot;border: 1px solid black&quot; alt=&quot;Livin&apos; it up, hut style&quot; src=&quot;//farm6.static.flickr.com/5251/5549474427_56d389dc71_t.jpg&quot;&gt;&lt;/a&gt;

&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;We made it!&quot; href=&quot;http://farm6.static.flickr.com/5027/5549475091_bcff5560a0.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;We made it!&quot; src=&quot;//farm6.static.flickr.com/5027/5549475091_bcff5560a0_t.jpg&quot;&gt;&lt;/a&gt;

&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;At the top of Charles Peak&quot; href=&quot;http://farm6.static.flickr.com/5025/5550058284_18d8a3b874.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;66&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;At the top of Charles Peak&quot; src=&quot;//farm6.static.flickr.com/5025/5550058284_18d8a3b874_t.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Trish and I started off April with a bang by moving in together, then embarking on a &lt;a href=&quot;http://raibledesigns.com/rd/entry/two_opening_days_with_a&quot;&gt;whirlwind trip of two opening days with a stopover in Krak&#243;w&lt;/a&gt;. We flew Business Class from Chicago to Munich (releasing &lt;a href=&quot;http://raibledesigns.com/rd/entry/appfuse_2_1_released&quot;&gt;AppFuse 2.1&lt;/a&gt; just before departing) and were very impressed with Krak&#243;w&apos;s Old Town upon arrival.
  &lt;p style=&quot;text-align: center&quot;&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;St. Mary&apos;s Basilica, Krak&#243;w&quot; href=&quot;http://farm6.static.flickr.com/5188/5618498585_0267da32ce.jpg&quot;&gt;&lt;img width=&quot;75&quot; height=&quot;75&quot; style=&quot;border: 1px solid black&quot; alt=&quot;St. Mary&apos;s Basilica, Krak&#243;w&quot; src=&quot;//farm6.static.flickr.com/5188/5618498585_0267da32ce_s.jpg&quot;&gt;&lt;/a&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Main Market Square&quot; href=&quot;http://farm6.static.flickr.com/5268/5618498729_613983abaf.jpg&quot;&gt;&lt;img width=&quot;75&quot; height=&quot;75&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; alt=&quot;Main Market Square&quot; src=&quot;//farm6.static.flickr.com/5268/5618498729_613983abaf_s.jpg&quot;&gt;&lt;/a&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;St. Mary&apos;s&quot; href=&quot;http://farm6.static.flickr.com/5101/5619084930_87a76dee6b.jpg&quot;&gt;&lt;img width=&quot;75&quot; height=&quot;75&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; alt=&quot;St. Mary&apos;s&quot; src=&quot;//farm6.static.flickr.com/5101/5619084930_87a76dee6b_s.jpg&quot;&gt;&lt;/a&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Flowers&quot; href=&quot;http://farm6.static.flickr.com/5030/5618499011_462ac088a6.jpg&quot;&gt;&lt;img width=&quot;75&quot; height=&quot;75&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; alt=&quot;Flowers&quot; src=&quot;//farm6.static.flickr.com/5030/5618499011_462ac088a6_s.jpg&quot;&gt;&lt;/a&gt;

  &lt;/p&gt;
  &lt;p&gt;On that trip, I especially enjoyed meeting Trish&apos;s brother for the first time and watching the Red Sox win their first game of the year.&lt;/p&gt;
  &lt;p style=&quot;text-align: center&quot;&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Fenway Paak!&quot; href=&quot;http://farm6.static.flickr.com/5222/5618502949_cdfbc9d030.jpg&quot;&gt;&lt;img width=&quot;75&quot; height=&quot;75&quot; style=&quot;border: 1px solid black&quot; alt=&quot;Fenway Paak!&quot; src=&quot;//farm6.static.flickr.com/5222/5618502949_cdfbc9d030_s.jpg&quot;&gt;&lt;/a&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Morse and Kidder&quot; href=&quot;http://farm6.static.flickr.com/5263/5618503117_28b4b2b8cc.jpg&quot;&gt;&lt;img width=&quot;75&quot; height=&quot;75&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; alt=&quot;Morse and Kidder&quot; src=&quot;//farm6.static.flickr.com/5263/5618503117_28b4b2b8cc_s.jpg&quot;&gt;&lt;/a&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Happy Siblings&quot; href=&quot;http://farm6.static.flickr.com/5061/5618503321_c766f1e7bc.jpg&quot;&gt;&lt;img width=&quot;75&quot; height=&quot;75&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; alt=&quot;Happy Siblings&quot; src=&quot;//farm6.static.flickr.com/5061/5618503321_c766f1e7bc_s.jpg&quot;&gt;&lt;/a&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Erika and Julie&quot; href=&quot;http://farm6.static.flickr.com/5146/5619089798_4aca920bfb.jpg&quot;&gt;&lt;img width=&quot;75&quot; height=&quot;75&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; alt=&quot;Erika and Julie&quot; src=&quot;//farm6.static.flickr.com/5146/5619089798_4aca920bfb_s.jpg&quot;&gt;&lt;/a&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Red Sox Win!&quot; href=&quot;http://farm6.static.flickr.com/5145/5619090216_2198246d63.jpg&quot;&gt;&lt;img width=&quot;75&quot; height=&quot;75&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; alt=&quot;Red Sox Win!&quot; src=&quot;//farm6.static.flickr.com/5145/5619090216_2198246d63_s.jpg&quot;&gt;&lt;/a&gt;
  &lt;/p&gt;
&lt;p&gt;After returning, I realized I lost a lot of data in my Roller 5 upgrade and &lt;a href=&quot;http://raibledesigns.com/rd/entry/be_careful_when_switching_mysql&quot;&gt;wrote about what happened and how I recovered it&lt;/a&gt;. Then we &lt;a href=&quot;http://raibledesigns.com/rd/entry/farewell_to_the_2010_2011&quot;&gt;bid farewell to the 2010-2011 ski season&lt;/a&gt; and got ready for mountain bike season.
  &lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
For next year, I think I&apos;ll keep my goal at 30 days. If everything works out as planned, we&apos;ll have a place in the mountains this fall and it&apos;ll be a bit easier to hit the slopes without sitting in traffic. For now, I&apos;m pumped about the beginning of mountain bike season.
&lt;/p&gt;
&lt;p&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; ref=&quot;http://farm3.staticflickr.com/2181/5712084350_217de950a5.jpg&quot; title=&quot;Door to Sauna&quot;&gt;&lt;img src=&quot;//farm3.staticflickr.com/2181/5712084350_217de950a5_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Door to Sauna&quot; class=&quot;picture&quot;&gt;&lt;/a&gt;
  
May arrived and Trish and I started looking for a place in the mountains. We found an &lt;a href=&quot;https://www.facebook.com/media/set/?set=a.10150158165601712.292395.571296711&amp;amp;type=1&amp;amp;l=80b0b43473&quot;&gt;very cool cabin&lt;/a&gt;, but later decided it was &lt;em&gt;too&lt;/em&gt; nice and we&apos;d rather have a condo. I finished &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_basement_sauna_project&quot;&gt;The Basement Sauna Project&lt;/a&gt; and wrote about Java Web Application Security: &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part&quot;&gt;Java EE 6&lt;/a&gt;, &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part1&quot;&gt;Spring Security&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part2&quot;&gt;Apache Shiro&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;On May 21st, we again visited Winter Park and Fraser to look at condos, then drove back to Denver for &lt;a href=&quot;http://www.denverpost.com/commented/ci_18114909&quot;&gt;U2 at Mile High Stadium&lt;/a&gt;. I&apos;m not a big fan of U2, but this was quite possibly the best concert I&apos;ve ever been to. The experience of 70,000+ fans, all screaming, doing the wave, and loving life was epic. We decided that night that we liked one of the condos more than the rest and put in an offer the following week. The kids headed off to Florida for a month with their Mom and we drove to Utah for &lt;a href=&quot;http://raibledesigns.com/rd/entry/music_mountain_biking_and_memories&quot;&gt;Desert Rocks and mountain biking in Moab&lt;/a&gt;. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;https://fbcdn-sphotos-f-a.akamaihd.net/hphotos-ak-ash3/253034_2099846942595_2382489_n.jpg&quot; title=&quot;La Sal Mountains from Desert Rocks&quot; rel=&quot;lightbox[desertrocks2011]&quot;&gt;&lt;img src=&quot;//fbcdn-photos-a.akamaihd.net/hphotos-ak-snc6/253034_2099846942595_1438065285_32404850_2382489_a.jpg&quot; width=&quot;180&quot; height=&quot;120&quot; alt=&quot;La Sal Mountains from Desert Rocks&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a rev=&quot;http://www.flickr.com/photos/mcginityphoto/8358915594/&quot; href=&quot;http://farm9.staticflickr.com/8467/8358915594_e79cd2231d_c.jpg&quot; title=&quot;Scenic Byway&quot; rel=&quot;lightbox[desertrocks2011]&quot;&gt;&lt;img src=&quot;//farm9.staticflickr.com/8467/8358915594_e79cd2231d.jpg&quot; width=&quot;180&quot; height=&quot;120&quot; alt=&quot;Scenic Byway&quot; style=&quot;border: 1px solid black; margin-left: 20px&quot;&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;https://sphotos-a.xx.fbcdn.net/hphotos-frc1/250385_2099847942620_1801230_n.jpg&quot; title=&quot;Bar-B or Killer B?&quot; rel=&quot;lightbox[desertrocks2011]&quot;&gt;&lt;img src=&quot;//sphotos-a.xx.fbcdn.net/hphotos-frc1/p206x206/250385_2099847942620_1801230_n.jpg&quot; width=&quot;180&quot; height=&quot;120&quot; alt=&quot;Bar-B or Killer B?&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a rev=&quot;http://www.flickr.com/photos/mcginityphoto/8359032204/&quot; href=&quot;http://farm9.staticflickr.com/8049/8359032204_ace553c370_c.jpg&quot; title=&quot;Three Gossips and Tower of Babel&quot; rel=&quot;lightbox[desertrocks2011]&quot;&gt;&lt;img src=&quot;//farm9.staticflickr.com/8049/8359032204_ace553c370.jpg&quot; width=&quot;180&quot; height=&quot;120&quot; alt=&quot;Three Gossips and Tower of Babel&quot; style=&quot;border: 1px solid black; margin-left: 20px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;I &lt;a href=&quot;http://raibledesigns.com/rd/entry/upgraded_to_roller_5_and&quot;&gt;Upgraded to Roller 5.0&lt;/a&gt; in June and showed how to add a &lt;a href=&quot;https://developers.facebook.com/docs/reference/plugins/like/&quot;&gt;Facebook Like button&lt;/a&gt;. Next, I transcribed a couple more Java Web Application Security articles: &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part3&quot;&gt;programmatic login APIs&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part4&quot;&gt;penetrating with Zed Attack Proxy&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;The kids returned to us just before the &lt;a href=&quot;http://raibledesigns.com/rd/entry/good_times_on_the_annual&quot;&gt;annual Father&apos;s Day Camping Trip&lt;/a&gt;. We drove to Lake Granby and stayed at &lt;a href=&quot;http://campincolorado.com/federal/arapaho_roosevelt_nf/stillwater/stillwater.html&quot;&gt;Stillwater Campground&lt;/a&gt; for the weekend.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm6.static.flickr.com/5275/5850616117_57971bfd55.jpg&quot; title=&quot;Stillwater Campground Rocks!&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5275/5850616117_57971bfd55_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Stillwater Campground Rocks!&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3182/5851171484_b745090d35.jpg&quot; title=&quot;Beautiful Colorado&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3182/5851171484_b745090d35_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Beautiful Colorado&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;From my Father&apos;s Day post:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;I really enjoyed spending so much time with my family this weekend. The good news is we get to do it again when I meet them at The Cabin in Montana next week. In the meantime, Trish and I are off to &lt;a href=&quot;http://jazoon.com/&quot;&gt;Jazoon&lt;/a&gt; for a few days of fun in Switzerland.
&lt;/p&gt;
&lt;p&gt;A few days later, we were &lt;a href=&quot;http://raibledesigns.com/rd/entry/a_sweet_trip_to_switzerland&quot;&gt;in Zurich for the first time&lt;/a&gt;, enjoying our accommodations and marveling at Switzerland&apos;s excellent transportation system.
I experienced an interesting situation while speaking, but quickly forgot when we visited Rhine Falls, celebrated our anniversary at Gruelich and played in the Swiss Alps.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;http://farm7.static.flickr.com/6030/5879428306_a793f2a67e.jpg&quot; title=&quot;View from Great Church&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm7.static.flickr.com/6030/5879428306_a793f2a67e_s.jpg&quot; width=&quot;75&quot; height=&quot;75&quot; alt=&quot;View from Great Church&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5080/5879428652_e847f2ff0c.jpg&quot; title=&quot;Happy Couple in Z&#252;rich&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5080/5879428652_e847f2ff0c_s.jpg&quot; width=&quot;75&quot; height=&quot;75&quot; alt=&quot;Happy Couple in Z&#252;rich&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;http://farm6.static.flickr.com/5108/5879429020_21dd2b6ddf.jpg&quot; title=&quot;Riding the Train&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5108/5879429020_21dd2b6ddf_s.jpg&quot; width=&quot;75&quot; height=&quot;75&quot; alt=&quot;Riding the Train&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;http://farm7.static.flickr.com/6005/5879429424_275a73ac3d.jpg&quot; title=&quot;Rhine Falls!&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm7.static.flickr.com/6005/5879429424_275a73ac3d_s.jpg&quot; width=&quot;75&quot; height=&quot;75&quot; alt=&quot;Rhine Falls!&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5112/5878867297_cac4cd43c9.jpg&quot; title=&quot;Whoa!&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5112/5878867297_cac4cd43c9_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Whoa!&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5183/5881479860_7ef4ba409e.jpg&quot; title=&quot;Rhine Falls Flowers&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5183/5881479860_7ef4ba409e_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Rhine Falls Flowers&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5320/5880917345_38968f556c.jpg&quot; title=&quot;Olives and Sprouts&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5320/5880917345_38968f556c_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Olives and Sprouts&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5144/5880917787_cfcb0012ce.jpg&quot; title=&quot;Scallops and Tomato&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5144/5880917787_cfcb0012ce_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Scallops and Tomato&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm7.static.flickr.com/6018/5878966083_8bef3238da.jpg&quot; title=&quot;Dessert at Greulich&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm7.static.flickr.com/6018/5878966083_8bef3238da_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Dessert at Greulich&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5151/5878966527_7634f8a94e.jpg&quot; title=&quot;Greulich&apos;s Backyard Trees&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5151/5878966527_7634f8a94e_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Greulich&apos;s Backyard Trees&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;p&gt;We arrived back in Denver at 6pm on Sunday, June 26th and I flew to Montana at 8am the next morning. I worked from The Cabin that week and &lt;a href=&quot;http://raibledesigns.com/rd/entry/agile_hiring_book_review&quot;&gt;wrote a book review for Agile Hiring&lt;/a&gt;.
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
I think Sean [Landis] does a great job in showing how you can apply agile principles (people over process, tracking tools, failing fast, continuous improvement, constant feedback) to improve your hiring process. As a person that interviews often, I think it also gives great insights into how companies interview and what they&apos;re looking for. I&apos;ve often thought that being honest about my skills and what I&apos;m looking for is a good tactic and this book seems to confirm that.
&lt;/p&gt;
&lt;p&gt;That weekend, it was the &quot;90s Reunion&quot; for the Seeley Swan High School, which I attended my freshman and sophomore year of high school. There were several highlights of the trip, but one of my favorites was our float in the Swan Valley Parade. Abbie came up with the idea (Happy Birthday America) and we decorated an old trailer with streamers, balloons and a birthday cake to celebrate. Abbie made up a song and sang it throughout the entire parade (with a portable microphone and amp).
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Abbie singing &amp;quot;Happy Birthday America&amp;quot;&quot; href=&quot;http://farm7.static.flickr.com/6130/5934498303_10250c2760.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;border: 1px solid black&quot; alt=&quot;Abbie singing &amp;quot;Happy Birthday America&amp;quot;&quot; src=&quot;//farm7.static.flickr.com/6130/5934498303_10250c2760_t.jpg&quot;&gt;&lt;/a&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Abbie before getting dunked&quot; href=&quot;http://farm7.static.flickr.com/6020/5934498549_38f1793c46.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;margin-left: 0px; border: 1px solid black&quot; alt=&quot;Abbie before getting dunked&quot; src=&quot;//farm7.static.flickr.com/6020/5934498549_38f1793c46_t.jpg&quot;&gt;&lt;/a&gt;
&lt;a rel=&quot;lightbox[4thofjuly2011]&quot; title=&quot;Fiddlin&apos; Trish&quot; href=&quot;http://farm7.static.flickr.com/6002/5934499269_c40b347316.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;margin-left: 0px; border: 1px solid black&quot; alt=&quot;Fiddlin&apos; Trish&quot; src=&quot;//farm7.static.flickr.com/6002/5934499269_c40b347316_t.jpg&quot;&gt;&lt;/a&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Paddleboating&quot; href=&quot;http://farm7.static.flickr.com/6123/5935065040_59657b06fa.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;margin-left: 0px; border: 1px solid black&quot; alt=&quot;Paddleboating&quot; src=&quot;//farm7.static.flickr.com/6123/5935065040_59657b06fa_t.jpg&quot;&gt;&lt;/a&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Lake McDonald, Glacier National Park&quot; href=&quot;http://farm7.static.flickr.com/6006/5935068822_cfd7c86009.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;margin-left: 0px; border: 1px solid black&quot; alt=&quot;Lake McDonald, Glacier National Park&quot; src=&quot;//farm7.static.flickr.com/6006/5935068822_cfd7c86009_t.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I went swimming with my iPhone 4 that Sunday and Trish and her Dad showed up a few hours later. On the 4th, we had a blast celebrating the holiday with mine and my parents&apos; old friends. The next day, we adventured to Glacier National Park, where Trish shot an &lt;a href=&quot;http://www.mcginityphoto.com/Nature/Nature/4725995_JRpvJB/9/1373210164_W4mgd99#!i=1373210164&amp;amp;k=W4mgd99&quot;&gt;awesome sunrise at Lake McDonald&lt;/a&gt;.
She also captured a beautiful picture of The Cabin at sunset that week.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rel=&quot;lightbox[4thofjuly2011]&quot; title=&quot;The Raible Cabin by Trish McGinity&quot; href=&quot;http://farm7.static.flickr.com/6122/5933924991_8dde37f131.jpg&quot;&gt;&lt;img width=&quot;500&quot; height=&quot;333&quot; style=&quot;border: 1px solid black&quot; alt=&quot;The Raible Cabin&quot; src=&quot;//farm7.static.flickr.com/6122/5933924991_8dde37f131.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;In between vacationing in Montana and writing about it, I wrote some technical posts:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_oauth_with_appfuse_and&quot;&gt;Integrating OAuth with AppFuse and its REST API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/installing_openjdk_7_on_os&quot;&gt;Installing OpenJDK 7 on OS X&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We returned to Denver in mid-July and shipped the kids off to Florida just before my annual Birthday Golf Debacle. We teed off at Wellshire Golf Course and had one of the most well-behaved rounds in a few years. The next weekend, we closed on our &quot;Ski Shack&quot; in Fraser and I penned &lt;a href=&quot;http://raibledesigns.com/rd/entry/another_dream_realized_mountain_views&quot;&gt;Another Dream Realized: Mountain Views&lt;/a&gt;. Trish&apos;s &lt;a href=&quot;http://www.flickr.com/photos/mcginityphoto/6716291441&quot;&gt;October Sunset photo&lt;/a&gt; is one of my favorite glimpses of our view.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm8.staticflickr.com/7155/6716291441_c70eb5e378.jpg&quot; rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;October Sunset from our dock&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7155/6716291441_c70eb5e378.jpg&quot; alt=&quot;October Sunset in Fraser&quot; width=&quot;400&quot; height=&quot;269&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next, I blogged about &lt;a href=&quot;http://raibledesigns.com/rd/entry/how_do_you_get_started&quot;&gt;How do you get started in programming?&lt;/a&gt; and we headed to the airport a few hours later for a whirlwind trip from Oregon to Cape Cod. &lt;em&gt;That&lt;/em&gt; was a wonderful trip and it took me almost a month &lt;a href=&quot;http://raibledesigns.com/rd/entry/oregon_cape_cod_and_fun&quot;&gt;to write about it&lt;/a&gt;. We flew into Portland and spent the weekend hiking in Silver Falls and drinking good beer at the &lt;a href=&quot;http://www.oregonbrewfest.com/&quot;&gt;Oregon Brewers Festival&lt;/a&gt; and &lt;a href=&quot;http://www.mcmenamins.com/54-edgefield-home&quot;&gt;Edgefield&lt;/a&gt;. We stayed with my good friends Clint and Autumn (married in &lt;a href=&quot;http://raibledesigns.com/rd/entry/costa_rica_was_awesome&quot;&gt;Costa Rica in 2008&lt;/a&gt;), who had their first child only a few weeks after our visit (August 26th).
&lt;/p&gt;
&lt;p&gt;We had an awful early flight out of Portland to Boston that Sunday. On Monday afternoon, we picked up Abbie and Jack from the Boston airport. They flew up from West Palm Beach on their first unaccompanied minors flight. We drove them to Cape Cod and settled into Trish&apos;s parents house near the water. The rest of the week, we had a blast with our friends Chris and Julie and the entire McGinity clan. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Wheeee!!&quot; href=&quot;http://farm7.static.flickr.com/6022/6008443089_cc4f752c0f.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;border: 1px solid black&quot; alt=&quot;Wheeee!!&quot; src=&quot;//farm7.static.flickr.com/6022/6008443089_cc4f752c0f_t.jpg&quot;&gt;&lt;/a&gt;

&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Hercules!&quot; href=&quot;http://farm7.static.flickr.com/6006/6008999952_78fd13f415.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Hercules!&quot; src=&quot;//farm7.static.flickr.com/6006/6008999952_78fd13f415_t.jpg&quot;&gt;&lt;/a&gt;

&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Michael and Jack&quot; href=&quot;http://farm7.static.flickr.com/6125/6044153539_84019058e4.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Michael and Jack&quot; src=&quot;//farm7.static.flickr.com/6125/6044153539_84019058e4_t.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Monkey Shadows&quot; href=&quot;http://farm7.static.flickr.com/6133/6044703126_cb16505a0c.jpg&quot;&gt;&lt;img width=&quot;240&quot; height=&quot;180&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Monkey Shadows&quot; src=&quot;//farm7.static.flickr.com/6133/6044703126_cb16505a0c_m.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
We spent the rest of August going to concerts at Red Rocks, beer festivals in Winter Park, mountain biking, hiking, taking the kids to the Ski Shack and playing with Crazy Sagan. 
&lt;a href=&quot;http://farm7.staticflickr.com/6087/6044208823_60c83e67c9.jpg&quot; title=&quot;Crazy Sagan!&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6087/6044208823_60c83e67c9_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Crazy Sagan!&quot; class=&quot;picture&quot; style=&quot;margin-top: 5px&quot;&gt;&lt;/a&gt;
In my only August post, I talked a lot about the Broncos, Hawaii, Devoxx and leaving Overstock.&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
  That pretty much catches you up-to-date with the goings on in my life. As you can tell, it&apos;s been a &lt;em&gt;great&lt;/em&gt; summer so far. I&apos;m really looking forward to the fall too. Broncos season, a trip to Hawaii, learning new technologies, talking about them at Devoxx and a new gig.
  &lt;br/&gt;...&lt;br/&gt;
  Tomorrow is Jack&apos;s birthday. I gotta run ... it&apos;s time to go buy a bike, play a little golf, hit the pool and go to the BBQ before tonight&apos;s CD Release Party. 
&lt;/p&gt;
&lt;p&gt;We watched proudly as Jack turned 7 the next day and loved his excitement when he got his first mountain bike.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;http://farm7.staticflickr.com/6173/6168228852_44f34ab78d.jpg&quot; title=&quot;7 Miles and ready for more&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6173/6168228852_44f34ab78d_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;7 Miles and ready for more&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
  &lt;/p&gt;
&lt;p&gt;September started with mountain breezes and &lt;a href=&quot;http://raibledesigns.com/rd/entry/labor_day_weekend_in_grand&quot;&gt;fishing at Lake Granby&lt;/a&gt;. Lots of friends, family and delicious food make for a heckuva 3-day weekend. Jack was the only one to catch a fish and you couldn&apos;t wipe the smile off his face for the rest of the day.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;The delicious fish that Jack caught at Lake Granby&quot; href=&quot;http://farm7.static.flickr.com/6189/6112833896_59bd8ecc99.jpg&quot;&gt;&lt;img width=&quot;500&quot; height=&quot;375&quot; style=&quot;border: 1px solid black&quot; alt=&quot;The delicious fish that Jack caught at Lake Granby&quot; src=&quot;//farm7.static.flickr.com/6189/6112833896_59bd8ecc99.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I described my &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_digital_diet&quot;&gt;Digital Diet&lt;/a&gt; and wrote my first article related to my Devoxx talk: &lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_scalate_and_jade_with&quot;&gt;Integrating Scalate and Jade with Play 1.2.3&lt;/a&gt;. The 2nd weekend in September, we enjoyed a &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157627717258988/&quot;&gt;September Sports Weekend&lt;/a&gt;, going to two Rockies games and the Monday night Broncos Opener before heading to Kauai. While the Broncos didn&apos;t win that game, Trish&apos;s shot of Brett, Joe and I sums up many-a-game this season.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm7.staticflickr.com/6168/6185423596_e62d1e1efd.jpg&quot; title=&quot;Broncos Home Opener&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6168/6185423596_e62d1e1efd.jpg&quot; width=&quot;500&quot; height=&quot;333&quot; alt=&quot;Broncos Home Opener&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;p&gt;As expected, &lt;a href=&quot;http://raibledesigns.com/rd/entry/mahalo_kauai&quot;&gt;Kauai blew our minds&lt;/a&gt;. We saw several spectacular sunsets, did some Stand Up Paddling (it&apos;s harder than it looks), played golf, took a doorless helicopter ride and kayaked along the Na Pali coast. &lt;/p&gt;
&lt;table style=&quot;margin: 0 auto 5px auto&quot; cellspacing=&quot;10&quot;&gt;
  &lt;tr&gt;
    &lt;td rowspan=&quot;3&quot;&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm7.staticflickr.com/6154/6174598580_f440fdfc48.jpg&quot; title=&quot;HDR Sunset next to the palm trees on the beach at Hanalei Bay by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6154/6174598580_f440fdfc48_m.jpg&quot; width=&quot;156&quot; height=&quot;240&quot; alt=&quot;HDR Sunset next to the palm trees on the beach at Hanalei Bay&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
  &lt;/td&gt;
  &lt;td&gt;
    &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm7.staticflickr.com/6153/6174087039_b3740f60b7.jpg&quot; title=&quot;Hanalei Bay Sunset HDR by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6153/6174087039_b3740f60b7_t.jpg&quot; width=&quot;100&quot; height=&quot;66&quot; alt=&quot;Hanalei Bay Sunset HDR&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
    &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm7.staticflickr.com/6159/6174622520_87c18de29c.jpg&quot; title=&quot;Makai Golf Club my pitch out of the sand is next to the pin.  Matt&apos;s is on the edge of the green :) by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6159/6174622520_87c18de29c_t.jpg&quot; width=&quot;100&quot; height=&quot;67&quot; alt=&quot;Makai Golf Club my pitch out of the sand is next to the pin.  Matt&apos;s is on the edge of the green :)&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;&gt;&lt;/a&gt;
  &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;
    &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm7.staticflickr.com/6154/6174624336_9065acfafa.jpg&quot; title=&quot;Bougainvillia on the Makai Golf course looking across Hanalei Bay by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6154/6174624336_9065acfafa_t.jpg&quot; width=&quot;100&quot; height=&quot;66&quot; alt=&quot;Bougainvillia on the Makai Golf course looking across Hanalei Bay&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
    &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm7.staticflickr.com/6153/6174630996_bee864d25d.jpg&quot; title=&quot;2 Blue Hawai&apos;i on the beach in Hanalei Bay by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6153/6174630996_bee864d25d_t.jpg&quot; width=&quot;100&quot; height=&quot;67&quot; alt=&quot;2 Blue Hawai&apos;i on the beach in Hanalei Bay&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;&gt;&lt;/a&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;
    &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm7.staticflickr.com/6178/6174149421_49cc20532c.jpg&quot; title=&quot;Rainbow to Kalalau Valley Napali Coast State Park by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6178/6174149421_49cc20532c.jpg&quot; width=&quot;100&quot; height=&quot;67&quot; alt=&quot;Rainbow to Kalalau Valley Napali Coast State Park&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
    &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm7.staticflickr.com/6174/6174681482_01c2422fd3.jpg&quot; title=&quot;Wahooo That was Awesome! :) by McGinityPhoto, on Flickr&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6174/6174681482_01c2422fd3_t.jpg&quot; width=&quot;100&quot; height=&quot;67&quot; alt=&quot;Wahooo That was Awesome! :)&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;&gt;&lt;/a&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;We never got bored of the view from our room.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Aloha in the morning at the St Regis Hanalei Bay by McGinityPhoto, on Flickr&quot; href=&quot;http://farm7.staticflickr.com/6157/6174599098_879e9d9aa4.jpg&quot;&gt;&lt;img width=&quot;500&quot; height=&quot;331&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Aloha in the morning at the St Regis Hanalei Bay&quot; src=&quot;//farm7.staticflickr.com/6157/6174599098_879e9d9aa4.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Upon our return, I &lt;a href=&quot;http://raibledesigns.com/rd/entry/trying_to_make_coffeescript_work&quot;&gt;tried to make CoffeeScript work with Scalate&lt;/a&gt; and 
&lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_html5_boilerplate_with_scalate&quot;&gt;integrated HTML5 Boilerplate with Play&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://fbcdn-photos-a.akamaihd.net/hphotos-ak-snc7/309585_10150334101446712_571296711_8306949_270832760_n.jpg&quot; title=&quot;Halloween&quot;&gt;&lt;img src=&quot;//fbcdn-photos-a.akamaihd.net/hphotos-ak-snc7/309585_10150334101446712_571296711_8306949_270832760_a.jpg&quot; alt=&quot;Halloween&quot; width=&quot;180&quot; height=&quot;139&quot; class=&quot;picture&quot; style=&quot;margin-top: 0; border: 1px solid black&quot;&gt;&lt;/a&gt;
October was a quiet month on this blog. I only wrote two articles, one about &lt;a href=&quot;http://raibledesigns.com/rd/entry/increasing_my_developer_happiness&quot;&gt;increasing my developer happiness&lt;/a&gt; and another about &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_with_html5_coffeescript_and&quot;&gt;developing with HTML5, CoffeeScript and Twitter&apos;s Bootstrap&lt;/a&gt;. Watching the Broncos in October was painful at first, buy many rejoiced when Tebow started against Miami (10/23) and we had the amazing comeback to win. We went to the next game against the Lions and were quickly shown they had a long ways to go. We dressed up as the Scary Family for Halloween and had a ball.
&lt;/p&gt;
&lt;p&gt;I made up for October&apos;s lack of writing by writing 9 articles in November. I started with &lt;a href=&quot;http://raibledesigns.com/rd/entry/play_scala_s_anorm_heroku&quot;&gt;complaints about Play Scala&apos;s Anorm and PostgreSQL&lt;/a&gt;, then &lt;a href=&quot;http://raibledesigns.com/rd/entry/happy_9th_birthday_abbie&quot;&gt;celebrated Abbie&apos;s 9th Birthday&lt;/a&gt; with a &lt;a href=&quot;http://www.flickr.com/photos/mraible/6316702824&quot;&gt;Magic Show&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;a href=&quot;http://farm7.staticflickr.com/6117/6316702372_40594e7cbf.jpg&quot; title=&quot;Happy Kids&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6117/6316702372_40594e7cbf_m.jpg&quot; width=&quot;240&quot; height=&quot;160&quot; alt=&quot;Happy Kids&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
  &lt;a href=&quot;http://farm7.staticflickr.com/6047/6316702824_e46bacdc72.jpg&quot; title=&quot;Birthday Crew&quot; rel=&quot;lightbox[yearinreview2011]&quot;&gt;&lt;img src=&quot;//farm7.staticflickr.com/6047/6316702824_e46bacdc72_m.jpg&quot; width=&quot;240&quot; height=&quot;160&quot; alt=&quot;Birthday Crew&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;The next week, I wrote about my &lt;a href=&quot;http://raibledesigns.com/rd/entry/new_macbook_pro_and_imac&quot;&gt;new MacBook Pro and iMac&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/more_scalate_goodness_for_play&quot;&gt;more Scalate goodness for Play&lt;/a&gt;. At this point, I was scrambling to finish up my &lt;em&gt;Play More!&lt;/em&gt; application for &lt;a href=&quot;http://www.devoxx.com/display/DV11/Home&quot;&gt;Devoxx&lt;/a&gt; and worked a lot of late nights. That weekend, I &lt;a href=&quot;http://raibledesigns.com/rd/entry/phonegap_to_the_rescue&quot;&gt;used PhoneGap&lt;/a&gt; to turn my webapp into a native app and finished everything in the nick of time. We flew to Paris that Monday, took the train to Antwerp on Tuesday and settled in for a memorable week of interesting talks.
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/play_2_0_a_web&quot;&gt;Play 2.0, A web framework for a new era&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/phonegap_for_hybrid_app_development&quot;&gt;PhoneGap for Hybrid App Development&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/deploying_java_and_play_framework&quot;&gt;Deploying Java and Play Framework Apps to the Cloud with James Ward&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/my_html5_with_play_scala&quot;&gt;My HTML5 with Play Scala, CoffeeScript and Jade Presentation from Devoxx 2011&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Crew at Devoxx dinner by McGinity Photo&quot; href=&quot;http://farm8.staticflickr.com/7006/6448345655_df403b1cfd.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;67&quot; style=&quot;border: 1px solid black&quot; alt=&quot;Matt Raible and Crew at Devoxx dinner&quot; src=&quot;//farm8.staticflickr.com/7006/6448345655_df403b1cfd_t.jpg&quot;&gt;&lt;/a&gt;

  
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;At Pelgrom by McGinity Photo&quot; href=&quot;http://farm8.staticflickr.com/7019/6448347213_5e9c59ba8c.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;67&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Matt Raible at Pelgrom&quot; src=&quot;//farm8.staticflickr.com/7019/6448347213_5e9c59ba8c_t.jpg&quot;&gt;&lt;/a&gt;

  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;James Ward speaking on Heroku at Devoxx by McGinity Photo&quot; href=&quot;http://farm8.staticflickr.com/7147/6448349163_313bc48dd5.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;67&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;James Ward speaking on Heroku at Devoxx&quot; src=&quot;//farm8.staticflickr.com/7147/6448349163_313bc48dd5_t.jpg&quot;&gt;&lt;/a&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Speaking at Devoxx Belgium 2011 by McGinity Photo&quot; href=&quot;http://farm8.staticflickr.com/7031/6448350561_e62da3327b.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;67&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Matt Raible speaking at Devoxx Belgium 2011&quot; src=&quot;//farm8.staticflickr.com/7031/6448350561_e62da3327b_t.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Antwerp Town Square by McGinity Photo&quot; href=&quot;http://farm8.staticflickr.com/7002/6716294395_28ce2c5f5b.jpg&quot;&gt;&lt;img width=&quot;240&quot; height=&quot;160&quot; style=&quot;border: 1px solid black&quot; alt=&quot;Antwerp Town Square&quot; src=&quot;//farm8.staticflickr.com/7002/6716294395_28ce2c5f5b_m.jpg&quot;&gt;&lt;/a&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Riverside in Antwerp by McGinity Photo&quot; href=&quot;http://farm8.staticflickr.com/7010/6448353693_f63f7afee6.jpg&quot;&gt;&lt;img width=&quot;240&quot; height=&quot;160&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Riverside in Antwerp&quot; src=&quot;//farm8.staticflickr.com/7010/6448353693_f63f7afee6_m.jpg&quot;&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;That Saturday, we took the train back to Paris and checked into our hotel for a few days of romance. I proposed to Trish at Versailles on Sunday at sunset and we rolled around in our joy for a few days before we told any of our friends. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;The Versailles Orangerie&quot; href=&quot;http://farm8.staticflickr.com/7009/6402228135_6ffc860b9f.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;border: 1px solid black&quot; alt=&quot;The Versailles Orangerie&quot; src=&quot;//farm8.staticflickr.com/7009/6402228135_6ffc860b9f_t.jpg&quot;&gt;&lt;/a&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Ch&#226;teau de Versailles&quot; href=&quot;http://farm8.staticflickr.com/7141/6402228667_2e908c6fb0.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Ch&#226;teau de Versailles&quot; src=&quot;//farm8.staticflickr.com/7141/6402228667_2e908c6fb0_t.jpg&quot;&gt;&lt;/a&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Gardens of Versailles&quot; href=&quot;http://farm8.staticflickr.com/7161/6402229087_0d34f8f6f9.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Gardens of Versailles&quot; src=&quot;//farm8.staticflickr.com/7161/6402229087_0d34f8f6f9_t.jpg&quot;&gt;&lt;/a&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Trees in the Versailles Gardens&quot; href=&quot;http://farm8.staticflickr.com/7023/6402230475_9251f0664c.jpg&quot;&gt;&lt;img width=&quot;100&quot; height=&quot;75&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Trees in the Versailles Gardens&quot; src=&quot;//farm8.staticflickr.com/7023/6402230475_9251f0664c_t.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Bassin d&#8217;Apollon &amp;ndash; the Apollo Fountain by McGinity Photo&quot; href=&quot;http://farm8.staticflickr.com/7156/6716294893_7a8ed53bf5.jpg&quot;&gt;&lt;img width=&quot;500&quot; height=&quot;329&quot; alt=&quot;Bassin d&#8217;Apollon &amp;ndash; the Apollo Fountain&quot; src=&quot;//farm8.staticflickr.com/7156/6716294893_7a8ed53bf5.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;  
&lt;p&gt;
We flew back to the US the Wednesday before Christmas and spent the weekend in Boston with Trish&apos;s family. For full details of that trip, see &lt;a href=&quot;http://raibledesigns.com/rd/entry/our_engaging_trip_to_paris&quot;&gt;Our Engaging Trip to Paris and Antwerp&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Happy&quot; href=&quot;http://farm7.staticflickr.com/6031/6402231033_9a0f51938c.jpg&quot;&gt;&lt;img width=&quot;240&quot; height=&quot;180&quot; style=&quot;border: 1px solid black&quot; alt=&quot;Happy&quot; src=&quot;//farm7.staticflickr.com/6031/6402231033_9a0f51938c_m.jpg&quot;&gt;&lt;/a&gt;
&lt;a rel=&quot;lightbox[yearinreview2011]&quot; title=&quot;Versailles Sunset&quot; href=&quot;http://farm8.staticflickr.com/7018/6402232723_e61d57cc98.jpg&quot;&gt;&lt;img width=&quot;240&quot; height=&quot;180&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; alt=&quot;Versailles Sunset&quot; src=&quot;//farm8.staticflickr.com/7018/6402232723_e61d57cc98_m.jpg&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;To end the year, I kept it light and only spun up one blog post in December: &lt;a href=&quot;http://raibledesigns.com/rd/entry/what_have_i_been_working&quot;&gt;What have I been working on at Taleo?&lt;/a&gt; A week after writing that post, we moved to the Ski Shack for 3 weeks and enjoyed a &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157628628439665/&quot;&gt;wonderful holiday break&lt;/a&gt; with &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157628725392081/&quot;&gt;many visitors&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm8.staticflickr.com/7150/6638934399_2fb67c7883.jpg&quot; title=&quot;Shredders&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7150/6638934399_2fb67c7883_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Shredders&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm8.staticflickr.com/7031/6638937219_8623aa8e63.jpg&quot; title=&quot;Happy New Year!&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7031/6638937219_8623aa8e63_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Happy New Year!&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Yes, 2011 was a spectacular year. We traveled to four different countries, did a lot of camping and mountain biking and accomplished 2/3 of my 5 year goals (basement sauna and mountain views). I wrote a lot of technical blog posts in the 2nd half of the year; most inspired my extracurricular activities&lt;/a&gt;. I plan to continue that this year as I learn more about HTML5, Play Framework, Scala and CoffeeScript. At the end of last year&apos;s &lt;a href=&quot;http://raibledesigns.com/rd/entry/2010_a_year_in_review&quot;&gt;Year in Review&lt;/a&gt;, I wrote:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
In 2011, I plan on doing two main things: keep rockin&apos; it with Trish and finishing The Bus.
&lt;/p&gt;
&lt;p&gt;I think I can safely say I kept it rockin&apos; with Trish - we&apos;re living together, engaged and still amazed we found one another. As for The Bus, I think &lt;a href=&quot;http://www.motorworksrestorations.com/&quot;&gt;MotorWorks Restorations&lt;/a&gt; and I are in a good position to make a final push and finish the sucker. My hope is to have it done by May so I can start driving it and taking it to VW Shows. In the meantime, Trish has started working on &lt;a href=&quot;http://www.mcginityphoto.com/&quot;&gt;McGinity Photo&lt;/a&gt; full-time and loving it. We have trips planned to Stockholm (for &lt;a href=&quot;http://jfokus.se&quot;&gt;Jfokus&lt;/a&gt;), Madrid (for &lt;a href=&quot;http://www.springio.net/&quot;&gt;Spring I/O&lt;/a&gt;) and Paris (for &lt;a href=&quot;http://www.devoxx.fr/display/FR12/Accueil&quot;&gt;Devoxx Paris&lt;/a&gt;).
&lt;/p&gt;
&lt;p&gt;Last weekend, we &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157628804308427/&quot;&gt;witnessed&lt;/a&gt; one of the greatest playoff games &lt;em&gt;ever&lt;/em&gt; when the Broncos beat the Steelers. I think the picture of Trish celebrating the final touchdown pretty much sums up 2011. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;a rel=&quot;lightbox[yearinreview2011]&quot; href=&quot;http://farm8.staticflickr.com/7161/6671393297_d6f01b715f.jpg&quot; title=&quot;Broncos Win!&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7161/6671393297_d6f01b715f.jpg&quot; width=&quot;500&quot; height=&quot;375&quot; alt=&quot;Broncos Win!&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
  &lt;/p&gt;
&lt;p&gt;I look forward to all the skiing, celebrating, camping, traveling and bus rides in 2012. It&apos;s gonna be a fantastic year.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/deploying_java_and_play_framework</id>
        <title type="html">Deploying Java and Play Framework Apps to the Cloud with James Ward</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/deploying_java_and_play_framework"/>
        <published>2011-11-18T08:14:45-07:00</published>
        <updated>2011-12-02T20:23:49-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <category term="playframework" scheme="http://roller.apache.org/ns/tags/" />
        <category term="sbt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springroo" scheme="http://roller.apache.org/ns/tags/" />
        <category term="scala" scheme="http://roller.apache.org/ns/tags/" />
        <category term="heroku" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx2011" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jamesward" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Yesterday, I attended &lt;a href=&quot;http://www.jamesward.com/&quot;&gt;James Ward&lt;/a&gt;&apos;s presentation on &lt;a href=&quot;http://www.devoxx.com/pages/viewpage.action?pageId=5015973&quot;&gt;Deploying Java &amp;amp; Play Framework Apps to the Cloud&lt;/a&gt; at Devoxx. I arrived a bit late, but still managed to get there in time to see a lot of demos and learn more about &lt;a href=&quot;http://heroku.com&quot;&gt;Heroku&lt;/a&gt;. Below are my notes from James&apos;s talk.
&lt;/p&gt;
&lt;p&gt;When I arrived, James was doing a demo using &lt;a href=&quot;http://www.springsource.org/spring-roo&quot;&gt;Spring Roo&lt;/a&gt;. He was using Roo&apos;s Petclinic sample app and showed us how you could use Git to create a local repository of the new project and install Heroku&apos;s command line tool. From there, he ran the following command to create a new application on Heroku.
&lt;/p&gt;
&lt;pre&gt;heroku create -s cedar&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;http://devcenter.heroku.com/articles/cedar&quot;&gt;Cedar Stack&lt;/a&gt; is what supports Java, Scala and Play Framework. It&apos;s the 3rd generation stack for Heroku. The command above created two endpoints, one for HTTP and one for Git. It picks from a list of randomly generated names, which all seem to have some humor in them. James ended up with &quot;electric-sword-8877&quot; for this demo.&lt;/p&gt;
&lt;p&gt;From there, he ran &lt;code&gt;git push heroku master&lt;/code&gt; to deploy the project to Heroku. Unfortunately, this resulted in a login error and there was an akward moment where we all thought the Demo Gods were angry. However, James was able to resolve this by using Heroku&apos;s sharing feature with the following command.
&lt;/p&gt;
&lt;pre&gt;
heroku sharing:add jw@heroku.com
&lt;/pre&gt;
&lt;p&gt;For Java projects, Heroku looks for a pom.xml file in the root directory and runs a Maven build on project. All the dependencies get downloaded on the cloud rather than put them into a WAR and requiring you to upload a large WAR file. You don&apos;t have to upload your source code to Heroku; James did it for the sake of the demo because it was faster.
&lt;/p&gt;
&lt;p&gt;After the build finishes, it creates a &lt;em&gt;slug&lt;/em&gt; file. This file contains everything Heroku needs to run your application. 
&lt;p&gt;Next, James showed a demo of the running application and added a new Pet through its UI. Then he scaled it to two servers using the following command:
&lt;/p&gt;
&lt;pre&gt;
heroku scale web=2
&lt;/pre&gt;
&lt;p&gt;
He proved this was working by running &lt;code&gt;heroku ps&lt;/code&gt;, which showed there were two running processes. He showed the app again, but noted that the record he added was missing. This is because when it started up a new dyno, Hibernate created the schema again and deleted all records. To fix, James changed Hibernate to only update the schema instead of create a new one. If you&apos;re a Hibernate user, you know this is as simple as changing:
&lt;/p&gt;
&lt;pre&gt;
hibernate.hbm2ddl.auto=create
&lt;/pre&gt;
&lt;p&gt;to:
&lt;pre&gt;
hibernate.hbm2ddl.auto=update
&lt;/pre&gt;
&lt;p&gt;After committing this change, James redeployed using Git.
&lt;/p&gt;
&lt;pre&gt;
git push heroku master
&lt;/pre&gt;
&lt;p&gt;The slug file got built again and Heroku deployed the new slug onto both dynos, automatically load balancing the app across two servers. James then ran &lt;code&gt;heroku logs&lt;/code&gt; to see the logs of his dynos and prove that a request to his app&apos;s HTTP endpoint made requests to both dynos. The logging is powered by &lt;a href=&quot;https://github.com/heroku/logplex&quot;&gt;Logplex&lt;/a&gt; and you can read about how it works in the article &lt;a href=&quot;http://blog.heroku.com/archives/2010/12/13/logging/&quot;&gt;Heroku Gets Sweet Logging&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;James mentioned that Roo has a Heroku plugin, but after watching his talk and searching a bit on the internet, it seems it&apos;s just the jetty-runner setup as described in &lt;a href=&quot;http://devcenter.heroku.com/articles/spring-mvc-hibernate&quot;&gt;Getting Started with Spring MVC Hibernate on Heroku/Cedar&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
What about autoscaling? There are some 3rd party tools that do this. Heroku&apos;s Management infrastructure has APIs that these tools talk too. Heroku hasn&apos;t built autoscaling into the platform because they don&apos;t know where the bottlenecks are in your application.
&lt;/p&gt;
&lt;p&gt;
Heroku = Polyglot + PaaS + Cloud Components. It supports Ruby, node.js, Java, Clojure, Play and Scala and they&apos;re working on native Grails and Gradle support. There&apos;s currently 534,374 apps running on Heroku.
&lt;/p&gt;
&lt;p&gt;
Heroku is a cloud application platform and there&apos;s 5 different components. 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Instant deployment&lt;/li&gt;
&lt;li&gt;HTTP Routing / Load Balancing&lt;/li&gt;
&lt;li&gt;Elastic Polyglot Runtime&lt;/li&gt;
&lt;li&gt;Management &amp;amp; Logging&lt;/li&gt;
&lt;li&gt;Component as a Service Ecosystem&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
For instant deployment, it&apos;s a pretty simple process:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;You add files to a git repo&lt;/li&gt;
&lt;li&gt;You provision the app on Heroku (heroku create)&lt;/li&gt;
&lt;li&gt;You upload the files to Heroku (git push heroku master)&lt;/li&gt;
&lt;li&gt;Heroku runs the build and assembles a &quot;slug&quot; file&lt;/li&gt;
&lt;li&gt;Heroku starts a &quot;dyno&quot;&lt;/li&gt;
&lt;li&gt;Heroku copies the &quot;slug&quot; to the &quot;dyno&quot;&lt;/li&gt;
&lt;li&gt;Heroku starts the web application&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most apps will contain a &lt;em&gt;Procfile&lt;/em&gt; that contains information about how to run the web process. For Spring Roo, it has:
&lt;/p&gt;
&lt;pre&gt;
web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war
&lt;/pre&gt;
&lt;p&gt;So how does Heroku decide what application server to use? It doesn&apos;t, you do. You need to get your application server into the slug file. 
The easiest way to do this is to specify your application server as a dependency in your pom.xml. In the Roo example, James uses the maven-dependency-plugin to get the jetty-runner dependency and copy it to the target directory. On Heroku, you bring your application server with you.
&lt;/p&gt;
&lt;p&gt;Heroku gives you 750 free dyno hours per app, per month. For developers, it&apos;s very easy to get started and use. Once you extend past one dyno, it&apos;s
  $.05 per dyno hour, which works out to around $30/month.

It&apos;s only when you want to scale beyond one dyno where you get charged by Heroku, no matter how much data you transfer.

&lt;a href=&quot;http://www.scalatest.org/&quot;&gt;Scalatest&lt;/a&gt; is running on Heroku. It has one dyno and is doing fine with that. Bill Venners doesn&apos;t have to pay anything for it.
&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://java.herokuapp.com&quot;&gt;java.herokuapp.com&lt;/a&gt; is a site James created that allows you to clone example apps and get started quickly with Heroku&apos;s Cedar Stack.&lt;/p&gt;
&lt;p&gt;
For 
HTTP Routing, 
Heroku uses an Erlang-based routing system to route all the HTTP requests across your dynos. Heroku doesn&apos;t support sticky sessions. Distributed session management does not work well, because it does not scale well. Heroku recommends you use a stateless web architecture or move your state into something like &lt;a href=&quot;http://memcached.org/&quot;&gt;memcached&lt;/a&gt;. Jetty has (in the latest version) the ability to automatically serialize your session into a Mongo system. This works fine on Heroku. The problem with this is if you have 2 dynos running, each request can hit a different dyno and get different session state. Hence the recommendation for an external storage mechanism that can synchronize between dynos.
&lt;/p&gt;
You can also run non-web applications on Heroku. You can have one web process, but as many non-web processes as you want.
&lt;/p&gt;
&lt;p&gt;Heroku has native support for the &lt;a href=&quot;http://www.playframework.org/&quot;&gt;Play framework&lt;/a&gt;. To detect Play applications, it look for a &lt;em&gt;conf/application.conf&lt;/em&gt; file. You don&apos;t need to have a Procfile in your root directory because Heroku knows how to start a Play application.
&lt;/p&gt;
&lt;p&gt;At this point, James created a new Play application, created a new Heroku app (he got &quot;young-night-7104&quot; this time) and pushed it to Heroku. He created a simple model object, a controller to allow adding new data and then wrote some jQuery to show new records via Ajax and JSON. He also showed how to configure the application to talk to Heroku&apos;s PostgreSQL database using the DATABASE_URL environment variable. He explained how you can use the &lt;code&gt;heroku config&lt;/code&gt; command to see your environment variables.
&lt;/p&gt;
&lt;p&gt;
The reason they use environment variables is so Heroku can update DATABASE_URL (and other variables) without having to call up all their customers and have them change them in their source code.
&lt;/p&gt;
&lt;p&gt;
Play on Heroku supports Scala if you create your app with Scala. Play 2.0 uses Scala, Akka and SBT. Heroku added support for SBT a couple month ago, so everything will work just fine.
&lt;/p&gt;
&lt;p&gt;Heroku also supports Scala, detecting it by looking for the &lt;code&gt;build.sbt&lt;/code&gt; file in the root directory. Heroku supports SBT 0.11.0 and it builds the &apos;stage&apos; task.
It currently does not support Lift because Lift uses an older version of SBT and because it&apos;s a very stateful framework that would require sticky sessions. Use Play, &lt;a href=&quot;https://github.com/jdegoes/blueeyes&quot;&gt;BlueEyes&lt;/a&gt; or &lt;a href=&quot;http://www.scalatra.org/&quot;&gt;Scalatra&lt;/a&gt; if you want Scala on Heroku.
&lt;/p&gt;
&lt;p&gt;Heroku has &lt;a href=&quot;http://addons.heroku.com&quot;&gt;addons&lt;/a&gt; for adding functionality to your application, including Custom DNS, HTTPS, Amazon RDS, NoSQL and many more. They&apos;re also working on making their add-on and management APIs available via Java, so you&apos;ll (hopefully) be able to use them from your IDE in the future.
&lt;/p&gt;
&lt;p&gt;From there, James showed us how Heroku keeps slug files around so you can do rollbacks with &lt;code&gt;heroku rollback&lt;/code&gt;. He also showed how you can use:
&lt;/p&gt;
&lt;pre&gt;heroku run &quot;your bash command&quot;&lt;/pre&gt;
to run any Bash command on the cloud.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
I attended James&apos;s talk because he&apos;s a good friend, but also because I&apos;ve been using Heroku to host &lt;a href=&quot;http://raibledesigns.com/rd/entry/phonegap_to_the_rescue&quot;&gt;my latest adventures with Play, Scala, CoffeeScript and Jade&lt;/a&gt;. I&apos;m glad I attended because I learned some good tips and tricks and more about how Heroku works. 
&lt;/p&gt;
&lt;p&gt;Heroku seems like a great development tool to me. In my experience, it&apos;s been really nice to have instant deployments using Git. In fact, I&apos;ve created a &apos;push&apos; alias so I can push to my project&apos;s repo and heroku at the same time.
&lt;/p&gt;
&lt;pre&gt;
alias push=&apos;git push origin master &amp;&amp; git push heroku master&apos;
&lt;/pre&gt;
&lt;p&gt;I&apos;d like to see more organizations embrace something like Heroku for developers. It&apos;d be great if everyone had their own sandbox that business owners and product managers could see. I can&apos;t help but think this would be awesome for demos, prototyping, etc.
&lt;/p&gt;
&lt;p&gt;
There were some other talks I wanted to attend at the same time, particularly Martin Odersky&apos;s &lt;a href=&quot;http://www.devoxx.com/pages/viewpage.action?pageId=5015952&quot;&gt;What&apos;s in store for Scala?&lt;/a&gt; and &lt;a href=&quot;http://www.devoxx.com/display/DV11/WWW++World+Wide+Wait++A+Performance+Comparison+of+Java+Web+Frameworks&quot;&gt;WWW: World Wide Wait? A Performance Comparison of Java Web Frameworks&lt;/a&gt;. The WWW talk has &lt;a href=&quot;http://prezi.com/dr3on1qcajzw/www-world-wide-wait-devoxx-edition/&quot;&gt;posted their presentation&lt;/a&gt; but I&apos;m sure it&apos;d be more fun to watch. 
&lt;/p&gt;
&lt;p&gt;
It&apos;s pretty awesome that all the talks from Devoxx 2011 will be up on &lt;a href=&quot;http://www.parleys.com/&quot;&gt;Parleys.com&lt;/a&gt; soon.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; James has &lt;a href=&quot;http://www.jamesward.com/2011/11/29/heroku-preso-from-devoxx-2011&quot;&gt;posted his slides&lt;/a&gt; from this talk.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/play_2_0_a_web</id>
        <title type="html">Play 2.0, A web framework for a new era</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/play_2_0_a_web"/>
        <published>2011-11-16T05:58:09-07:00</published>
        <updated>2011-11-16T12:07:33-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="devoxx2011" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx" scheme="http://roller.apache.org/ns/tags/" />
        <category term="scala" scheme="http://roller.apache.org/ns/tags/" />
        <category term="playframework" scheme="http://roller.apache.org/ns/tags/" />
        <category term="akka" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This week, I&apos;m in Antwerp, Belgium for the annual &lt;a href=&quot;http://devoxx.com&quot;&gt;Devoxx&lt;/a&gt; conference. After traveling 21 hours door-to-door yesterday, I woke up and came to the conference to attend some talks on Play and PhoneGap. I just got out of the &lt;a href=&quot;http://devoxx.com/display/DV11/Play+2.0%2C+a+Web+framework+for+a+new+era&quot;&gt;session on Play 2.0&lt;/a&gt;, which was presented by &lt;a href=&quot;http://devoxx.com/display/DV11/Sadek+Drobi&quot;&gt;Sadek Drobi&lt;/a&gt; and &lt;a href=&quot;http://devoxx.com/display/DV11/Guillaume+Bort&quot;&gt;Guillaume Bort&lt;/a&gt;. Below are my notes from this presentation.&lt;/p&gt;
&lt;p&gt;The Play 2.0 beta is out! You can read more about this release &lt;a href=&quot;http://groups.google.com/group/play-framework/browse_thread/thread/6d5783e28efb6931&quot;&gt;on the mailing list&lt;/a&gt;. This beta includes native support for both Scala and Java, meaning you can use both in the same project. The release also bundles &lt;a href=&quot;http://akka.io/&quot;&gt;Akka&lt;/a&gt; and &lt;a href=&quot;https://github.com/harrah/xsbt/wiki&quot;&gt;SBT&lt;/a&gt; by default.
&lt;/p&gt;
&lt;p&gt;In other news, &lt;a href=&quot;http://blog.typesafe.com/typesafe-stack-adds-play-framework&quot;&gt;Play 2.0 is now part of the Typesafe Stack&lt;/a&gt;. Typesafe is the Scala company, started by the founder of Scala (&lt;a href=&quot;http://ch.linkedin.com/in/odersky&quot;&gt;Martin Odersky&lt;/a&gt;) and the founder of Akka (&lt;a href=&quot;http://se.linkedin.com/in/jonasboner&quot;&gt;Jonas Bon&#233;r&lt;/a&gt;). Guillaume is also joining the Typesafe Advisory Board.
&lt;/p&gt;
&lt;p&gt;Sadek and Guillaume both work at &lt;a href=&quot;http://www.zenexity.com/&quot;&gt;zenexity&lt;/a&gt;, where Play is the secret weapon for the web applications they&apos;ve built for the last decade. Play was born in the real world. They kept listening to the market to see what they should add to the project. At some point, they realized they couldn&apos;t keep adding to the old model and they needed to create something new.&lt;/p&gt;
&lt;p&gt;
The web has evolved from static pages to dynamic pages (ASP, PHP). From there, we moved to structured web applications with frameworks and MVC. Then the web moved to Ajax and long-polling to more real-time, live features.  And this changes everything.
&lt;/p&gt;
&lt;p&gt;
Now we need to adapt our tools. We need to handle tremendous flows of data. Need to improve expressiveness for concurrent code. We need to pick the appropriate datastore for the problem (not only SQL). We need to integrate with rapidly-evolving client side technologies like JavaScript, CoffeeScript, and Dart. We need to use elastic deployment that allows scaling up and scaling down.&lt;/p&gt;
&lt;p&gt;zenexity wanted to integrated all of these modern web needs into Play 2.0. But they also wanted to keep Play approachable. They wanted to maintain fast turnaround so you can change your code and hit reload to see the changes. They wanted to keep it as a full stack framework with support for JSON, XML, Web Services, Jobs, etc. And they wanted to continue to use and conventions over configuration.
&lt;/p&gt;
&lt;p&gt;At this point, Guillaume did a Play 2.0 Beta demo, show us how it uses SBT and has a console so everything so it runs really fast. You can have both Scala and Java files in the same project. Play 2.0 templates are based on Scala, but you don&apos;t need to know Scala to use them. You might have to learn how to write a for loop in Scala, but it&apos;s just a subset of Scala for templates and views. SBT is used for the build system, but you don&apos;t have to learn or know SBT. All the old &lt;code&gt;play&lt;/code&gt; commands still work, they&apos;re just powered by a different system.
&lt;/p&gt;
&lt;p&gt;After the demo, Sadek took over and started discussing the key features of Play 2.0.
&lt;/p&gt;
&lt;p&gt;
To handle tremendous amounts of data, you need to do chunking of data and be able to process a stream of data, not just wait until it&apos;s finished. Java&apos;s InputStream is outdated and too low level. Its &lt;em&gt;read()&lt;/em&gt; method reads the next byte of data from the input and this method can block until input data is available.&lt;/p&gt;
&lt;p&gt;
To solve this, Play includes a reactive programming feature, which they borrowed from Haskell. It uses Iteratee/Enumerator IO and leverages inversion of control (not like dependency injection, but more like not micro-managing). The feature allows you to have control when you need it so you don&apos;t have to wait for the input stream to complete. The Enumerator is the component that sends data and the Iteratee is the component that receives data. The Iteratee does incremental processing and can tell the Enumerator when it&apos;s done. The Iteratee can also send back a continuation, where it tells the Enumerator it wants more data and how to give it. With this paradigm, you can do a lot of cool stuff without consuming resources and blocking data flow.
&lt;/p&gt;
&lt;p&gt;
Akka is an actor system that is a great model for doing concurrent code. An Actor could be both an Enumerator and an Iteratee. This vastly improves the expressiveness for concurrent code. For example, here&apos;s how you&apos;d use Akka in Play:
&lt;pre class=&quot;brush: scala&quot;&gt;
def search(keyword: String) = Action {
  AsyncResult {
    // do something with result
  }
}
&lt;/pre&gt;
&lt;p&gt;
Play does not try to abstract data access because datastores are different now. You don&apos;t want to think of everything as objects if you&apos;re using something like MongoDB or navigating a Social Graph. Play 2.0 will provide some default modules for the different datastores, but they also expect a lot of contributed modules. Anorm will be the default SQL implementation for Play Scala and &lt;a href=&quot;https://github.com/playframework/Play20/wiki/JavaEbean&quot;&gt;Ebean&lt;/a&gt; will be the default ORM implementation for Play Java. The reason they&apos;ve moved away from Hibernate is because they needed something that was more stateless.
&lt;/p&gt;
&lt;p&gt;
On the client side, there&apos;s so many technologies (LESS, CoffeeScript, DART, Backbone.js, jQuery, SASS), they didn&apos;t want to bundle any because they move too fast. Instead, there&apos;s plugins you can add that help you leverage these technologies. There&apos;s a lot of richness you can take advantage of on the client side and you need to have the tools for that.&lt;/p&gt;
&lt;p&gt;Lastly, there&apos;s a new type of deployment: container-less deployment to the cloud. Akka allows you to distribute your jobs across many servers and &lt;a href=&quot;http://heroku.com&quot;&gt;Heroku&lt;/a&gt; is an implementation of elastic deployment that has built-in support for Play.
&lt;/p&gt;
&lt;p&gt;
They&apos;ve explained what they tried to design and the results of this new, clean architecture have been suprising. Side effects include: type-safety everywhere for rock-solid applications. There&apos;s an awesome performance boost from Scala. There&apos;s easier integration with existing projects via SBT. And it only takes 10 lines of code to develop an HTTP Server that responds to web requests.
&lt;p&gt;The memory consumption is amazing: only 2MB of heap is used when a Play 2.0 app is started. Tests on Guillaume&apos;s laptop have shown that it can handle up to 40,000 requests per second, without any optimization of the JVM. Not only that, but after the requests subside, garbage collection cleans up everything and reduces the memory consumption back to 2MB.
&lt;/p&gt;
&lt;p&gt;At this point, Guillaume did another demo, showing how everything is type-safe in 2.0, including the routes file. If you mistype (or comment one out) any routes, the compiler will find it and notify you. Play 2.0 also contains a &lt;em&gt;compiled assets&lt;/em&gt; feature. This allows you to &lt;a href=&quot;https://github.com/playframework/Play20/wiki/AssetsGoogleClosureCompiler&quot;&gt;use Google&apos;s Closure Compiler&lt;/a&gt;, &lt;a href=&quot;https://github.com/playframework/Play20/wiki/AssetsCoffeeScript&quot;&gt;CoffeeScript&lt;/a&gt; and &lt;a href=&quot;https://github.com/playframework/Play20/wiki/AssetsLess&quot;&gt;LESS&lt;/a&gt;. If you put your LESS files in &lt;em&gt;app/assets/stylesheets&lt;/em&gt;, compilation errors will show up in your browser. If you put JavaScript files in &lt;em&gt;app/assets/javascripts&lt;/em&gt;, the Closure compiler will be used and compilation errors will show up in your browser.
&lt;/p&gt;
&lt;p&gt;
Play 2.0 ships with 3 different sample applications, all implemented in both Java and Scala. HelloWorld is more than just text in a browser, it includes a form that shows how validation works. Another app is computer-database. When Guillaume started it, we saw how evolutions were used to create the database schema from the browser. The Play Team has done their best to make the development process a browser-based experience rather than having to look in your console. The computer-database is a nice example of how to do CRUD and leverages Twitter&apos;s Bootstrap for its look and feel.
&lt;/p&gt;
The last sample application is zentasks. It uses Ajax and implements security so you can see how to create a login form. It uses LESS for CSS and CoffeeScript and contains features like in-place editing. If you&apos;d like to see any of these applications in action, you can stop by the Typesafe booth this week at Devoxx.
&lt;/p&gt;
&lt;p&gt;Unfortunately, there will be no migrating path for Play 1.x applications. The API seems very similar, but there are subtle changes that make this difficult. The biggest thing is how templating has changed from Groovy to Scala. To migrate from 1.2.x would be mostly a copy/paste, modify process. There are folks working on getting Groovy templates working in 2.0. The good news is zenexity has hundreds of 1.x applications in production, so 1.x will likely be maintained for many years.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
This was a great talk on what&apos;s new in Play 2.0. I especially like the native support for LESS and CoffeeScript and the emphasis on trying to keep developers using two tools: their editor and the browser. The sample apps look great, but the documentation look sparse. I doubt I&apos;ll get a chance to migrate my Play 1.2.3 app to 2.0 this month, but I hope to try migrating sometime before the end of the year.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/more_scalate_goodness_for_play</id>
        <title type="html">More Scalate Goodness for Play</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/more_scalate_goodness_for_play"/>
        <published>2011-11-07T14:07:40-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="playframework" scheme="http://roller.apache.org/ns/tags/" />
        <category term="scala" scheme="http://roller.apache.org/ns/tags/" />
        <category term="play-more" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx2011" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jade" scheme="http://roller.apache.org/ns/tags/" />
        <category term="scalate" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;a href=&quot;http://scalate.fusesource.org&quot;&gt;&lt;img src=&quot;//scalate.fusesource.org/images/project-icon-160x160.png&quot; width=&quot;80&quot; height=&quot;80&quot; alt=&quot;Scalate&quot; class=&quot;picture&quot; style=&quot;border: 0&quot;/&gt;&lt;/a&gt;
This article is the 6th in a series on about my adventures developing a web application with HTML5, Play Scala, CoffeeScript and Jade. Previous articles can be found at:
&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_scalate_and_jade_with&quot;&gt;Integrating Scalate and Jade with Play 1.2.3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/trying_to_make_coffeescript_work&quot;&gt;Trying to make CoffeeScript work with Scalate and Play&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_html5_boilerplate_with_scalate&quot;&gt;Integrating HTML5 Boilerplate with Scalate and Play&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_with_html5_coffeescript_and&quot;&gt;Developing with HTML5, CoffeeScript and Twitter&apos;s Bootstrap&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/play_scala_s_anorm_heroku&quot;&gt;Play Scala&apos;s Anorm, Heroku and PostgreSQL Issues&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last week, I wrote about my adventures with &lt;a href=&quot;http://scala.playframework.org/documentation/scala-0.9.1/anorm&quot;&gt;Anorm&lt;/a&gt; and mentioned I&apos;d made some improvements to Scalate Play interoperability. First of all, I&apos;ve been using a Scalate trait and ScalateTemplate class to render Jade templates in my application. I described this setup in my &lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_scalate_and_jade_with&quot;&gt;first article on Scalate and Play&lt;/a&gt;. 
&lt;/p&gt;
&lt;p id=&quot;default-variables&quot;&gt;&lt;strong&gt;Adding SiteMesh Features and Default Variables&lt;/strong&gt;&lt;br/&gt;  
When I started making my app look good with CSS, I started longing for a feature I&apos;ve used in SiteMesh. That is, to have a body id or class that can identify the page and allow per-page CSS rules. To do this with SiteMesh, you&apos;d have something like the following in your page:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;  
&amp;lt;body id=&quot;signup&quot;/&gt;
&lt;/pre&gt;
&lt;p&gt;  
And then read it in your decorator:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;body&lt;decorator:getProperty property=&quot;body.id&quot; writeEntireProperty=&quot;true&quot;/&gt;&amp;lt;decorator:getProperty property=&quot;body.class&quot; writeEntireProperty=&quot;true&quot;/&gt;&gt;
&lt;/pre&gt;
&lt;p&gt;As I started looking into how to do this, I came across Play Scala&apos;s &lt;a href=&quot;https://github.com/playframework/play-scala/blob/master/src/play/mvc/ScalaController.scala&quot;&gt;ScalaController&lt;/a&gt; and how it was populating Play&apos;s default variables (request, response, flash, params, etc.). Based on this newfound knowledge, I added a &lt;em&gt;populateRenderArgs()&lt;/em&gt; method to set all the default variables and my desired &lt;em&gt;bodyClass&lt;/em&gt; variable.
&lt;/p&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
def populateRenderArgs(args: (Symbol, Any)*): Map[String, Any] = {
  val renderArgs = Scope.RenderArgs.current();

  args.foreach {
    o =&gt;
      renderArgs.put(o._1.name, o._2)
  }

  renderArgs.put(&quot;session&quot;, Scope.Session.current())
  renderArgs.put(&quot;request&quot;, Http.Request.current())
  renderArgs.put(&quot;flash&quot;, Scope.Flash.current())
  renderArgs.put(&quot;params&quot;, Scope.Params.current())
  renderArgs.put(&quot;errors&quot;, validationErrors)
  renderArgs.put(&quot;config&quot;, Play.configuration)

  // CSS class to add to body
  renderArgs.put(&quot;bodyClass&quot;, Http.Request.current().action.replace(&quot;.&quot;, &quot; &quot;).toLowerCase)
  renderArgs.data.toMap
}

implicit def validationErrors:Map[String,play.data.validation.Error] = {
  import scala.collection.JavaConverters._
  Map.empty[String,play.data.validation.Error] ++ 
    Validation.errors.asScala.map( e =&gt; (e.getKey, e) )
}
&lt;/pre&gt;&lt;p&gt;After adding this method, I was able to access these values in my templates by defining them at the top:
&lt;/pre&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
-@ val bodyClass: String 
-@ val params: play.mvc.Scope.Params
-@ val flash: play.mvc.Scope.Flash
&lt;/pre&gt;
&lt;p&gt;And then reading their values in my template:
&lt;/p&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
body(class=bodyClass)
...
- if (flash.get(&quot;success&quot;) != null) {
  div(class=&quot;alert-message success&quot; data-alert=&quot;alert&quot;)
    a(class=&quot;close&quot; href=&quot;#&quot;) &amp;&amp;times;
    | #{flash.get(&quot;success&quot;)}
- }
...
  fieldset
    legend Leave a comment &amp;rarr;
    div.clearfix
      label(for=&quot;author&quot;) Your name:
      input(type=&quot;text&quot; name=&quot;author&quot; class=&quot;xlarge&quot; value={params.get(&quot;author&quot;)})
    div.clearfix
      label(for=&quot;content&quot;) Your message:
      textarea(name=&quot;content&quot; class=&quot;xlarge&quot;) #{params.get(&quot;content&quot;)}
    div.actions
      button(type=&quot;submit&quot; class=&quot;btn primary&quot;) Submit your comment
      button(type=&quot;reset&quot; class=&quot;btn&quot;) Cancel
&lt;/pre&gt;  
&lt;p&gt;For a request like Home/index, the body tag is now rendered as:
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;body class=&quot;home index&quot;&gt;
&lt;/pre&gt;
This allows you to group CSS styles by Controller names as well as by method names.
&lt;/p&gt;
&lt;p&gt;
Next, I started developing forms and validation logic. I quickly discovered I needed an &lt;em&gt;action()&lt;/em&gt; method like the one defined in &lt;a href=&quot;https://github.com/playframework/play-scala/blob/master/src/play/templates/ScalaTemplate.scala&quot;&gt;ScalaTemplate&apos;s&lt;/a&gt; TemplateMagic class. 
&lt;/p&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
def action(action: =&gt; Any) = {
  new play.mvc.results.ScalaAction(action).actionDefinition.url
}
&lt;/pre&gt;
&lt;p&gt;
Since TemplateMagic is an inner class, I determined that copying the method into my ScalateTemplate class was the easiest workaround. After doing this, I was able to import the method and use it in my templates.
&lt;/p&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
-import controllers.ScalateTemplate._
...
form(method=&quot;post&quot; class=&quot;form-stacked&quot; id=&quot;commentForm&quot;
     action={action(controllers.Profile.postComment(workout._1.id()))})
&lt;/pre&gt;
&lt;p&gt;After getting the proper URL written into my form&apos;s action attribute, I encountered a new problem. The &lt;a href=&quot;http://scala.playframework.org/documentation/scala-0.9.1/guide4#aAddingvalidationa&quot;&gt;Play Scala Tutorial explains validation flow&lt;/a&gt; as follows:
&lt;/p&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
if (Validation.hasErrors) {
  show(postId)
} else {
  Comment.create(Comment(postId, author, content))
  Action(show(postId))
}
&lt;/pre&gt;
&lt;p&gt;However, when I had validation errors, I end up with the following error:
&lt;/p&gt;
&lt;pre&gt;
Could not load resource: [Timeline/postComment.jade]
&lt;/pre&gt;&lt;p&gt;To fix this, I added logic to my Scalate trait that looks for a &quot;template&quot; variable before using &lt;em&gt;Http.Request.current().action.replace(&quot;.&quot;, &quot;/&quot;)&lt;/em&gt; for the name. After making this change, I was able to use the following code to display validation errors.&lt;/p&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
if (Validation.hasErrors) {
  renderArgs.put(&quot;template&quot;, &quot;Timeline/show&quot;)
  show(postId)
} else {
  Comment.create(Comment(postId, author, content))
  Action(show(postId))
}
&lt;/pre&gt;
&lt;p&gt;Next, I wanted to give child pages the ability to set content in parent pages. With SiteMesh, I could use the &amp;lt;content&amp;gt; tag as follows:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;content tag=&quot;underground&quot;&gt;
  HTML goes here
&amp;lt;/content&gt;
&lt;/pre&gt;
&lt;p&gt;This HTML could then be retrieved in the decorator using the &amp;lt;decorator:getProperty&amp;gt; tag:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;decorator:getProperty property=&quot;page.underground&quot;/&gt;
&lt;/pre&gt;
&lt;p&gt;With Scalate, I found it equally easy using the &lt;em&gt;captureAttribute()&lt;/em&gt; method. For example, here&apos;s how I captured a list of an athlete&apos;s workouts for display in a sidebar.
&lt;/p&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
- captureAttribute(&quot;sidebar&quot;)
  - Option(older).filterNot(_.isEmpty).map { workouts =&gt;
    .older-workouts
      h3
        | Older workouts
        span.from from this app
      - workouts.map { workout =&gt;
        - render(&quot;workout.jade&quot;, Map(&apos;workout -&gt; workout, &apos;mode -&gt; &quot;teaser&quot;))
      - }
  - }
- }
&lt;/pre&gt;
&lt;p&gt;Then in my layout, I was able to retrieve this and display it. Below is a snippet from the layout I&apos;m using (copied from &lt;a href=&quot;http://twitter.github.com/bootstrap/examples/container-app.html&quot;&gt;Twitter&apos;s Bootstrap example&lt;/a&gt;). You can see how the sidebar is included in the .span4 at the end.
&lt;/p&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
-@ val sidebar: String = &quot;&quot;
...
.container
  .content
    .page-header
      h1
        = pageHeader
        small
          = pageTagline
    .row
      .span10
        !~~ body
      .span4
        = unescape(sidebar)
  footer
&lt;/pre&gt;
&lt;p id=&quot;view-vs-render&quot;&gt;&lt;strong&gt;View vs. Render in Scalate&lt;/strong&gt;&lt;br/&gt;
In the sidebar code above, you might notice the &lt;em&gt;render()&lt;/em&gt; call. This is the &lt;a href=&quot;http://scalate.fusesource.org/documentation/user-guide.html#Render_templates&quot;&gt;Scalate version of server-side includes&lt;/a&gt;. It works well, but there&apos;s also a &lt;a href=&quot;http://scalate.fusesource.org/documentation/user-guide.html#Views&quot;&gt;&lt;em&gt;view()&lt;/em&gt; shortcut&lt;/a&gt; you can use if you want to have templates for rendering your model objects. I quickly discovered it might be difficult to use this feature in my app because my object was &lt;em&gt;Option[(models.Workout, models.Athlete, Seq[models.Comment])]&lt;/em&gt; instead of a simple object. You can read the &lt;a href=&quot;http://groups.google.com/group/scalate/browse_thread/thread/bcc6059fc08d4da0&quot;&gt;view vs. render thread&lt;/a&gt; on the Scalate Google Group if you&apos;re interested in learning more.
&lt;/p&gt;
&lt;p id=&quot;scalate-plugin&quot;&gt;&lt;strong&gt;Scalate as a Module&lt;/strong&gt;&lt;br/&gt;
The last enhancement I attempted to make was to put Scalate support into a &lt;a href=&quot;http://www.playframework.org/documentation/1.2.3/modules&quot;&gt;Play module&lt;/a&gt;. At first, I tried overriding Play&apos;s &lt;em&gt;Template&lt;/em&gt; class but &lt;a href=&quot;http://groups.google.com/group/play-framework/browse_thread/thread/8d1b00ec4304f4ea&quot;&gt;ran into compilation issues&lt;/a&gt;. Then Guillaume Bort (Play&apos;s lead developer) recommended I stick with the trait approach and I was able to get everything working. I looked at the &lt;a href=&quot;https://github.com/pk11/play-scalate&quot;&gt;outdated play-scalate module&lt;/a&gt; to figure out how to add Scala support to build.xml and copied its &lt;a href=&quot;https://github.com/pk11/play-scalate/blob/master/resources/500.scaml&quot;&gt;500.scaml&lt;/a&gt; page for error reporting.&lt;/p&gt;
&lt;p&gt;In order to get line-precise error reporting working, I had to wrap a try/catch around calling Scalate&apos;s &lt;em&gt;TemplateEngine.layout()&lt;/em&gt; method. Again, most of this code was copied from the outdated play-scalate module.
&lt;/p&gt;
&lt;pre class=&quot;brush: scala&quot;&gt;
case class Template(name: String) {
  
  def render(args: (Symbol, Any)*) = {
    val argsMap = populateRenderArgs(args: _*)
    
    val buffer = new StringWriter()
    var context = new DefaultRenderContext(name, scalateEngine, new PrintWriter(buffer))
    
    try {
      val templatePath = new File(Play.applicationPath+&quot;/app/views&quot;,&quot;/&quot;+name).toString
        .replace(new File(Play.applicationPath+&quot;/app/views&quot;).toString,&quot;&quot;)
      scalateEngine.layout(templatePath + scalateType, argsMap)
    } catch {
      case ex:TemplateNotFoundException =&gt; {
        if(ex.isSourceAvailable) {
          throw ex
        }
        val element = PlayException.getInterestingStrackTraceElement(ex)
        if (element != null) {
           throw new TemplateNotFoundException(name, 
             Play.classes.getApplicationClass(element.getClassName()), element.getLineNumber());
        } else {
           throw ex
        }
      }  
      case ex:InvalidSyntaxException =&gt; handleSpecialError(context,ex)
      case ex:CompilerException =&gt; handleSpecialError(context,ex)
      case ex:Exception =&gt; handleSpecialError(context,ex)
    } finally {
      if (buffer.toString.length &gt; 0)
        throw new ScalateResult(buffer.toString,name)
    }
  }
}
...
private def handleSpecialError(context:DefaultRenderContext,ex:Exception) {
  context.attributes(&quot;javax.servlet.error.exception&quot;) = ex
  context.attributes(&quot;javax.servlet.error.message&quot;) = ex.getMessage
  try {
    scalateEngine.layout(scalateEngine.load(errorTemplate), context)
  } catch {
    case ex:Exception =&gt;
      // TODO use logging API from Play here...
      println(&quot;Caught: &quot; + ex)
      ex.printStackTrace
  }
}

private def errorTemplate:String = {
  val fullPath = new File(Play.applicationPath,&quot;/app/views/errors/500.scaml&quot;).toString 
  fullPath.replace(new File(Play.applicationPath+&quot;/app/views&quot;).toString,&quot;&quot;)
}
&lt;/pre&gt;
&lt;p&gt;Once I had this in place, error messages from Scalate are much better. Not only do I see the error in my browser, but I can click on the offending line to open it directly in TextMate.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm7.static.flickr.com/6054/6323523392_91888694bc_o.png&quot; title=&quot;Play Scalate Error Reporting&quot; rel=&quot;lightbox[scalate-goodness]&quot;&gt;&lt;img src=&quot;//farm7.static.flickr.com/6054/6323523392_affe4cf053.jpg&quot; width=&quot;500&quot; height=&quot;290&quot; alt=&quot;Play Scalate Error Reporting&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I&apos;ve published my &lt;a href=&quot;https://github.com/mraible/play-scalate&quot;&gt;play-scalate module on GitHub&lt;/a&gt; so others can try it out. To give it a whirl, add the following to your dependencies.yml:
&lt;/p&gt;
&lt;pre&gt;
    - upgrades -&gt; play-scalate 0.1

repositories:
    - upgrades:
        type: http
        artifact: &quot;http://static.raibledesigns.com/[module]-[revision].zip&quot;
        contains:
            - upgrades -&gt; *
&lt;/pre&gt;&lt;p&gt;Then add &lt;em&gt;with play.modules.scalate.Scalate&lt;/em&gt; to your controllers and call the &lt;em&gt;render()&lt;/em&gt; method.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
After using Scalate and Play for almost 3 months, I&apos;m really enjoying the combination. When I first integrated Scalate with a simple trait, the error messages were always in the console. Now that I&apos;ve borrowed some smarts from Play&apos;s ScalaController and play-scalate&apos;s error reporting, I feel like it&apos;s practically a built-in solution. I was easily able to integrate my desired SiteMesh features and it even allows &lt;a href=&quot;http://groups.google.com/group/scalate/browse_thread/thread/f6df5b165024407e&quot;&gt;reusable template blocks&lt;/a&gt;. In the end, it&apos;s just Scala and Scalate does a good job of allowing you to leverage that.&lt;/p&gt;
&lt;p&gt;Other thoughts:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you&apos;re writing a lot of Jade and familiar with HTML, Don Park&apos;s &lt;a href=&quot;https://github.com/donpark/html2jade&quot;&gt;html2jade&lt;/a&gt; is a great tool that comes with Scalate support.&lt;/li&gt;
&lt;li&gt;I&apos;m really enjoying writing CSS with &lt;a href=&quot;http://lesscss.org/&quot;&gt;LESS&lt;/a&gt;, particularly the ability to nest rules and have programming features. The only issue I&apos;ve seen is IntelliJ&apos;s LESS plugin only does code-completion for variables rather than CSS values.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;http://www.packtpub.com/play-framework-cookbook/book&quot;&gt;Play Framework Cookbook&lt;/a&gt; is a great reference for learning how to write modules. Not only does it explain how to create modules, it has some great real-world examples for doing bytecode enhancement, implementing message queues, using Solr and how to do production monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If this series of articles has intrigued you and you&apos;ll be at &lt;a href=&quot;http://www.devoxx.com/display/DV11/Home&quot;&gt;Devoxx&lt;/a&gt; next week, you should stop by &lt;a href=&quot;http://www.devoxx.com/display/DV11/HTML5+with+Play+Scala%2C+CoffeeScript+and+Jade&quot;&gt;my talk on Thursday afternoon&lt;/a&gt;. In addition, there&apos;s several other Play talks at Devoxx and a possible meetup on Wednesday. Check out the &lt;a href=&quot;http://groups.google.com/group/play-framework/browse_thread/thread/eaef08eb36f9eb0a&quot;&gt;Devoxx, anyone?&lt;/a&gt; thread for more information.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: There&apos;s one thing I forgot to mention about the Play Scalate Module. When I had Scalate integrated in my app with a trait, I only included the scalate-core and scalate-util JARs in dependencies.yml:&lt;/p&gt;
&lt;pre&gt;
- org.fusesource.scalate -&gt; scalate-core 1.5.2-scala_2.8.1:
    transitive: false
- org.fusesource.scalate -&gt; scalate-util 1.5.2-scala_2.8.1:
    transitive: false
&lt;/pre&gt;&lt;p&gt;However, when I created the play-scalate module, I allowed more dependencies.&lt;/p&gt;
&lt;pre&gt;
- org.fusesource.scalate -&gt; scalate-core 1.5.2-scala_2.8.1:
    exclude:
        - javax.servlet -&gt; *
        - com.sun.jersey -&gt; *
        - org.osgi -&gt; *
- org.fusesource.scalate -&gt; scalate-util 1.5.2-scala_2.8.1
&lt;/pre&gt;Because Scalate depends on &lt;a href=&quot;http://logback.qos.ch/&quot;&gt;Logback&lt;/a&gt;, debug messages started showing up in my console. To fix this, I created &lt;em&gt;conf/logback.xml&lt;/em&gt; in my project and filled it with the following XML.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;appender name=&quot;STDOUT&quot; class=&quot;ch.qos.logback.core.ConsoleAppender&quot;&amp;gt;
      &amp;lt;encoder&amp;gt;
          &amp;lt;pattern&amp;gt;%msg%n&amp;lt;/pattern&amp;gt;
      &amp;lt;/encoder&amp;gt;
  &amp;lt;/appender&amp;gt;

  &amp;lt;root level=&quot;info&quot;&amp;gt;
    &amp;lt;appender-ref ref=&quot;STDOUT&quot; /&amp;gt;
  &amp;lt;/root&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This reduces the logging and allows me to increase Scalate&apos;s logging if I ever have the need.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/integrating_scalate_and_jade_with</id>
        <title type="html">Integrating Scalate and Jade with Play 1.2.3</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/integrating_scalate_and_jade_with"/>
        <published>2011-09-07T13:21:41-06:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="devoxx2011" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jade" scheme="http://roller.apache.org/ns/tags/" />
        <category term="play" scheme="http://roller.apache.org/ns/tags/" />
        <category term="lift" scheme="http://roller.apache.org/ns/tags/" />
        <category term="play-more" scheme="http://roller.apache.org/ns/tags/" />
        <category term="scala" scheme="http://roller.apache.org/ns/tags/" />
        <category term="scalate" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">At the beginning of this year, I decided I wanted to learn &lt;a href=&quot;http://www.scala-lang.org/&quot;&gt;Scala&lt;/a&gt;. Since I&apos;m a Web Frameworks Aficionado, I figured the best way to do that would be to learn &lt;a href=&quot;http://liftweb.net/&quot;&gt;Lift&lt;/a&gt;. I entered these two items on my todo list and let them lie for a couple months. After attending &lt;a href=&quot;http://raibledesigns.com/rd/entry/livin_it_up_in_vegas&quot;&gt;TSSJS 2011&lt;/a&gt; and having a conversation with &lt;a href=&quot;http://macstrac.blogspot.com/&quot;&gt;James Strachan&lt;/a&gt;, I added a couple more technologies to my learning list. James had great things to say about both &lt;a href=&quot;http://jashkenas.github.com/coffee-script/&quot;&gt;CoffeeScript&lt;/a&gt; and &lt;a href=&quot;http://jade-lang.com/&quot;&gt;Jade&lt;/a&gt; and I decided to learn those as well.&lt;/p&gt;
&lt;p&gt;In May, &lt;a href=&quot;http://devoxx.com&quot;&gt;Devoxx&lt;/a&gt; announced their Call For Papers and I started reminiscing about how awesome &lt;a href=&quot;http://raibledesigns.com/rd/entry/an_awesome_trip_to_amsterdam&quot;&gt;last year&apos;s trip&lt;/a&gt; was. I decided I&apos;d try to get accepted again and started brainstorming about talks I&apos;d like to give. I came up with &quot;Comparing Scala Web Frameworks&quot; and &quot;HTML5 with Play Scala, CoffeeScript and Jade&quot;. The reason I chose Play over Lift for the latter talk is because I think it fits a lot more with the MVC mindset I have and the easy-to-learn nature of web frameworks I enjoy using. 
Both topics sounded very interesting to me, and I figured they&apos;d also inspire me to learn the technologies in a brute-force fashion; where I was under a time constraint and would be embarrassed in front of a large audience if I didn&apos;t succeed.&lt;/p&gt;
&lt;p&gt;In mid-July, I got an email from &lt;a href=&quot;https://twitter.com/Stephan007&quot;&gt;Stephan&lt;/a&gt; inviting me to speak again at the 10th edition of Devoxx. I smile splashed across my face and I quickly realized I had a lot to learn. Since I was still in vacation mode after &lt;a href=&quot;http://raibledesigns.com/rd/entry/4th_of_july_adventures_in&quot;&gt;summer vacation in Montana&lt;/a&gt;, I decided to wait until I returned from &lt;a href=&quot;http://raibledesigns.com/rd/entry/oregon_cape_cod_and_fun&quot;&gt;Cape Cod&lt;/a&gt; to start studying. While on my 2nd summer vacation, I received an email from Devoxx stating that they&apos;d like me present &quot;HTML5 with Play/Scala, CoffeeScript and Jade&quot;. 
&lt;/p&gt;
&lt;p&gt;To learn all these technologies, I decided on an &lt;em&gt;In Anger&lt;/em&gt; approach - where I would study minimally and learn mostly by doing. I ordered &lt;a href=&quot;http://pragprog.com/book/tbcoffee/coffeescript&quot;&gt;CoffeeScript&lt;/a&gt; on August 8th and &lt;a href=&quot;http://www.artima.com/shop/programming_in_scala_2ed&quot;&gt;Programming in Scala, 2nd Edition&lt;/a&gt; the following week (August 17th). I started reading both books while traveling the following week (I found CoffeeScript and Scala to be very similar, so I don&apos;t know if I&apos;d recommend learning them at the same time). That same week, I started integrating &lt;a href=&quot;http://scalate.fusesource.org/&quot;&gt;Scalate&lt;/a&gt; (Jade) into a new &lt;a href=&quot;http://scala.playframework.org/&quot;&gt;Play Scala&lt;/a&gt; application.&lt;/p&gt;
&lt;p&gt;Scalate advertises on their homepage that it works with Play via the &lt;a href=&quot;https://github.com/pk11/play-scalate&quot;&gt;play-scalate&lt;/a&gt; module. They neglect to mention that this module hasn&apos;t been updated in over a year or what version of Play it works with. I tried to use the &lt;a href=&quot;http://www.playframework.org/modules/scalate-0.7.2/home&quot;&gt;scalate-0.7.2&lt;/a&gt; version and quickly ran into issues. I posted &lt;a href=&quot;http://groups.google.com/group/scalate/browse_thread/thread/398cee0190a47a39&quot;&gt;a message to the Scalate Google Group&lt;/a&gt; explaining my compilation issues and stacktraces. The response? Crickets.&lt;/p&gt;
&lt;p&gt;Next, I tried &lt;a href=&quot;http://groups.google.com/group/play-framework/browse_thread/thread/f225b1d228b3169&quot;&gt;posting to the Play Google Group&lt;/a&gt; and got a much better response. Here&apos;s what they said:
  &lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
  Looking at the Scalate module code, I don&apos;t think it can work as is 
  with Play Scala 0.9.1. The latest version is more than 1 year old, and 
  we have made a lot of changes in the API.
  &lt;br/&gt;...&lt;br/&gt;
  The integration of 
  Scalate is pretty difficult if you plan to get the same kind of 
  experience than the native Play scala template regarding auto-reload 
  and error reports.&lt;br/&gt;&lt;br/&gt;
  You can try to port the module to 0.9.1, basically all it has to do is 
  to provide a plugin that detect changes to scaml file, and recompile 
  them. No special integration with the Play API is needed.
&lt;/p&gt;
&lt;p&gt;After learning that play-scalate was out-of-date, I contacted the project owner via GitHub and tried to get everything working with Play 1.2.3 and Scalate 1.5.1. I updated the dependencies in the project, fixed compilation issues and tried to build. No dice:
&lt;/p&gt;
&lt;pre&gt;
build: 
    [mkdir] Created dir: /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] Compiling 7 source files to /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] error: class file needed by Binding is missing. 
   [scalac] reference type Serializable of package scala refers to nonexisting symbol. 
   [scalac] one error found
&lt;/pre&gt;
&lt;p&gt;I &lt;a href=&quot;http://groups.google.com/group/play-framework/browse_thread/thread/759e29173b3db99d&quot;&gt;posted this error to the Play Group&lt;/a&gt;, discovered it was caused by Scalate 1.5.1 requiring Scala 2.9. I downgraded to Scalate 2.4.1 and got another nice cryptic error:&lt;/p&gt;
&lt;pre&gt;
build: 
    [mkdir] Created dir: /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] Compiling 7 source files to /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] error: class file needed by ScalaController is missing. 
   [scalac] reference value dispatch of package &amp;lt;root&gt; refers to nonexisting symbol. 
   [scalac] one error found
&lt;/pre&gt;
&lt;p&gt;Apparently, this was caused by another &lt;em&gt;Scala versioning issue&lt;/em&gt; and I was offered a &lt;a href=&quot;https://gist.github.com/1184490&quot;&gt;much simpler solution&lt;/a&gt; for integrating Scalate. Below are the steps I performed to integrate Scalate 1.4.1 with Play 1.2.3.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Updated dependencies.yml to references Scala and Scalate dependencies.
&lt;pre style=&quot;margin-top: 5px&quot;&gt;
require:
    - play
    - play -&gt; scala 0.9.1
    - org.fusesource.scalate -&gt; scalate-core 1.4.1:
        transitive: false
    - org.fusesource.scalate -&gt; scalate-util 1.4.1:
        transitive: false
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Added Scalate configuration elements to application.conf.
&lt;pre style=&quot;margin-top: 5px&quot;&gt;
scalate=jade
jvm.memory=-Xmx256M
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Created a ScalateTemplate class to contain the Scalate Engine and render the template.
&lt;pre class=&quot;brush: scala&quot;&gt;
package controllers

import play.Play

object ScalateTemplate {

  import org.fusesource.scalate._
  import org.fusesource.scalate.util._

  lazy val scalateEngine = {
    val engine = new TemplateEngine
    engine.resourceLoader = new FileResourceLoader(Some(Play.getFile(&quot;/app/views&quot;)))
    engine.classpath = Play.getFile(&quot;/tmp/classes&quot;).getAbsolutePath
    engine.workingDirectory = Play.getFile(&quot;tmp&quot;)
    engine.combinedClassPath = true
    engine.classLoader = Play.classloader
    engine
  }

  case class Template(name: String) {
    val scalateType = &quot;.&quot; + Play.configuration.get(&quot;scalate&quot;);

    def render(args: (Symbol, Any)*) = {
      scalateEngine.layout(name + scalateType, args.map {
        case (k, v) =&gt; k.name -&gt; v
      } toMap)
    }
  }

  def apply(template: String) = Template(template)
}
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Created a Scalate trait to override the render() method in Play&apos;s Controller class.
&lt;pre class=&quot;brush: scala&quot;&gt;
package controllers

import play.mvc.Http

trait Scalate {

  def render(args: (Symbol, Any)*) = {
    def defaultTemplate = Http.Request.current().action.replace(&quot;.&quot;, &quot;/&quot;)
    ScalateTemplate(defaultTemplate).render(args: _*);
  }
}
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Created an Application.scala controller with a default &lt;em&gt;index&lt;/em&gt; method.
&lt;pre class=&quot;brush: scala&quot;&gt;
package controllers

import play.mvc._
import models._

object Application extends Controller with Scalate {

  def index = {
    render(&apos;user -&gt; User(&quot;Raible&quot;))
  }
}
&lt;/pre&gt;The models/User.scala class is very simple:
&lt;pre class=&quot;brush: scala&quot;&gt;
package models

case class User(name:String)
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Lastly, I created an index.jade file in views/Application.
&lt;pre class=&quot;brush: scala&quot;&gt;
-@ var user: models.User
p Hi #{user.name},
- for(i &amp;lt;- 1 to 3)
  p= i
p See, I can count!
&lt;/pre&gt;
&lt;/ol&gt;
&lt;p&gt;After getting all this working, I decided it was time to get it into production. As luck would have it, &lt;a href=&quot;http://blog.heroku.com/archives/2011/8/29/play/&quot;&gt;Heroku had just announced Play support&lt;/a&gt; a few days earlier. I heard through the grapevine that Play Scala would work, so I gave it a try. It was amazingly easy. All I had to do was create an account, create a &quot;Procfile&quot; in my application&apos;s root directory and run a &lt;code&gt;heroku&lt;/code&gt; command followed by a &lt;code&gt;git push&lt;/code&gt;. It all looked great until Play tried to compile my Jade templates as Groovy templates:
&lt;/p&gt;
&lt;pre&gt;
Cannot start in PROD mode with errors 
Template compilation error (In /app/views/Application/index.jade around line 2) 
The template /app/views/Application/index.jade does not compile : #{user.name} is not closed. 
play.exceptions.TemplateCompilationException: #{user.name} is not closed. 
       at play.templates.TemplateCompiler.generate(TemplateCompiler.java:102) 
       at play.templates.TemplateCompiler.compile(TemplateCompiler.java:15) 
       at play.templates.GroovyTemplateCompiler.compile(GroovyTemplateCompiler.java:4 1)
&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;http://groups.google.com/group/play-framework/msg/75344463d19e0e36&quot;&gt;solution from Guillaume&lt;/a&gt; was simple enough and I renamed my &quot;views&quot; directory to &quot;templates&quot; and updated ScalateTemplate.scala accordingly. You can see the deployed application at &lt;a href=&quot;http://play-more.herokuapp.com&quot;&gt;http://play-more.herokuapp.com&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;The next steps in my Play Scala adventure will be trying to get the &lt;a href=&quot;http://www.playframework.org/modules/coffee&quot;&gt;CoffeeScript module&lt;/a&gt; to work. I also hope to integrate &lt;a href=&quot;http://html5boilerplate.com/&quot;&gt;HTML5 Boilerplate&lt;/a&gt; with Jade and &lt;a href=&quot;http://scalate.fusesource.org/documentation/user-guide.html#layouts&quot;&gt;Scalate Layouts&lt;/a&gt;. I&apos;ll be doing this with the mindset that HTML and JavaScript aren&apos;t &lt;em&gt;that&lt;/em&gt; bad. I expect a lot from CoffeeScript and Jade and hope I enjoy them as much as Strachan. &lt;img src=&quot;https://raibledesigns.com/images/smileys/wink.gif&quot; class=&quot;smiley&quot; alt=&quot;;-)&quot; title=&quot;;-)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In the meantime, here&apos;s some interesting links I&apos;ve seen recently encountered that discuss Scala and/or Play. I dig the passion and activity that exists in these communities.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://goodstuff.im/yes-virginia-scala-is-hard&quot;&gt;Yes, Virginia, Scala is hard&lt;/a&gt; and &lt;a href=&quot;http://goodstuff.im/scala-use-is-less-good-than-java-use-for-at-l&quot;&gt;the followup&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://groups.google.com/group/scala-user/browse_thread/thread/55b529c0c81335bc&quot;&gt;Scalatra vs Unfiltered vs Lift vs Play&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://groups.google.com/group/play-framework/browse_thread/thread/8cdca8216bffc464&quot;&gt;Introducing Play 2.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/integrating_oauth_with_appfuse_and</id>
        <title type="html">Integrating OAuth with AppFuse and its REST API</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/integrating_oauth_with_appfuse_and"/>
        <published>2011-07-05T10:56:48-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springsecurity" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rest" scheme="http://roller.apache.org/ns/tags/" />
        <category term="oauth" scheme="http://roller.apache.org/ns/tags/" />
        <category term="enunciate" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">One of the new features in &lt;a href=&quot;http://raibledesigns.com/rd/entry/appfuse_2_1_released&quot;&gt;AppFuse 2.1&lt;/a&gt; is an &lt;a href=&quot;http://issues.appfuse.org/browse/APF-897&quot;&gt;appfuse-ws&lt;/a&gt; archetype. This archetype leverages &lt;a href=&quot;http://enunciate.codehaus.org/&quot;&gt;Enunciate&lt;/a&gt; and &lt;a href=&quot;http://cxf.apache.org/&quot;&gt;CXF&lt;/a&gt; to create a project with a REST API and generated HTML documentation. Enunciate is a very useful tool, allowing you to develop web services with JAX-RS and JAX-WS annotations and have all types of client libraries generated. For me, it seems very useful for developing the backend of &lt;abbr title=&quot;Service Oriented Front End Applications&quot;&gt;SOFEA&lt;/abbr&gt; (a.k.a. modern) applications. &lt;/p&gt;
&lt;p&gt;Back in March, &lt;a href=&quot;http://www.java.net/blogs/stoicflame/&quot;&gt;Ryan Heaton&lt;/a&gt; published a nice article on &lt;a href=&quot;http://docs.codehaus.org/display/ENUNCIATE/Securing+Web+Services&quot;&gt;Securing Web Services&lt;/a&gt; in an Enunciate application. I decided to take his tutorial a step further and not only secure my web services, but also to integrate with  OAuth 2. In this tutorial, I&apos;ll show you how to create a new application with AppFuse WS, secure it, add OAuth support, and then use a client app to authenticate and retrieve data.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#create-appfuse-ws&quot;&gt;Create a New AppFuse WS Project&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#integrate-oauth&quot;&gt;Integrate Spring Security and OAuth&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#oauth-client&quot;&gt;Authenticate and Retrieve Data with Client&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;create-appfuse-ws&quot;&gt;
&lt;strong&gt;Create a New AppFuse WS Project&lt;/strong&gt;&lt;br/&gt;
To begin, I visited the &lt;a href=&quot;http://static.appfuse.org/archetypes.html&quot;&gt;Create AppFuse Archetypes&lt;/a&gt; page and created a new application using the &quot;Web Services Only&quot; option in the &lt;em&gt;Web Framework&lt;/em&gt; dropdown. Below is the command I used to create the &quot;appfuse-oauth&quot; project.
&lt;/p&gt;
&lt;pre&gt;
mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes \
-DarchetypeArtifactId=appfuse-ws-archetype -DarchetypeVersion=2.1.0 \
-DgroupId=org.appfuse.example -DartifactId=appfuse-oauth 
&lt;/pre&gt;
&lt;p&gt;After doing this, I started the app using &lt;strong&gt;mvn jetty:run&lt;/strong&gt; and confirmed it started OK. At this point, I was able to view the generated documentation for the application at &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt;. The screenshot below shows what the app looks like at this point.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm7.static.flickr.com/6004/5891597325_7f9829e158.jpg&quot; title=&quot;AppFuse WS Homepage&quot; rel=&quot;lightbox[appfuse-oauth]&quot;&gt;&lt;img src=&quot;//farm7.static.flickr.com/6004/5891597325_7f9829e158_m.jpg&quot; width=&quot;240&quot; height=&quot;198&quot; alt=&quot;AppFuse WS Homepage&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p style=&quot;font-weight: italic; color: #666; margin-left: 10px&quot;&gt;
NOTE: You might notice the REST endpoint of /{username}. This is &lt;a href=&quot;http://issues.appfuse.org/browse/APF-1246&quot; style=&quot;color: #666&quot;&gt;a bug&lt;/a&gt; in AppFuse 2.1.0 and has been fixed in SVN. It does not affect this tutorial.&lt;/p&gt;
&lt;p id=&quot;integrate-oauth&quot;&gt;
&lt;strong&gt;Integrate Spring Security and OAuth&lt;/strong&gt;&lt;br/&gt;
I originally tried to integrate Spring Security with Enunciate&apos;s &lt;a href=&quot;http://docs.codehaus.org/display/ENUNCIATE/Securing+Web+Services&quot;&gt;Securing Web Services Tutorial&lt;/a&gt;. However, it only secures endpoints and doesn&apos;t do enough filtering for OAuth support, so I ended up using a custom web.xml. I put this file in &lt;em&gt;src/main/resources&lt;/em&gt; and loaded it in my &lt;em&gt;enunciate.xml&lt;/em&gt; file. I also upgraded Spring Security and imported my security.xml file.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
  &amp;lt;?xml version=&quot;1.0&quot;?&amp;gt;
  &amp;lt;enunciate xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
             xsi:noNamespaceSchemaLocation=&quot;http://enunciate.codehaus.org/schemas/enunciate-1.22.xsd&quot;&amp;gt;
      ...
      &amp;lt;webapp mergeWebXML=&quot;src/main/resources/web.xml&quot;/&amp;gt;
      &amp;lt;modules&amp;gt;
      ...
          &amp;lt;spring-app disabled=&quot;false&quot; springVersion=&quot;3.0.5.RELEASE&quot;&amp;gt;
              &amp;lt;springImport uri=&quot;classpath:/applicationContext-resources.xml&quot;/&amp;gt;
              &amp;lt;springImport uri=&quot;classpath:/applicationContext-dao.xml&quot;/&amp;gt;
              &amp;lt;springImport uri=&quot;classpath:/applicationContext-service.xml&quot;/&amp;gt;
              &amp;lt;springImport uri=&quot;classpath:/applicationContext.xml&quot;/&amp;gt;
              &amp;lt;springImport uri=&quot;classpath:/security.xml&quot;/&amp;gt;
          &amp;lt;/spring-app&amp;gt;
      &amp;lt;/modules&amp;gt;
  &amp;lt;/enunciate&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Then I created &lt;em&gt;src/main/resources/web.xml&lt;/em&gt; with a filter for Spring Security and a DispatcherServlet for OAuth support.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;web-app xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;
         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&quot;
         version=&quot;3.0&quot;&amp;gt;

    &amp;lt;filter&amp;gt;
        &amp;lt;filter-name&amp;gt;securityFilter&amp;lt;/filter-name&amp;gt;
        &amp;lt;filter-class&amp;gt;org.springframework.web.filter.DelegatingFilterProxy&amp;lt;/filter-class&amp;gt;
        &amp;lt;init-param&amp;gt;
            &amp;lt;param-name&amp;gt;targetBeanName&amp;lt;/param-name&amp;gt;
            &amp;lt;param-value&amp;gt;springSecurityFilterChain&amp;lt;/param-value&amp;gt;
        &amp;lt;/init-param&amp;gt;
    &amp;lt;/filter&amp;gt;

    &amp;lt;filter-mapping&amp;gt;
        &amp;lt;filter-name&amp;gt;securityFilter&amp;lt;/filter-name&amp;gt;
        &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;
    &amp;lt;/filter-mapping&amp;gt;

    &amp;lt;servlet&amp;gt;
        &amp;lt;servlet-name&amp;gt;appfuse-oauth&amp;lt;/servlet-name&amp;gt;
        &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&amp;gt;
        &amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;
    &amp;lt;/servlet&amp;gt;

    &amp;lt;servlet-mapping&amp;gt;
        &amp;lt;servlet-name&amp;gt;appfuse-oauth&amp;lt;/servlet-name&amp;gt;
        &amp;lt;url-pattern&amp;gt;/oauth/*&amp;lt;/url-pattern&amp;gt;
    &amp;lt;/servlet-mapping&amp;gt;
&amp;lt;/web-app&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Next, I created a &lt;em&gt;src/main/resources/security.xml&lt;/em&gt; and used it to secure my API, specify a login page, supply the users and integrate OAuth (see the last 4 beans below). &lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans:beans xmlns=&quot;http://www.springframework.org/schema/security&quot;
             xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
             xmlns:beans=&quot;http://www.springframework.org/schema/beans&quot;
             xmlns:oauth=&quot;http://www.springframework.org/schema/security/oauth2&quot;
             xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
                           http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd&quot;&amp;gt;

    &amp;lt;http auto-config=&quot;true&quot;&amp;gt;
        &amp;lt;intercept-url pattern=&quot;/api/**&quot; access=&quot;ROLE_USER&quot;/&amp;gt;
        &amp;lt;intercept-url pattern=&quot;/oauth/**&quot; access=&quot;ROLE_USER&quot;/&amp;gt;
        &amp;lt;intercept-url pattern=&quot;/**&quot; access=&quot;IS_AUTHENTICATED_ANONYMOUSLY&quot;/&amp;gt;
        &amp;lt;form-login login-page=&quot;/login.jsp&quot; authentication-failure-url=&quot;/login.jsp?error=true&quot;
                    login-processing-url=&quot;/j_security_check&quot;/&amp;gt;
    &amp;lt;/http&amp;gt;

    &amp;lt;authentication-manager&amp;gt;
        &amp;lt;authentication-provider&amp;gt;
            &amp;lt;user-service&amp;gt;
                &amp;lt;user name=&quot;admin&quot; password=&quot;admin&quot; authorities=&quot;ROLE_USER,ROLE_ADMIN&quot;/&amp;gt;
                &amp;lt;user name=&quot;user&quot; password=&quot;user&quot; authorities=&quot;ROLE_USER&quot;/&amp;gt;
            &amp;lt;/user-service&amp;gt;
        &amp;lt;/authentication-provider&amp;gt;
    &amp;lt;/authentication-manager&amp;gt;

    &amp;lt;!--hook up the spring security filter chain--&amp;gt;
    &amp;lt;beans:alias name=&quot;springSecurityFilterChain&quot; alias=&quot;securityFilter&quot;/&amp;gt;

    &amp;lt;beans:bean id=&quot;tokenServices&quot;
                class=&quot;org.springframework.security.oauth2.provider.token.InMemoryOAuth2ProviderTokenServices&quot;&amp;gt;
        &amp;lt;beans:property name=&quot;supportRefreshToken&quot; value=&quot;true&quot;/&amp;gt;
    &amp;lt;/beans:bean&amp;gt;

    &amp;lt;oauth:provider client-details-service-ref=&quot;clientDetails&quot; token-services-ref=&quot;tokenServices&quot;&amp;gt;
        &amp;lt;oauth:verification-code user-approval-page=&quot;/oauth/confirm_access&quot;/&amp;gt;
    &amp;lt;/oauth:provider&amp;gt;

    &amp;lt;oauth:client-details-service id=&quot;clientDetails&quot;&amp;gt;
        &amp;lt;!--&amp;lt;oauth:client clientId=&quot;my-trusted-client&quot; authorizedGrantTypes=&quot;password,authorization_code,refresh_token&quot;/&amp;gt;
        &amp;lt;oauth:client clientId=&quot;my-trusted-client-with-secret&quot;
                      authorizedGrantTypes=&quot;password,authorization_code,refresh_token&quot; secret=&quot;somesecret&quot;/&amp;gt;
        &amp;lt;oauth:client clientId=&quot;my-less-trusted-client&quot; authorizedGrantTypes=&quot;authorization_code&quot;/&amp;gt;--&amp;gt;
        &amp;lt;oauth:client clientId=&quot;ajax-login&quot; authorizedGrantTypes=&quot;authorization_code&quot;/&amp;gt;
    &amp;lt;/oauth:client-details-service&amp;gt;
&amp;lt;/beans:beans&amp;gt;
&lt;/pre&gt;
&lt;p&gt;I used the &lt;a href=&quot;http://static.springsource.org/spring-security/oauth/tutorial.html&quot;&gt;OAuth for Spring Security sample apps&lt;/a&gt; to figure this out. In this example, I used authorizedGrantTypes=&quot;authorization_code&quot;, but you can see from the commented &amp;lt;oauth:client&gt; elements above that there&apos;s a few different options. You should also note that the clientId is hard-coded to &quot;ajax-login&quot;, signifying I only want to allow a single application to authenticate.
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;At this point, I&apos;d like to give a shoutout to Ryan Heaton for creating &lt;em&gt;both&lt;/em&gt; Enunciate and Spring Security&apos;s OAuth support. Nice work Ryan!&lt;/p&gt;
&lt;p&gt;At this point, I needed to do a number of additional tasks to finish integrating oauth. The first was to modify the Jetty Plugin&apos;s configuration to 1) run on port 9000, 2) load my custom files and 3) allow jetty:run to recognize Enunciate&apos;s generated files. Below is the final configuration in my pom.xml.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.mortbay.jetty&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-jetty-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;6.1.26&amp;lt;/version&amp;gt;
    &amp;lt;configuration&amp;gt;
        &amp;lt;connectors&amp;gt;
            &amp;lt;connector implementation=&quot;org.mortbay.jetty.nio.SelectChannelConnector&quot;&amp;gt;
                &amp;lt;port&amp;gt;9000&amp;lt;/port&amp;gt;
                &amp;lt;maxIdleTime&amp;gt;60000&amp;lt;/maxIdleTime&amp;gt;
            &amp;lt;/connector&amp;gt;
        &amp;lt;/connectors&amp;gt;
        &amp;lt;webAppConfig&amp;gt;
            &amp;lt;baseResource implementation=&quot;org.mortbay.resource.ResourceCollection&quot;&amp;gt;
                &amp;lt;resourcesAsCSV&amp;gt;
                    ${basedir}/src/main/webapp,
                    ${project.build.directory}/${project.build.finalName}
                &amp;lt;/resourcesAsCSV&amp;gt;
            &amp;lt;/baseResource&amp;gt;
            &amp;lt;contextPath&amp;gt;/appfuse-oauth&amp;lt;/contextPath&amp;gt;
        &amp;lt;/webAppConfig&amp;gt;
        &amp;lt;webXml&amp;gt;${project.build.directory}/${project.build.finalName}/WEB-INF/web.xml&amp;lt;/webXml&amp;gt;
    &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Next, I added the necessary OAuth dependencies for Spring Security to my pom.xml. Since the latest release is a milestone release, I had to add Spring&apos;s milestone repo too. 
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;repository&amp;gt;
    &amp;lt;id&amp;gt;spring-milestone&amp;lt;/id&amp;gt;
    &amp;lt;url&amp;gt;http://s3.amazonaws.com/maven.springframework.org/milestone&amp;lt;/url&amp;gt;
&amp;lt;/repository&amp;gt;
...
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-security-taglibs&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
    &amp;lt;exclusions&amp;gt;
        &amp;lt;exclusion&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-web&amp;lt;/artifactId&amp;gt;
        &amp;lt;/exclusion&amp;gt;
        &amp;lt;exclusion&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-support&amp;lt;/artifactId&amp;gt;
        &amp;lt;/exclusion&amp;gt;
    &amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.security.oauth&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-security-oauth&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0.0.M3&amp;lt;/version&amp;gt;
    &amp;lt;exclusions&amp;gt;
        &amp;lt;exclusion&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-beans&amp;lt;/artifactId&amp;gt;
        &amp;lt;/exclusion&amp;gt;
        &amp;lt;exclusion&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
        &amp;lt;/exclusion&amp;gt;
        &amp;lt;exclusion&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-core&amp;lt;/artifactId&amp;gt;
        &amp;lt;/exclusion&amp;gt;
    &amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-webmvc&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.5&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jstl&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.1.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;taglibs&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;standard&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.1.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Since I named my DispatcherServlet &quot;appfuse-oauth&quot; in web.xml, I created a &lt;em&gt;src/main/webapp/WEB-INF/appfuse-oauth-servlet.xml&lt;/em&gt; to configure Spring MVC. I had to create the &lt;em&gt;src/main/webapp/WEB-INF&lt;/em&gt; directory. &lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xmlns:mvc=&quot;http://www.springframework.org/schema/mvc&quot;
       xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd&quot;&amp;gt;

    &amp;lt;!-- Scans the classpath of this application for @Components to deploy as beans --&amp;gt;
    &amp;lt;context:component-scan base-package=&quot;org.appfuse.examples.webapp&quot;/&amp;gt;

    &amp;lt;!-- Configures the @Controller programming model --&amp;gt;
    &amp;lt;mvc:annotation-driven/&amp;gt;

    &amp;lt;!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory --&amp;gt;
    &amp;lt;bean class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&amp;gt;
        &amp;lt;property name=&quot;viewClass&quot; value=&quot;org.springframework.web.servlet.view.JstlView&quot;/&amp;gt;
        &amp;lt;property name=&quot;prefix&quot; value=&quot;/&quot;/&amp;gt;
        &amp;lt;property name=&quot;suffix&quot; value=&quot;.jsp&quot;/&amp;gt;
    &amp;lt;/bean&amp;gt;
&amp;lt;/beans&amp;gt;
&lt;/pre&gt;
&lt;p&gt;In order to show the OAuth confirmation page, I needed to create &lt;em&gt;src/main/java/org/appfuse/examples/webapp/AccessConfirmationController.java&lt;/em&gt; and map it to /oauth/confirm_access. I copied this from one of the sample projects and modified to use Spring&apos;s annotations.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package org.appfuse.examples.webapp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.ClientAuthenticationToken;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.verification.ClientAuthenticationCache;
import org.springframework.security.oauth2.provider.verification.DefaultClientAuthenticationCache;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.TreeMap;

/**
 * Controller for retrieving the model for and displaying the confirmation page
 * for access to a protected resource.
 *
 * @author Ryan Heaton
 */
@Controller
@RequestMapping(&quot;/confirm_access&quot;)
public class AccessConfirmationController {

    private ClientAuthenticationCache authenticationCache = new DefaultClientAuthenticationCache();
    @Autowired
    private ClientDetailsService clientDetailsService;

    @RequestMapping(method = RequestMethod.GET)
    protected ModelAndView confirm(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ClientAuthenticationToken clientAuth = authenticationCache.getAuthentication(request, response);
        if (clientAuth == null) {
            throw new IllegalStateException(&quot;No client authentication request to authorize.&quot;);
        }

        TreeMap&amp;lt;String, Object&amp;gt; model = new TreeMap&amp;lt;String, Object&amp;gt;();
        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
        model.put(&quot;auth_request&quot;, clientAuth);
        model.put(&quot;client&quot;, client);

        return new ModelAndView(&quot;access_confirmation&quot;, model);
    }
}
&lt;/pre&gt;
&lt;p&gt;This controller delegates to &lt;em&gt;src/main/webapp/access_confirmation.jsp&lt;/em&gt;. I created this file and filled it with code to display Accept and Deny buttons.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;%@ page import=&quot;org.springframework.security.core.AuthenticationException&quot; %&amp;gt;
&amp;lt;%@ page import=&quot;org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException&quot; %&amp;gt;
&amp;lt;%@ page import=&quot;org.springframework.security.oauth2.provider.verification.BasicUserApprovalFilter&quot; %&amp;gt;
&amp;lt;%@ page import=&quot;org.springframework.security.oauth2.provider.verification.VerificationCodeFilter&quot; %&amp;gt;
&amp;lt;%@ page import=&quot;org.springframework.security.web.WebAttributes&quot; %&amp;gt;
&amp;lt;%@ taglib prefix=&quot;authz&quot; uri=&quot;http://www.springframework.org/security/tags&quot; %&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot; %&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Confirm Access&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;all&quot;
          href=&quot;http://demo.appfuse.org/appfuse-struts/styles/simplicity/theme.css&quot;/&amp;gt;
    &amp;lt;style type=&quot;text/css&quot;&amp;gt;
        h1 {
            margin-left: -300px;
            margin-top: 50px
        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;

&amp;lt;h1&amp;gt;Confirm Access&amp;lt;/h1&amp;gt;

&amp;lt;div id=&quot;content&quot;&amp;gt;

    &amp;lt;% if (session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) != null &amp;amp;&amp;amp; 
                 !(session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) instanceof UnapprovedClientAuthenticationException)) { %&amp;gt;
    &amp;lt;div class=&quot;error&quot;&amp;gt;
        &amp;lt;h2&amp;gt;Woops!&amp;lt;/h2&amp;gt;

        &amp;lt;p&amp;gt;Access could not be granted.
            (&amp;lt;%= ((AuthenticationException) session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION)).getMessage() %&amp;gt;)&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;% } %&amp;gt;
    &amp;lt;c:remove scope=&quot;session&quot; var=&quot;SPRING_SECURITY_LAST_EXCEPTION&quot;/&amp;gt;

    &amp;lt;authz:authorize ifAnyGranted=&quot;ROLE_USER,ROLE_ADMIN&quot;&amp;gt;
        &amp;lt;h2&amp;gt;Please Confirm&amp;lt;/h2&amp;gt;

        &amp;lt;p&amp;gt;You hereby authorize &quot;&amp;lt;c:out value=&quot;${client.clientId}&quot; escapeXml=&quot;true&quot;/&amp;gt;&quot; to access your protected resources.&amp;lt;/p&amp;gt;

        &amp;lt;form id=&quot;confirmationForm&quot; name=&quot;confirmationForm&quot;
              action=&quot;&amp;lt;%=request.getContextPath() + VerificationCodeFilter.DEFAULT_PROCESSING_URL%&amp;gt;&quot; method=&quot;POST&quot;&amp;gt;
            &amp;lt;input name=&quot;&amp;lt;%=BasicUserApprovalFilter.DEFAULT_APPROVAL_REQUEST_PARAMETER%&amp;gt;&quot;
                   value=&quot;&amp;lt;%=BasicUserApprovalFilter.DEFAULT_APPROVAL_PARAMETER_VALUE%&amp;gt;&quot; type=&quot;hidden&quot;/&amp;gt;
            &amp;lt;label&amp;gt;&amp;lt;input name=&quot;authorize&quot; value=&quot;Authorize&quot; type=&quot;submit&quot;&amp;gt;&amp;lt;/label&amp;gt;
        &amp;lt;/form&amp;gt;
        &amp;lt;form id=&quot;denialForm&quot; name=&quot;denialForm&quot;
              action=&quot;&amp;lt;%=request.getContextPath() + VerificationCodeFilter.DEFAULT_PROCESSING_URL%&amp;gt;&quot; method=&quot;POST&quot;&amp;gt;
            &amp;lt;input name=&quot;&amp;lt;%=BasicUserApprovalFilter.DEFAULT_APPROVAL_REQUEST_PARAMETER%&amp;gt;&quot;
                   value=&quot;not_&amp;lt;%=BasicUserApprovalFilter.DEFAULT_APPROVAL_PARAMETER_VALUE%&amp;gt;&quot; type=&quot;hidden&quot;/&amp;gt;
            &amp;lt;label&amp;gt;&amp;lt;input name=&quot;deny&quot; value=&quot;Deny&quot; type=&quot;submit&quot;&amp;gt;&amp;lt;/label&amp;gt;
        &amp;lt;/form&amp;gt;
    &amp;lt;/authz:authorize&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Finally, I needed to create &lt;em&gt;src/main/webapp/login.jsp&lt;/em&gt; to allow users to login.&lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;%@ page language=&quot;java&quot; pageEncoding=&quot;UTF-8&quot; contentType=&quot;text/html;charset=utf-8&quot; %&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot; %&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot; prefix=&quot;fmt&quot; %&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot; %&amp;gt;

&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Login&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;all&quot;
          href=&quot;http://demo.appfuse.org/appfuse-struts/styles/simplicity/theme.css&quot;/&amp;gt;
    &amp;lt;style type=&quot;text/css&quot;&amp;gt;
        h1 {
            margin-left: -300px;
            margin-top: 50px
        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Login&amp;lt;/h1&amp;gt;

&amp;lt;form method=&quot;post&quot; id=&quot;loginForm&quot; action=&quot;&amp;lt;c:url value=&apos;/j_security_check&apos;/&amp;gt;&quot;&amp;gt;
    &amp;lt;fieldset style=&quot;padding-bottom: 0&quot;&amp;gt;
        &amp;lt;ul&amp;gt;
            &amp;lt;c:if test=&quot;${param.error != null}&quot;&amp;gt;
                &amp;lt;li class=&quot;error&quot;&amp;gt;
                    ${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}
                &amp;lt;/li&amp;gt;
            &amp;lt;/c:if&amp;gt;
            &amp;lt;li&amp;gt;
                &amp;lt;label for=&quot;j_username&quot; class=&quot;required desc&quot;&amp;gt;
                    Username &amp;lt;span class=&quot;req&quot;&amp;gt;*&amp;lt;/span&amp;gt;
                &amp;lt;/label&amp;gt;
                &amp;lt;input type=&quot;text&quot; class=&quot;text medium&quot; name=&quot;j_username&quot;
                       id=&quot;j_username&quot; tabindex=&quot;1&quot;/&amp;gt;
            &amp;lt;/li&amp;gt;

            &amp;lt;li&amp;gt;
                &amp;lt;label for=&quot;j_password&quot; class=&quot;required desc&quot;&amp;gt;
                    Password &amp;lt;span class=&quot;req&quot;&amp;gt;*&amp;lt;/span&amp;gt;
                &amp;lt;/label&amp;gt;
                &amp;lt;input type=&quot;password&quot; class=&quot;text medium&quot; name=&quot;j_password&quot;
                       id=&quot;j_password&quot; tabindex=&quot;2&quot;/&amp;gt;
            &amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;
                &amp;lt;input type=&quot;submit&quot; class=&quot;button&quot; name=&quot;login&quot; value=&quot;Login&quot;
                       tabindex=&quot;3&quot;/&amp;gt;
            &amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
    &amp;lt;/fieldset&amp;gt;
&amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;
&lt;p&gt;All the changes described in the above section are necessary to implement OAuth if you create a project with AppFuse WS 2.1. It may seem like a lot of code, but I was able to copy/paste and get it all working in an app in under 5 minutes. Hopefully you can do the same. I&apos;m also considering adding it by default to the next version of AppFuse. Now let&apos;s look at integrating OAuth into a client to authenticate and retrieve data from this application.
&lt;/p&gt;
&lt;p id=&quot;oauth-client&quot;&gt;&lt;strong&gt;Authenticate and Retrieve Data with Client&lt;/strong&gt;&lt;br/&gt;
I originally thought my &lt;a href=&quot;http://raibledesigns.com/rd/entry/implementing_oauth_with_gwt&quot;&gt;GWT OAuth&lt;/a&gt; application would provide a nice client. However, after 30 minutes of trying to get GWT 1.7.1 and the GWT Maven plugin (1.1) working with my 64-bit Java 6 JDK on OS X, I gave up. So I opted to use the &lt;a href=&quot;https://github.com/mraible/ajax-login&quot;&gt;Ajax Login&lt;/a&gt; application I&apos;ve been using in my recent security tutorials.
&lt;/p&gt;
&lt;p&gt;In this example, I used OAuth2RestTemplate from Spring Security OAuth. While this works, and works well, I&apos;d still like to get things working with GWT (or jQuery) to demonstrate how to do it from a pure client-side perspective.
&lt;/p&gt;
&lt;p&gt;To begin, I got the latest source of Ajax Login from GitHub (as of this morning) and made some changes. First of all, I added the Spring Security OAuth dependencies to pom.xml:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;repository&amp;gt;
    &amp;lt;id&amp;gt;spring-milestone&amp;lt;/id&amp;gt;
    &amp;lt;url&amp;gt;http://s3.amazonaws.com/maven.springframework.org/milestone&amp;lt;/url&amp;gt;
&amp;lt;/repository&amp;gt;
...
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.security.oauth&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-security-oauth&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0.0.M3&amp;lt;/version&amp;gt;
    &amp;lt;exclusions&amp;gt;
        &amp;lt;exclusion&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-beans&amp;lt;/artifactId&amp;gt;
        &amp;lt;/exclusion&amp;gt;
        &amp;lt;exclusion&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
        &amp;lt;/exclusion&amp;gt;
        &amp;lt;exclusion&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-core&amp;lt;/artifactId&amp;gt;
        &amp;lt;/exclusion&amp;gt;
    &amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Then I modified &lt;em&gt;src/main/webapp/WEB-INF/security.xml&lt;/em&gt; and added an OAuth Token Service and defined the location of the OAuth server.&lt;/p&gt; 
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans:beans xmlns=&quot;http://www.springframework.org/schema/security&quot;
             xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
             xmlns:beans=&quot;http://www.springframework.org/schema/beans&quot;
             xmlns:oauth=&quot;http://www.springframework.org/schema/security/oauth2&quot;
             xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd
              http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd&quot;&amp;gt;

...
    &amp;lt;oauth:client token-services-ref=&quot;oauth2TokenServices&quot;/&amp;gt;

    &amp;lt;beans:bean id=&quot;oauth2TokenServices&quot;
                class=&quot;org.springframework.security.oauth2.consumer.token.InMemoryOAuth2ClientTokenServices&quot;/&amp;gt;

    &amp;lt;oauth:resource id=&quot;appfuse&quot; type=&quot;authorization_code&quot; clientId=&quot;ajax-login&quot;
                    accessTokenUri=&quot;http://localhost:9000/appfuse-oauth/oauth/authorize&quot;
                    userAuthorizationUri=&quot;http://localhost:9000/appfuse-oauth/oauth/user/authorize&quot;/&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Next, I created a Controller that uses OAuth2RestTemplate to make the request and get the data from the AppFuse OAuth application&apos;s API. I created &lt;em&gt;src/main/java/org/appfuse/examples/webapp/oauth/UsersApiController.java&lt;/em&gt; and filled it with the following code:&lt;/p&gt;
&lt;pre class=&quot;brush: java; auto-links: false&quot;&gt;
package org.appfuse.examples.webapp.oauth;

import org.appfuse.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.consumer.*;
import org.springframework.security.oauth2.consumer.token.OAuth2ClientTokenServices;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.List;

@RequestMapping(&quot;/appfuse/users&quot;)
@Controller
public class UsersApiController {

    private OAuth2RestTemplate apiRestTemplate;
    @Autowired
    private OAuth2ClientTokenServices tokenServices;

    private static final String REMOTE_DATA_URL = &quot;http://localhost:9000/appfuse-oauth/api/users&quot;;

    @Autowired
    public UsersApiController(OAuth2ProtectedResourceDetails resourceDetails) {
        this.apiRestTemplate = new OAuth2RestTemplate(resourceDetails);
    }

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public List&amp;lt;User&amp;gt; getUsers() {
        try {
            List users = apiRestTemplate.getForObject(REMOTE_DATA_URL, List.class);
            return new ArrayList&amp;lt;User&amp;gt;(users);
        } catch (InvalidTokenException badToken) {
            //we&apos;ve got a bad token, probably because it&apos;s expired.
            OAuth2ProtectedResourceDetails resource = apiRestTemplate.getResource();
            OAuth2SecurityContext context = OAuth2SecurityContextHolder.getContext();
            if (context != null) {
                // this one is kind of a hack for this application
                // the problem is that the sparklr photos page doesn&apos;t remove the &apos;code=&apos; request parameter.
                ((OAuth2SecurityContextImpl) context).setVerificationCode(null);
            }
            //clear any stored access tokens...
            tokenServices.removeToken(SecurityContextHolder.getContext().getAuthentication(), resource);
            //go get a new access token...
            throw new OAuth2AccessTokenRequiredException(resource);
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;At this point, I thought everything would work and I spent quite some time banging my head against the wall when it didn&apos;t. As I was composing an email to the Enunciate users mailing list, I realized the issue. It appeared to be working, but from the server side, and the redirect back to the client was not happening. The Ajax Login app uses UrlRewriteFilter (for pretty URLs) to redirect from /app/* to /$1 and this redirect was losing the code parameter in the URL. 
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;rule&amp;gt;
    &amp;lt;from&amp;gt;/app/**&amp;lt;/from&amp;gt;
    &amp;lt;to last=&quot;true&quot; type=&quot;redirect&quot;&amp;gt;%{context-path}/$1&amp;lt;/to&amp;gt;
&amp;lt;/rule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;To fix this, I added use-query-string=&quot;true&quot; to the root element in &lt;em&gt;src/main/webapp/WEB-INF/urlrewrite.xml&lt;/em&gt;:
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;urlrewrite default-match-type=&quot;wildcard&quot; use-query-string=&quot;true&quot;&gt;
&lt;/pre&gt;
&lt;p&gt;After making all these changes, I ran &lt;strong&gt;mvn jetty:run&lt;/strong&gt; on both apps and opened &lt;a href=&quot;http://localhost:8080/appfuse/users&quot;&gt;http://localhost:8080/appfuse/users&lt;/a&gt; in my browser. It all worked and a smile crept across my face. I&apos;ve checked in the client changes into &lt;a href=&quot;https://github.com/mraible/ajax-login&quot;&gt;ajax-login on GitHub&lt;/a&gt; and the appfuse-oauth example into &lt;a href=&quot;http://code.google.com/p/appfuse-demos/&quot;&gt;AppFuse Demos on Google Code&lt;/a&gt;. If you&apos;d like to see this example in action, I&apos;d encourage you to checkout both projects and let me know if you find any issues.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/java_web_application_security_part4</id>
        <title type="html">Java Web Application Security - Part V: Penetrating with Zed Attack Proxy</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/java_web_application_security_part4"/>
        <published>2011-06-21T07:45:41-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="owaspzap" scheme="http://roller.apache.org/ns/tags/" />
        <category term="zedattackproxy" scheme="http://roller.apache.org/ns/tags/" />
        <category term="owasp" scheme="http://roller.apache.org/ns/tags/" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appsec" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tutorial" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springsecurity" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Web Application Security is an important part of developing applications. As developers, I think we often forget this, or simply ignore it. In my career, I&apos;ve learned a lot about web application security. However, I only recently learned and became familiar with the rapidly growing &quot;appsec&quot; industry. 
&lt;/p&gt;
&lt;p&gt;
I found a disconnect between what appsec consultants were selling and what I was developing. It seemed like appsec consultants were selling me fear, mostly because I thought my apps were secure. So I set out on a mission to learn more about web application security and penetration testing to see if my apps really were secure. This article is part of that mission, as are the previous articles I&apos;ve written in this series.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part&quot;&gt;Java Web Application Security - Part I: Java EE 6 Login Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part1&quot;&gt;Java Web Application Security - Part II: Spring Security Login Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part2&quot;&gt;Java Web Application Security - Part III: Apache Shiro Login Demo&lt;/a&gt;&lt;/li&gt;          
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part3&quot;&gt;Java Web Application Security - Part IV: Programmatic Login APIs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
When I first decided I wanted to do a talk on Webapp Security, I knew it would be more interesting if I showed the audience how to hack and fix an application. That&apos;s why I wrote it into my &lt;a href=&quot;http://raibledesigns.com/rd/entry/upcoming_conferences_tssjs_in_las&quot;&gt;original proposal&lt;/a&gt;:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
&lt;strong&gt;Webapp Security: Develop. Penetrate. Protect. Relax.&lt;/strong&gt;&lt;br/&gt;
In this session, you&apos;ll learn how to implement authentication in your Java web applications using Spring Security, Apache Shiro and good ol&apos; Java EE Container Managed Authentication. You&apos;ll also learn how to secure your REST API with OAuth and lock it down with SSL.
&lt;br/&gt;&lt;br/&gt;
After learning how to develop authentication, I&apos;ll introduce you to OWASP, the OWASP Top 10, its Testing Guide and its Code Review Guide. From there, I&apos;ll discuss using WebGoat to verify your app is secure and commercial tools like webapp firewalls and accelerators.&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;At the time, I hadn&apos;t done much &lt;a href=&quot;http://en.wikipedia.org/wiki/Penetration_test#Web_application_penetration_testing&quot;&gt;webapp pentesting&lt;/a&gt;. You can tell this from the fact that I mentioned &lt;em&gt;WebGoat&lt;/em&gt; as the pentesting tool. From &lt;a href=&quot;https://www.owasp.org/index.php/Category:OWASP_WebGoat_Project&quot;&gt;WebGoat&apos;s Project page&lt;/a&gt;:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;&lt;b&gt;WebGoat&lt;/b&gt; is a deliberately insecure J2EE web application maintained by &lt;a href=&quot;http://www.owasp.org&quot;&gt;OWASP&lt;/a&gt; designed to teach web application security lessons. In each lesson, users must demonstrate their understanding of a security issue by exploiting a real vulnerability in the WebGoat application. For example, in one of the lessons the user must use &lt;a href=&quot;https://www.owasp.org//index.php/SQL_injection&quot; title=&quot;SQL injection&quot;&gt;SQL injection&lt;/a&gt; to steal fake credit card numbers. The application is a realistic teaching environment, providing users with hints and code to further explain the lesson.&lt;/p&gt;
&lt;p&gt;What I really meant to say and use was &lt;a href=&quot;https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project&quot;&gt;Zed Attack Proxy&lt;/a&gt;, also known as OWASP ZAP. ZAP is a Java Desktop application that you setup as a proxy for your browser, then use to find vulnerabilities in your application. This article explains how you can use ZAP to pentest a web applications and fix its vulnerabilities.
&lt;/p&gt;
&lt;p&gt;The application I&apos;ll be using in this article is the Ajax Login application I&apos;ve been using throughout this series. I think it&apos;s great that projects like &lt;a href=&quot;http://www.dvwa.co.uk/&quot;&gt;Damn Vulnerable Web App&lt;/a&gt; and WebGoat exist, but I wanted to test one that I &lt;em&gt;think&lt;/em&gt; is secure, rather than one I know is not secure. In this particular example, I&apos;ll be testing the Spring Security implementation, since that&apos;s the framework I most often use in my open source projects. 
&lt;/p&gt;

&lt;p id=&quot;zap-tutorial&quot;&gt;&lt;strong&gt;Zed Attack Proxy Tutorial&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#download-run&quot;&gt;Download and Run the Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#install-zap&quot;&gt;Install and Configure ZAP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#scan&quot;&gt;Perform a Scan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#fix-vulnerabilities&quot;&gt;Fix Vulnerabilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#summary&quot;&gt;Summary&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p id=&quot;download-run&quot;&gt;&lt;strong&gt;Download and Run the Application&lt;/strong&gt;&lt;br/&gt;
To begin, &lt;a href=&quot;http://static.raibledesigns.com/downloads/ajax-login-zap-tutorial-1.0.zip&quot;&gt;download the application&lt;/a&gt; and expand it on your hard drive. This app is the completed version of the Ajax Login application referenced in &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part1&quot;&gt;Java Web Application Security - Part II: Spring Security Login Demo&lt;/a&gt;. You&apos;ll need Java 6 and Maven installed to run the app. Run it using &lt;strong&gt;mvn jetty:run&lt;/strong&gt; and open &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt; in your browser. You&apos;ll see it&apos;s a simple CRUD application for users and you need to login to do anything.&lt;/p&gt;

&lt;p id=&quot;install-zap&quot;&gt;&lt;strong&gt;Install and Configure ZAP&lt;/strong&gt;&lt;br/&gt;
The &lt;a href=&quot;https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project&quot;&gt;Zed Attack Proxy&lt;/a&gt; (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications. &lt;a href=&quot;http://code.google.com/p/zaproxy/downloads/list&quot;&gt;Download&lt;/a&gt; the latest version (I used 1.3.0) and install it on your system. After installing, launch the app and change the proxy port to 9000 (Tools &gt; Options &gt; Local Proxy). Next, configure your browser to proxy requests through port 9000 and allow localhost requests to be proxied. I used Firefox 4 (Preferences &gt; Advanced &gt; Network &gt; Connection Settings). When finished, your proxy settings should look like the following screenshot:
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm6.static.flickr.com/5301/5841907039_d8b4ec906d_o.jpg&quot; title=&quot;Firefox Proxy Settings&quot; rel=&quot;lightbox[security-zap]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5301/5841907039_e8b204a6d8_m.jpg&quot; width=&quot;240&quot; height=&quot;239&quot; alt=&quot;Firefox Proxy Settings&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Another option (instead of removing localhost) is to add an entry to your hosts file with your production domain name. This is what I&apos;ve done for this demo.&lt;/p&gt;
&lt;pre&gt;127.0.0.1       demo.raibledesigns.com&lt;/pre&gt;
&lt;p&gt;I&apos;ve also configured Apache to proxy requests to Jetty with the following mod_proxy settings in my httpd.conf:
  &lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;IfModule mod_proxy.c&amp;gt;
    ProxyRequests Off 
    ProxyPreserveHost Off 

    &amp;lt;VirtualHost *:80&amp;gt;
       ProxyPass  /  http://localhost:8080/
    &amp;lt;/VirtualHost&amp;gt;

    &amp;lt;VirtualHost *:443&amp;gt;
        SSLEngine on
        SSLProxyEngine on
        SSLCertificateFile &quot;/etc/apache2/ssl.key/server.crt&quot;
        SSLCertificateKeyFile &quot;/etc/apache2/ssl.key/server.key&quot;

        ProxyPass  /  https://localhost:8443/
    &amp;lt;/VirtualHost&amp;gt;
&amp;lt;/IfModule&amp;gt;
&lt;/pre&gt;
&lt;p id=&quot;scan&quot;&gt;&lt;strong&gt;Perform a Scan&lt;/strong&gt;&lt;br/&gt;
Now you need to give ZAP some data to work with. Using Firefox, I navigated to http://demo.raibledesigns.com and browsed around a bit, listing users, added a new one and deleted an existing one. After doing this, I noticed a number of flags in the ZAP UI under Sites. I then right-clicked on each site (one for http and one for https) and selected Attack &gt; Active Scan site. You should be able to do this from the &quot;Active Scan&quot; tab at the bottom of ZAP, but &lt;a href=&quot;http://code.google.com/p/zaproxy/issues/detail?id=123&quot;&gt;there&apos;s a bug when the URLs are the same&lt;/a&gt;. After doing this, I received a number of alerts, ranging from high (cross-site scripting) to low (password autocomplete). The screenshot below shows the various issues.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://www.flickr.com/photos/mraible/5842085881/&quot; title=&quot;ZAP Alerts&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3177/5842085881_c35dd95cd4_o.jpg&quot; width=&quot;394&quot; height=&quot;157&quot; alt=&quot;ZAP Alerts&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Now let&apos;s take a look at how to fix them.
&lt;p id=&quot;fix-vulnerabilities&quot;&gt;&lt;strong&gt;Fix Vulnerabilities&lt;/strong&gt;&lt;br/&gt;
One of the things not mentioned by the scan, but #1 in &lt;a href=&quot;http://software-security.sans.org/blog/2010/08/11/security-misconfigurations-java-webxml-files&quot;&gt;Seven Security (Mis)Configurations in Java web.xml Files&lt;/a&gt;, is Custom Error Pages Not Configured. Custom error pages are configured in this app, but error.jsp contains the following code:
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
&amp;lt;% if (exception != null) { %&amp;gt;
    &amp;lt;% exception.printStackTrace(new java.io.PrintWriter(out)); %&amp;gt;
&amp;lt;% } else { %&amp;gt;
    Please check your log files for further information.
&amp;lt;% } %&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Stack traces can be really useful to an attacker, so it&apos;s important to start by removing the above code from &lt;em&gt;src/main/webapp/error.jsp&lt;/em&gt;.
&lt;/p&gt;
&lt;p&gt;The rest of the issues have to do with XSS, autocomplete, and cookies. Let&apos;s start with the easy ones. Fixing autocomplete is easy enough; simply changed the HTML in login.jsp and userform.jsp to have &lt;code&gt;autocomplete=&quot;off&quot;&lt;/code&gt; as part of the &amp;lt;form&amp;gt; tag.&lt;/p&gt;
&lt;p&gt;Then modify web.xml so http-only and secure cookies are used. While you&apos;re at it, add session-timeout and tracking-mode as recommended by the aforementioned web.xml misconfigurations article.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;session-config&amp;gt;
    &amp;lt;session-timeout&amp;gt;15&amp;lt;/session-timeout&amp;gt;
    &amp;lt;cookie-config&amp;gt;
        &amp;lt;http-only&amp;gt;true&amp;lt;/http-only&amp;gt;
        &amp;lt;secure&amp;gt;true&amp;lt;/secure&amp;gt;
    &amp;lt;/cookie-config&amp;gt;
    &amp;lt;tracking-mode&amp;gt;COOKIE&amp;lt;/tracking-mode&amp;gt;
&amp;lt;/session-config&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Next, modify Spring Security&apos;s Remember Me configuration so it uses secure cookies. To do this, add &lt;code&gt;use-secure-cookies=&quot;true&quot;&lt;/code&gt; to the &amp;lt;remember-me&amp;gt; element in &lt;em&gt;security.xml&lt;/em&gt;.
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;remember-me user-service-ref=&quot;userService&quot; key=&quot;e37f4b31-0c45-11dd-bd0b-0800200c9a66&quot;
             use-secure-cookie=&quot;true&quot;/&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Unfortunately, Spring Security &lt;a href=&quot;https://jira.springsource.org/browse/SEC-1761&quot;&gt;doesn&apos;t support HttpOnly cookies&lt;/a&gt;, but will in a future release.
&lt;/p&gt;
&lt;p&gt;The next issue to solve is disabling directory browsing. You can do this by copying Jetty&apos;s webdefault.xml (from the org.eclipse.jetty:jetty-webapp JAR) into &lt;em&gt;src/test/resources&lt;/em&gt; and changing its &quot;dirAllowed&quot; &amp;lt;init-param&amp;gt; to false:
&lt;/p&gt;              
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;servlet&amp;gt;
  &amp;lt;servlet-name&amp;gt;default&amp;lt;/servlet-name&amp;gt;
  &amp;lt;servlet-class&amp;gt;org.mortbay.jetty.servlet.DefaultServlet&amp;lt;/servlet-class&amp;gt;
  &amp;lt;init-param&amp;gt;
    &amp;lt;param-name&amp;gt;acceptRanges&amp;lt;/param-name&amp;gt;
    &amp;lt;param-value&amp;gt;true&amp;lt;/param-value&amp;gt;
  &amp;lt;/init-param&amp;gt;
  &amp;lt;init-param&amp;gt;
    &amp;lt;param-name&amp;gt;dirAllowed&amp;lt;/param-name&amp;gt;
    &amp;lt;param-value&amp;gt;false&amp;lt;/param-value&amp;gt;
  &amp;lt;/init-param&amp;gt;
  &amp;lt;init-param&amp;gt;
&lt;/pre&gt;
&lt;p&gt;You&apos;ll also need to modify the plugin&apos;s configuration to point to this file by adding it to the &amp;lt;webAppConfig&amp;gt; section in pom.xml.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;configuration&amp;gt;
    &amp;lt;webAppConfig&amp;gt;
        &amp;lt;contextPath&amp;gt;/&amp;lt;/contextPath&amp;gt;
        &amp;lt;defaultsDescriptor&amp;gt;src/test/resources/webdefault.xml&amp;lt;/defaultsDescriptor&amp;gt;
    &amp;lt;/webAppConfig&amp;gt;
&lt;/pre&gt;&lt;p&gt;Of course, if you&apos;re running in production you&apos;ll want to configure this in your server&apos;s settings rather than in your pom.xml file.
&lt;/p&gt;
&lt;p&gt;Next, I set out to fix &lt;em&gt;secure page browser cache issues&lt;/em&gt;. I had the following settings in my SiteMesh decorator:&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;meta http-equiv=&quot;Cache-Control&quot; content=&quot;no-store&quot;/&gt;
&amp;lt;meta http-equiv=&quot;Pragma&quot; content=&quot;no-cache&quot;/&gt;
&lt;/pre&gt;  
&lt;p&gt;However, according to ZAP, the first meta tag should have &quot;no-cache&quot; instead of &quot;no-store&quot;, so I changed it to &quot;no-cache&quot;.&lt;/p&gt;
&lt;p&gt;After making all these changes, I created a new ZAP session and ran an active scan on both sites again. Below are the results:
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://www.flickr.com/photos/mraible/5854063700/&quot; title=&quot;Active Scan after Fixes&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5068/5854063700_8b57a2d49c_o.png&quot; width=&quot;345&quot; height=&quot;116&quot; alt=&quot;Active Scan after Fixes&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I believe the first issue (parameter tampering) is because I show the error page when a duplicate user exists. To fix this, I changed UserFormController so it catches a UserExistsException and sends the user back to the form.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
try {
    userManager.saveUser(user);
} catch (UserExistsException uex) {
    result.addError(new ObjectError(&quot;user&quot;, uex.getMessage()));
    return &quot;userform&quot;;
}
&lt;/pre&gt;
&lt;p&gt;However, this still doesn&apos;t seem to cause the alert to go away. This is likely because I&apos;m not filtering/escaping HTML when it&apos;s first submitted. I believe the best solution for this would be to use something like OWASP&apos;s &lt;a href=&quot;https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API&quot;&gt;ESAPI&lt;/a&gt; to filter parameter values. However, I was unable to find integration with Spring MVC&apos;s data binding, so I decided not to try and fix this vulnerability.&lt;/p&gt;
&lt;p&gt;Finally, I tried to disable jsessionid in URLs using &lt;a href=&quot;http://stackoverflow.com/questions/962729/is-it-possible-to-disable-jsessionid-in-tomcat-servlet&quot;&gt;suggestions from Stack Overflow&lt;/a&gt;. The previous setting in web.xml (&lt;code&gt;&amp;lt;tracking-mode&amp;gt;COOKIE&amp;lt;/tracking-mode&amp;gt;&lt;/code&gt;) should do this, but it doesn&apos;t seem to work with Jetty 8. The other issues (secure page browser cache, HttpOnly cookies and secure cookies), I was unable to solve.  The last two are issues caused by Spring Security as far as I can tell. 
&lt;p id=&quot;summary&quot;&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
In this article, I&apos;ve shown you how to pentest a web application using Firefox and OWASP&apos;s Zed Attack Proxy (ZAP). I found ZAP to be a nice tool for figuring out vulnerabilities, but it&apos;d be nice if it had a &quot;retest&quot; feature to see if you fixed an issue for a particular URL. It does have a &quot;resend&quot; feature, but running it didn&apos;t seem to clear alerts after I&apos;d fixed them.
&lt;/p&gt;
&lt;p&gt;The issues I wasn&apos;t able to solve seemed to be mostly related to frameworks (e.g. Spring Security and HttpOnly cookies) or servers (Jetty not using cookies for tracking). My suspicion is the Jetty issues are because it doesn&apos;t support Servlet 3 as well as it advertises. I believe this is fair; I am using a milestone release after all. I tried scanning &lt;a href=&quot;http://demo.raibledesigns.com/ajax-login&quot;&gt;http://demo.raibledesigns.com/ajax-login&lt;/a&gt; (which runs on Tomcat 7 at &lt;a href=&quot;http://www.contegix.com&quot;&gt;Contegix&lt;/a&gt;) and confirmed that no jsessionid exists.
&lt;/p&gt;
&lt;p&gt;Hopefully this article has helped you understand how to figure out security vulnerabilities in your web applications. I believe ZAP will continue to get more popular as developers become aware of it. If you feel ambitious and want to try and solve &lt;em&gt;all&lt;/em&gt; of the issues in my Ajax Login application, feel free to fork it on &lt;a href=&quot;https://github.com/mraible/ajax-login&quot;&gt;GitHub&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;If you&apos;re interested in talking more about Webapp Security, please leave a comment, meet me at &lt;a href=&quot;http://jazoon.com/Conference/Thursday-23-June/Matt-Raible&quot;&gt;Jazoon&lt;/a&gt; later this week or let&apos;s talk in July at &lt;a href=&quot;http://uberconf.com/topics/java_web_application_security__develop__penetrate__protect__relax_&quot;&gt;&#220;ber Conf&lt;/a&gt;.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/java_web_application_security_part3</id>
        <title type="html">Java Web Application Security - Part IV: Programmatic Login APIs</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/java_web_application_security_part3"/>
        <published>2011-06-06T21:44:09-06:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="javaee" scheme="http://roller.apache.org/ns/tags/" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="esapi" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tutorial" scheme="http://roller.apache.org/ns/tags/" />
        <category term="apacheshiro" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springsecurity" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appsec" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Over the last month, I&apos;ve posted a number of articles on implementing authentication with &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part&quot;&gt;Java EE 6&lt;/a&gt;, &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part1&quot;&gt;Spring Security&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part2&quot;&gt;Apache Shiro&lt;/a&gt;. One of the things I demonstrated in my live demos (at Utah&apos;s JUG Meetings) was programmatic authentication. I left this out of my screencasts and previous tutorials because I thought it&apos;d fit better in a comparison article.&lt;/p&gt;
&lt;p&gt;In this article, I&apos;d like to show you how you can programmatically login to an application using the aforementioned security frameworks. To do this, I&apos;ll be using my &lt;a href=&quot;https://github.com/mraible/ajax-login&quot;&gt;ajax-login&lt;/a&gt; application that I wrote for &lt;a href=&quot;http://raibledesigns.com/rd/entry/implementing_ajax_authentication_using_jquery&quot;&gt;Implementing Ajax Authentication using jQuery, Spring Security and HTTPS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To begin, I implemented a LoginController as a Spring MVC Controller that returns JSON. 
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package org.appfuse.examples.webapp.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(&quot;/api/login.json&quot;)
public class LoginController {

    @Autowired
    LoginService loginService;

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public LoginStatus getStatus() {
        return loginService.getStatus();
    }

    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public LoginStatus login(@RequestParam(&quot;j_username&quot;) String username,
                             @RequestParam(&quot;j_password&quot;) String password) {

        return loginService.login(username, password);
    }
}
&lt;/pre&gt;
&lt;p&gt;
This controller delegates its logic to a LoginService interface.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package org.appfuse.examples.webapp.security;

public interface LoginService {

  LoginStatus getStatus();

  LoginStatus login(String username, String password);
}
&lt;/pre&gt;
&lt;p id=&quot;theclient&quot;&gt;&lt;strong&gt;The Client&lt;/strong&gt;&lt;br/&gt;
The client for this controller is the same as mentioned in my &lt;a href=&quot;http://raibledesigns.com/rd/entry/implementing_ajax_authentication_using_jquery&quot;&gt;previous article&lt;/a&gt;, but I&apos;ll post it again for your convenience. I used jQuery and jQuery UI to implement a dialog that opens the login page on the same page rather than redirecting to the login page. The &quot;#demo&quot; locator refers to a button in the page.
&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
var dialog = $(&apos;&amp;lt;div&gt;&amp;lt;/div&gt;&apos;);

$(document).ready(function() {
    $.get(&apos;/login?ajax=true&apos;, function(data) {
        dialog.html(data);
        dialog.dialog({
            autoOpen: false,
	       title: &apos;Authentication Required&apos;
        });
    });

    $(&apos;#demo&apos;).click(function() {
      dialog.dialog(&apos;open&apos;);
      // prevent the default action, e.g., following a link
      return false;
    });
});
&lt;/pre&gt;
&lt;p&gt;The login page then has the following JavaScript to add a click handler to the &quot;login&quot; button that submits the request securely to the LoginController.
&lt;/p&gt;
&lt;pre class=&quot;brush: js; auto-links: false&quot;&gt;
var getHost = function() {
    var port = (window.location.port == &quot;8080&quot;) ? &quot;:8443&quot; : &quot;&quot;;
    return ((secure) ? &apos;https://&apos; : &apos;http://&apos;) + window.location.hostname + port;
};

var loginFailed = function(data, status) {
    $(&quot;.error&quot;).remove();
    $(&apos;#username-label&apos;).before(&apos;&lt;div class=&quot;error&quot;&gt;Login failed, please try again.&lt;/div&gt;&apos;);
};

$(&quot;#login&quot;).live(&apos;click&apos;, function(e) {
    e.preventDefault();
    $.ajax({url: getHost() + &quot;${ctx}/api/login.json&quot;,
        type: &quot;POST&quot;,
        beforeSend: function(xhr) {
            xhr.withCredentials = true;
        },
        data: $(&quot;#loginForm&quot;).serialize(),
        success: function(data, status) {
            if (data.loggedIn) {
                // success
                dialog.dialog(&apos;close&apos;);
                location.href = getHost() + &apos;${ctx}/users&apos;;
            } else {
                loginFailed(data);
            }
        },
        error: loginFailed
    });
});
&lt;/pre&gt;
&lt;p&gt;The biggest secret to making this all work (the HTTP -&gt; HTTPS communication, which is considered cross-domain), is the &lt;a href=&quot;http://www.sitepen.com/blog/2008/07/22/windowname-transport/&quot;&gt;window.name Transport&lt;/a&gt; and the &lt;a href=&quot;http://friedcellcollective.net/outbreak/jsjquerywindownameplugin/&quot;&gt;jQuery plugin&lt;/a&gt; that implements it. To make this plugin work with Firefox 3.6, I had to implement a Filter that adds Access-Control headers. 
&lt;/p&gt;
&lt;pre class=&quot;brush: java; auto-links: false&quot;&gt;
public class OptionsHeadersFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader(&quot;Access-Control-Allow-Origin&quot;, &quot;http://&quot; + req.getServerName());
        response.setHeader(&quot;Access-Control-Allow-Methods&quot;, &quot;GET,POST&quot;);
        response.setHeader(&quot;Access-Control-Max-Age&quot;, &quot;360&quot;);
        response.setHeader(&quot;Access-Control-Allow-Headers&quot;, &quot;x-requested-with&quot;);
        response.setHeader(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;);

        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {
    }

    public void destroy() {
    }
}
&lt;/pre&gt;
&lt;/p&gt;
&lt;p id=&quot;javaee6-loginservice&quot;&gt;&lt;strong&gt;Java EE 6 LoginService&lt;/strong&gt;&lt;br/&gt;
Java EE 6 has a few new methods in &lt;a href=&quot;http://download.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html&quot;&gt;HttpServletRequest&lt;/a&gt;:
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;authenticate(response)&lt;/li&gt;
&lt;li&gt;login(user, pass)&lt;/li&gt;
&lt;li&gt;logout()&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;In this example, I&apos;ll use the new &lt;em&gt;login(username, password)&lt;/em&gt; method. The hardest part about getting this working was finding the right Maven dependency. At first, I tried the one that seemed to make the most sense:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;javax&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;javaee-web-api&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;6.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Unfortunately, this resulted in a &lt;a href=&quot;http://hi.baidu.com/8741659422/blog/item/8410bf16104aef44f3de32b5.html&quot;&gt;strange error&lt;/a&gt; that  means the dependency has the interfaces, but not the implementation classes. I ended up using GlassFish&apos;s dependency instead (thanks to &lt;a href=&quot;http://stackoverflow.com/questions/1979957/maven-dependency-for-servlet-3-0-api&quot;&gt;Stack Overflow&lt;/a&gt; for the tip).
&lt;/p&gt;&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.glassfish&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;javax.servlet&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.0&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Since Servlet 3.0 doesn&apos;t appear to be in Maven Central, I had to add the GlassFish Repository to my pom.xml&apos;s &amp;lt;repositories&amp;gt; element.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; auto-links: false&quot;&gt;
&amp;lt;repository&amp;gt;
    &amp;lt;id&amp;gt;glassfish-repo&amp;lt;/id&amp;gt;
    &amp;lt;url&amp;gt;http://download.java.net/maven/glassfish&amp;lt;/url&amp;gt;
&amp;lt;/repository&amp;gt;
&lt;/pre&gt;
&lt;p&gt;After that, it was easy to implement the LoginService interface with a JavaEELoginService class:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package org.appfuse.examples.webapp.security;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

@Service(&quot;javaeeLoginService&quot;)
public class JavaEELoginService implements LoginService {
    private Log log = LogFactory.getLog(JavaEELoginService.class);

    @Autowired
    HttpServletRequest request;

    public LoginStatus getStatus() {
        if (request.getRemoteUser() != null) {
            return new LoginStatus(true, request.getRemoteUser());
        } else {
            return new LoginStatus(false, null);
        }
    }

    @Override
    public LoginStatus login(String username, String password) {
        try {
            if (request.getRemoteUser() == null) {
                request.login(username, password);
                log.debug(&quot;Login succeeded!&quot;);
            }
            return new LoginStatus(true, request.getRemoteUser());
        } catch (ServletException e) {
            e.printStackTrace();
            return new LoginStatus(false, null);
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;I tried to use this with &quot;mvn jetty:run&quot; (with version 8.0.0.M2 of the jetty-maven-plugin), but I got the following error:&lt;/p&gt;
&lt;pre&gt;
javax.servlet.ServletException
        at org.eclipse.jetty.server.Request.login(Request.java:1927)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:178)
        at $Proxy52.login(Unknown Source)
        at org.appfuse.examples.webapp.security.JavaEELoginService.login(JavaEELoginService.java:30)
&lt;/pre&gt;
&lt;p&gt;This lead me to believe that Servlet 3 is not quite implemented, so I tried it with Tomcat 7.0.8. To support SSL and container-managed authentication, I had to &lt;a href=&quot;http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html&quot;&gt;create a certificate keystore and uncomment the SSL Connector in $CATALINA_HOME/conf/server.xml&lt;/a&gt;. I also had to add an &quot;admin&quot; user with roles=&quot;ROLE_ADMIN&quot; to $CATALINA_HOME/conf/tomcat-users.xml.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;user username=&quot;admin&quot; password=&quot;admin&quot; roles=&quot;ROLE_ADMIN&quot;/&gt;
&lt;/pre&gt;
&lt;p&gt;With Tomcat 7, I was able to login successfully, proven by the following logging.&lt;/p&gt;
&lt;pre&gt;
DEBUG - JavaEELoginService.login(31) | Login succeeded!
&lt;/pre&gt;
&lt;p&gt;However, in the UI, I still got a &quot;Login failed, please try again.&quot; message. Recalling that I had some issues with ports previous, I configured Apache to proxy the default http/https ports to 8080/8443 and tried again. This time it worked!&lt;/p&gt;
&lt;p id=&quot;springsecurity-loginservice&quot;&gt;&lt;strong&gt;Spring Security LoginService&lt;/strong&gt;&lt;br/&gt;
Spring Security offers a programmatic API and I was able to implement its LoginService as follows:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package org.appfuse.examples.webapp.security;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.appfuse.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

@Service(&quot;springLoginService&quot;)
public class SpringSecurityLoginService implements LoginService {
    private Log log = LogFactory.getLog(SpringSecurityLoginService.class);

    @Autowired(required = false)
    @Qualifier(&quot;authenticationManager&quot;)
    AuthenticationManager authenticationManager;

    public LoginStatus getStatus() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null &amp;&amp; !auth.getName().equals(&quot;anonymousUser&quot;) &amp;&amp; auth.isAuthenticated()) {
            return new LoginStatus(true, auth.getName());
        } else {
            return new LoginStatus(false, null);
        }
    }

    public LoginStatus login(String username, String password) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        User details = new User(username);
        token.setDetails(details);

        try {
            Authentication auth = authenticationManager.authenticate(token);
            log.debug(&quot;Login succeeded!&quot;);
            SecurityContextHolder.getContext().setAuthentication(auth);
            return new LoginStatus(auth.isAuthenticated(), auth.getName());
        } catch (BadCredentialsException e) {
            return new LoginStatus(false, null);
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;I then modified the LoginService dependency in LoginController so this implementation would be used.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Autowired
@Qualifier(&quot;springLoginService&quot;)
LoginService loginService;
&lt;/pre&gt;
&lt;p&gt;Since Spring&apos;s API doesn&apos;t depend on Servlet 3, I tried it in Jetty using &quot;mvn jetty:run&quot;. Of course, I modified my web.xml accordingly for Spring Security before doing so. Interestingly enough, I found that the my SpringSecurityLoginService seemed to work:
&lt;/p&gt;
&lt;pre&gt;DEBUG - SpringSecurityLoginService.login(39) | Login succeeded!&lt;/pre&gt;
&lt;p&gt;But in the UI, the login failed with a &quot;Login failed, please try again.&quot; message. Using the standard ports with Apache in front of Jetty solved this issue.
&lt;p id=&quot;apacheshiro-loginservice&quot;&gt;&lt;strong&gt;Apache Shiro LoginService&lt;/strong&gt;&lt;br/&gt;
Apache Shiro is nice enough to offer a programmatic API as well. I was able to implement a ShiroLoginService as follows:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package org.appfuse.examples.webapp.security;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;

@Service(&quot;shiroLoginService&quot;)
public class ShiroLoginService implements LoginService {
    private Log log = LogFactory.getLog(ShiroLoginService.class);

    public LoginStatus getStatus() {
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.isAuthenticated()) {
            return new LoginStatus(true, currentUser.getPrincipal().toString());
        } else {
            return new LoginStatus(false, null);
        }
    }

    public LoginStatus login(String username, String password) {
        if (!getStatus().isLoggedIn()) {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            Subject currentUser = SecurityUtils.getSubject();
            try {
                currentUser.login(token);
                log.debug(&quot;Login succeeded!&quot;);
                return new LoginStatus(currentUser.isAuthenticated(),
                        currentUser.getPrincipal().toString());
            } catch (AuthenticationException e) {
                return new LoginStatus(false, null);
            }

        } else {
            return getStatus();
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;Then I modified the LoginService dependency in LoginController so this implementation would be used.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Autowired
@Qualifier(&quot;shiroLoginService&quot;)
LoginService loginService;
&lt;/pre&gt;&lt;p&gt;Next, I modified my web.xml for Apache Shiro and tried &quot;mvn jetty:run&quot;. Again, the login appeared to succeed (based on log messages) on the server, but failed in the UI. When using http://localhost instead of http://localhost:8080, everything worked fine.&lt;/p&gt;
&lt;p id=&quot;summary&quot;&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
This article has shown you how you can programmatically login using Java EE 6, Spring Security and Apache Shiro. Before Java EE 6 (and Servlet 3), there was no API to programmatically login, so this is a welcome addition. The fact that my Ajax login example didn&apos;t work when ports differed is because of browsers&apos; &lt;a href=&quot;http://en.wikipedia.org/wiki/Same_origin_policy&quot;&gt;same origin policy&lt;/a&gt;, which specifies the ports have to be the same. Specifying no ports (the defaults), seems to be the loophole.
&lt;/p&gt;
&lt;p&gt;On a related note, I&apos;ve discovered some interesting articles recently from the &lt;a href=&quot;http://software-security.sans.org/blog&quot;&gt;AppSec Blog&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://software-security.sans.org/blog/2010/08/11/security-misconfigurations-java-webxml-files&quot;&gt;Seven Security (Mis)Configurations in Java web.xml Files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://software-security.sans.org/blog/2011/06/06/safer-software-through-secure-frameworks&quot;&gt;Safer Software through Secure Frameworks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The 2nd article has an interesting paragraph:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;... there&apos;s &lt;a href=&quot;http://shiro.apache.org/&quot;&gt;Apache Shiro&lt;/a&gt; (FKA &lt;a href=&quot;http://www.jsecurity.org/&quot;&gt;JSecurity&lt;/a&gt; and then later as Apache &lt;a href=&quot;http://incubator.apache.org/ki/&quot;&gt;Ki&lt;/a&gt;), another secure framework for Java apps. Although it looks &lt;a href=&quot;http://shiro.apache.org/10-minute-tutorial.html&quot;&gt;simpler to use and understand&lt;/a&gt; than ESAPI and covers most of the main security bases (authentication, authorization, session management and encryption), it doesn&apos;t help take care of important functions like input validation and output encoding. And Spring users have &lt;a href=&quot;http://static.springsource.org/spring-security/site/&quot;&gt;Spring Security&lt;/a&gt; (Acegi) a comprehensive, but heavyweight authorization and authentication framework.
&lt;/p&gt;So according to this blog, the security frameworks discussed here aren&apos;t the best.&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
The most comprehensive, up-to-date choice for Java developers is OWASP&apos;s &lt;a href=&quot;https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API&quot;&gt;ESAPI Enterprise Security API&lt;/a&gt; especially now that the 2.0 release has just come out. 
&lt;/p&gt;
&lt;p&gt;I haven&apos;t heard of many organizations adopting ESAPI over Java EE 6, Spring Security or Apache Shiro, but maybe I&apos;m wrong. Is ESAPI something that&apos;s being used out there by companies?
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/java_web_application_security_part2</id>
        <title type="html">Java Web Application Security - Part III: Apache Shiro Login Demo</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/java_web_application_security_part2"/>
        <published>2011-05-26T16:43:22-06:00</published>
        <updated>2015-07-07T01:37:14-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="presentation" scheme="http://roller.apache.org/ns/tags/" />
        <category term="web" scheme="http://roller.apache.org/ns/tags/" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="apacheshiro" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ujug" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">A couple weeks ago, I wrote &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part1&quot;&gt;a tutorial on how to implement security with Spring Security&lt;/a&gt;. The week prior, I wrote a &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part&quot;&gt;similar tutorial for Java EE 6&lt;/a&gt;. This week, I&apos;d like to show you how to implement the same features using &lt;a href=&quot;http://shiro.apache.org&quot;&gt;Apache Shiro&lt;/a&gt;. As I mentioned in previous articles, I&apos;m writing this because I told the audience at April&apos;s &lt;a href=&quot;http://ujug.org&quot;&gt;UJUG&lt;/a&gt; that I would publish screencasts of the demos.
&lt;/p&gt;
&lt;p&gt;
Today, I&apos;ve finished the third screencast showing how to implement security with Apache Shiro. Below is the presentation (with the screencast embedded on slide 22) as well as a step-by-step tutorial.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/o4wwswiZck6bKS&quot; width=&quot;510&quot; height=&quot;420&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen&gt; &lt;/iframe&gt;
&lt;br/&gt;
&lt;div style=&quot;font-size: .9em; text-align: left&quot;&gt;* You can also &lt;a href=&quot;http://www.youtube.com/watch?v=YJByiDvOhsc&quot;&gt;watch the screencast on YouTube&lt;/a&gt; or &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/Java_Web_Application_Security_UJUG2011.pdf&quot;&gt;download the presentation PDF&lt;/a&gt;.&lt;/div&gt;
&lt;/p&gt;

&lt;p id=&quot;apacheshiro-login-tutorial&quot;&gt;&lt;strong&gt;Apache Shiro Login Tutorial&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#download-run&quot;&gt;Download and Run the Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#secure-basic&quot;&gt;Implement Basic Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#ssl&quot;&gt;Force SSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#form-authentication&quot;&gt;Implement Form-based Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#jdbc&quot;&gt;Store Users in a Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#summary&quot;&gt;Summary&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;download-run&quot;&gt;&lt;strong&gt;Download and Run the Application&lt;/strong&gt;&lt;br/&gt;

To begin, &lt;a href=&quot;http://static.raibledesigns.com/downloads/ajax-login-apacheshiro-tutorial-1.0.zip&quot;&gt;download the application&lt;/a&gt; you&apos;ll be implementing security in. This app is a stripped-down version of the Ajax Login application I wrote for my article on &lt;a href=&quot;http://raibledesigns.com/rd/entry/implementing_ajax_authentication_using_jquery&quot;&gt;Implementing Ajax Authentication using jQuery, Spring Security and HTTPS&lt;/a&gt;. You&apos;ll need Java 6 and Maven installed to run the app. Run it using &lt;strong&gt;mvn jetty:run&lt;/strong&gt; and open &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt; in your browser. You&apos;ll see it&apos;s a simple CRUD application for users and there&apos;s no login required to add or delete users.&lt;/p&gt;

&lt;p id=&quot;secure-basic&quot;&gt;&lt;strong&gt;Implement Basic Authentication&lt;/strong&gt;&lt;br/&gt;
  
The first step is to protect the list screen so people have to login to view users. To do this, you&apos;ll need to create a shiro.ini file Shiro&apos;s configuration. Create &lt;em&gt;src/main/resources/shiro.ini&lt;/em&gt; and populate it with the contents below:
&lt;/p&gt;
&lt;pre&gt;
[main]

[users]
admin = admin, ROLE_ADMIN

[roles]
ROLE_ADMIN = *

[urls]
/app/users = authcBasic
&lt;/pre&gt;
&lt;p&gt;You can see this file has four sections and is pretty simple to read and understand. For more information about what each section is for, check out &lt;a href=&quot;http://shiro.apache.org/configuration.html#Configuration-INISections&quot;&gt;Shiro&apos;s configuration documentation&lt;/a&gt;.
&lt;p&gt;Next, open &lt;em&gt;src/main/webapp/WEB-INF/web.xml&lt;/em&gt; and add Shiro&apos;s IniShiroFilter:&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;filter&amp;gt;
    &amp;lt;filter-name&amp;gt;securityFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;filter-class&amp;gt;org.apache.shiro.web.servlet.IniShiroFilter&amp;lt;/filter-class&amp;gt;
    &amp;lt;!-- no init-param means load the INI config from classpath:shiro.ini --&amp;gt;
&amp;lt;/filter&amp;gt;
&lt;/pre&gt;
&lt;p&gt;And add its filter-mapping just after the rewriteFilter in the filter-mappings section (order is important!):
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;rewriteFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;securityFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;
    &amp;lt;dispatcher&amp;gt;REQUEST&amp;lt;/dispatcher&amp;gt;
    &amp;lt;dispatcher&amp;gt;FORWARD&amp;lt;/dispatcher&amp;gt;
    &amp;lt;dispatcher&amp;gt;INCLUDE&amp;lt;/dispatcher&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
Then add Shiro&apos;s &lt;em&gt;core&lt;/em&gt; and &lt;em&gt;web&lt;/em&gt; dependencies to your pom.xml:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.shiro&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;shiro-core&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.1.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.shiro&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;shiro-web&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.1.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
At this point, if you restart Jetty (Ctrl+C and jetty:run again), you should be prompted to login when you click on the &quot;Users&quot; tab. Enter admin/admin to login. Apache Shiro is easier to configure than Spring Security out-of-the-box, mostly because it doesn&apos;t require XML.
&lt;/p&gt;
&lt;p&gt;After logging in, you can try to logout by clicking the &quot;Logout&quot; link in the top-right corner. This calls a LogoutController with the following code that logs the user out.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public void logout(HttpServletResponse response) throws ServletException, IOException {
    request.getSession().invalidate();
    response.sendRedirect(request.getContextPath()); 
}
&lt;/pre&gt; 
&lt;p class=&quot;quote&quot; style=&quot;font-style: italic; color: #666&quot;&gt;NOTE: Shiro doesn&apos;t currently have a way to logout with its API. However, &lt;a href=&quot;https://issues.apache.org/jira/browse/SHIRO-284&quot;&gt;it will be added in the 1.2 release&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You&apos;ll notice that clicking this link doesn&apos;t log you out, even though the session is invalidated. The only way to logout with basic authentication is to close the browser. In order to get the ability to logout, as well as to have more control over the look-and-feel of the login, you can implement form-based authentication.
  Before you implement form-based authentication, I&apos;d like to show you how easy it is to force SSL with Apache Shiro.
&lt;/p&gt;
&lt;p id=&quot;ssl&quot;&gt;&lt;strong&gt;Force SSL&lt;/strong&gt;&lt;br/&gt;
Apache Shiro allows you to force SSL on a URL by simply adding &quot;ssl[&lt;em&gt;port&lt;/em&gt;]&quot; to a URL in the [urls] section. If you don&apos;t specify the port, it will use the default port (443). I&apos;m not sure if it allows you to switch back to http like Spring Security&apos;s &lt;em&gt;requires-channel&lt;/em&gt;, but I don&apos;t think it does. Modify the URLs section of your &lt;em&gt;shiro.ini&lt;/em&gt; to have the following:
&lt;/p&gt;
&lt;pre&gt;[urls]
/app/users = ssl[8443],authc
&lt;/pre&gt;
&lt;p&gt;In order for this to work, you have to configure Jetty to listen on an SSL port. Add the following just after the jetty-maven-plugin&apos;s &amp;lt;/webAppConfig&amp;gt; element in your pom.xml:
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;connectors&amp;gt;
    &amp;lt;connector implementation=&quot;org.eclipse.jetty.server.nio.SelectChannelConnector&quot;&amp;gt;
        &amp;lt;forwarded&amp;gt;true&amp;lt;/forwarded&amp;gt;
        &amp;lt;port&amp;gt;8080&amp;lt;/port&amp;gt;
    &amp;lt;/connector&amp;gt;
    &amp;lt;connector implementation=&quot;org.eclipse.jetty.server.ssl.SslSelectChannelConnector&quot;&amp;gt;
        &amp;lt;forwarded&amp;gt;true&amp;lt;/forwarded&amp;gt;
        &amp;lt;port&amp;gt;8443&amp;lt;/port&amp;gt;
        &amp;lt;maxIdleTime&amp;gt;60000&amp;lt;/maxIdleTime&amp;gt;
        &amp;lt;keystore&amp;gt;${project.build.directory}/ssl.keystore&amp;lt;/keystore&amp;gt;
        &amp;lt;password&amp;gt;appfuse&amp;lt;/password&amp;gt;
        &amp;lt;keyPassword&amp;gt;appfuse&amp;lt;/keyPassword&amp;gt;
    &amp;lt;/connector&amp;gt;
&amp;lt;/connectors&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The keystore must be generated for Jetty to start successfully, so add the keytool-maven-plugin just above the jetty-maven-plugin in pom.xml.
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;keytool-maven-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;
    &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;phase&amp;gt;generate-resources&amp;lt;/phase&amp;gt;
            &amp;lt;id&amp;gt;clean&amp;lt;/id&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;clean&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
        &amp;lt;/execution&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;phase&amp;gt;generate-resources&amp;lt;/phase&amp;gt;
            &amp;lt;id&amp;gt;genkey&amp;lt;/id&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;genkey&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
        &amp;lt;/execution&amp;gt;
    &amp;lt;/executions&amp;gt;
    &amp;lt;configuration&amp;gt;
        &amp;lt;keystore&amp;gt;${project.build.directory}/ssl.keystore&amp;lt;/keystore&amp;gt;
        &amp;lt;dname&amp;gt;cn=localhost&amp;lt;/dname&amp;gt;
        &amp;lt;keypass&amp;gt;appfuse&amp;lt;/keypass&amp;gt;
        &amp;lt;storepass&amp;gt;appfuse&amp;lt;/storepass&amp;gt;
        &amp;lt;alias&amp;gt;appfuse&amp;lt;/alias&amp;gt;
        &amp;lt;keyalg&amp;gt;RSA&amp;lt;/keyalg&amp;gt;
    &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Now if you restart Jetty, go to &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt; and click on the &quot;Users&quot; tab, you&apos;ll be prompted to accept the Untrusted Certificate and then redirected to https://localhost:8443/users after logging in. 
&lt;/p&gt;
&lt;p&gt;Now let&apos;s look at how to have more control over the look-and-feel of the login screen, as well as how to make logout work with form-based authentication.&lt;/p&gt;
&lt;p id=&quot;form-authentication&quot;&gt;&lt;strong&gt;Implement Form-based Authentication&lt;/strong&gt;&lt;br/&gt;
To change from basic to form-based authentication, you simply have to add a few lines to shiro.ini. First of all, since I&apos;d rather not change the name of the input elements in login.jsp, override the default names in the [main] section:
&lt;/p&gt;
&lt;pre&gt;
# name of request parameter with username; if not present filter assumes &apos;username&apos;
authc.usernameParam = j_username
# name of request parameter with password; if not present filter assumes &apos;password&apos;
authc.passwordParam = j_password
authc.failureKeyAttribute = shiroLoginFailure
&lt;/pre&gt;
&lt;p&gt;Then change the [urls] section to filter on login.jsp and use &quot;authc&quot; instead of &quot;authcBasic&quot;:
&lt;pre&gt;[urls]
# The /login.jsp is not restricted to authenticated users (otherwise no one could log in!), but
# the &apos;authc&apos; filter must still be specified for it so it can process that url&apos;s
# login submissions. It is &apos;smart&apos; enough to allow those requests through as specified by the
# shiro.loginUrl above.
/login.jsp = authc
/app/users = ssl[8443],authc
&lt;/pre&gt;
&lt;p&gt;Then change login.jsp so the form&apos;s action is blank (causing it to submit to itself) instead of j_security_check:&lt;/p&gt;
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;form action=&quot;&quot; id=&quot;loginForm&quot; method=&quot;post&quot;&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Now, restart Jetty and you should be prompted to login with this JSP instead of the basic authentication dialog.
&lt;/p&gt;
&lt;p id=&quot;jdbc&quot;&gt;&lt;strong&gt;Store Users in a Database&lt;/strong&gt;&lt;br/&gt;
To store your users in a database instead of file, you&apos;ll need to add a few settings to shiro.ini to define your database and tables to use. Open &lt;em&gt;src/main/resources/shiro.ini&lt;/em&gt; and add the following lines under the [main] section.
&lt;/p&gt;
&lt;pre&gt;
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
#jdbcRealm.permissionsLookupEnabled=false
# If not filled, subclasses of JdbcRealm assume &quot;select password from users where username = ?&quot;
jdbcRealm.authenticationQuery = select user_pass from users where user_name = ?
# If not filled, subclasses of JdbcRealm assume &quot;select role_name from user_roles where username = ?&quot;
jdbcRealm.userRolesQuery = select role_name from users_roles where user_name = ?

ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.databaseName = appfuse
jdbcRealm.dataSource = $ds
&lt;/pre&gt;
&lt;p class=&quot;quote&quot; style=&quot;margin-left: 0; color: #666&quot;&gt;This configuration is similar to what I did with the Java EE 6 tutorial where I&apos;m pointing to a database other than the H2 instance that&apos;s used by the application. I believe Shiro can talk to a DAO like Spring Security, but I have yet to explore that option.
&lt;/p&gt;
&lt;p&gt;While you&apos;re at it, add the following lines to enable password encryption.&lt;/p&gt;
&lt;pre&gt;
sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
jdbcRealm.credentialsMatcher = $sha256Matcher
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;You&apos;ll need to &lt;a href=&quot;http://dev.mysql.com/downloads/mysql/5.5.html&quot;&gt;install MySQL&lt;/a&gt; for this to work. After installing it, you should be able to create an &quot;appfuse&quot; database using the following command:
&lt;/p&gt;
&lt;pre&gt;
mysql -u root -p -e &apos;create database appfuse&apos;
&lt;/pre&gt;
&lt;p&gt;Then create the tables necessary and populate it with an &apos;admin&apos; user. Login using &quot;mysql -u root -p appfuse&quot; and execute the following SQL statements:&lt;/p&gt;
&lt;pre&gt;
create table users (
  user_name         varchar(30) not null primary key,
  user_pass         varchar(100) not null
);

create table user_roles (
  user_name         varchar(30) not null,
  role_name         varchar(30) not null,
  primary key (user_name, role_name)
);

insert into users values (&apos;admin&apos;, &apos;22f256eca1f336a97eef2b260773cb0d81d900c208ff26e94410d292d605fed8&apos;);
insert into user_roles values (&apos;admin&apos;, &apos;ROLE_ADMIN&apos;);
&lt;/pre&gt;
&lt;p&gt;Now if you restart Jetty, you should be able to login with admin/adminjdbc and view the list of users.
&lt;/p&gt;
&lt;p id=&quot;summary&quot;&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
In this tutorial, you learned how to implement authentication using Apache Shiro 1.1.0. I don&apos;t have a lot of experience with Apache Shiro, but I was able to get the basics working without too much effort. This tutorial doesn&apos;t show how to do Remember Me because I couldn&apos;t figure it out in 5 minutes, which means I have 5 more minutes before it fails the 10-minute test. &lt;img src=&quot;https://raibledesigns.com/images/smileys/wink.gif&quot; class=&quot;smiley&quot; alt=&quot;;)&quot; title=&quot;;)&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;
Shiro was formerly named &lt;a href=&quot;http://www.jsecurity.org/&quot;&gt;JSecurity&lt;/a&gt; and has been an Apache project for less than a year. It seems to be more targeted towards non-web use, so its certainly something to look at if you&apos;re more interested in cryptography or non-web apps. I think there&apos;s a good chance this project will continue to grow and be used more as more developers learn about it. The Apache brand certainly doesn&apos;t hurt.
&lt;/p&gt;
&lt;p&gt;
I didn&apos;t include a slide about the limitations I found with Shiro, mostly because I haven&apos;t used it much. I&apos;ve used Java EE and Spring Security for several years. The main limitation I found was the lack of documentation, but I&apos;ve heard it&apos;s improving rapidly.
&lt;/p&gt;
  &lt;p&gt;In the next couple weeks, I&apos;ll post a &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part3&quot;&gt;Part IV&lt;/a&gt; on implementing programmatic login using the APIs of Java EE 6, Spring Security and Apache Shiro. I&apos;ll be presenting this topic at &lt;a href=&quot;http://jazoon.com&quot;&gt;Jazoon&lt;/a&gt; as well as the long-form version (with hacking) at &lt;a href=&quot;http://uberconf.com/conference/denver/2011/07/home&quot;&gt;&#220;berConf&lt;/a&gt;. Hopefully I&apos;ll see you at one of those conferences.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Thanks to help from &lt;a href=&quot;http://leshazlewood.com&quot;&gt;Les Hazlewood&lt;/a&gt;, I&apos;ve figured out how to implement Remember Me with Apache Shiro. In the [urls] section of shiro.ini, the second url (shown below) says to Shiro &quot;In order to visit the /app/users URL, you must be connecting via SSL on port 8443 and you must also be authenticated.&quot;
&lt;/p&gt;
&lt;pre&gt;
/app/users = ssl[8443],authc
&lt;/pre&gt;
&lt;p&gt;
Remembered users are not authenticated because their identity hasn&apos;t been proven during the current session.  What I want Shiro to say is &quot;In order to visit the /app/users URL, you must be connecting via SSL on 8443 and you must also be a known user.  If you&apos;re not, you should login first.&quot; Where a &lt;em&gt;known user&lt;/em&gt; is someone who has a recognized identity and has either authenticated during the current session or is known via RememberMe from a previous session.  The &lt;a href=&quot;http://shiro.apache.org/authentication.html#Authentication-Rememberedvs.Authenticated&quot;&gt;documentation&lt;/a&gt; gives a good example with Amazon.com for why Shiro makes this distinction.  It allows more control (usually necessary), but you can relax the control as you see fit.
&lt;p&gt;
So, to relax my configuration a bit to match what I want (&lt;em&gt;known users&lt;/em&gt;), I updated shiro.ini&apos;s [urls] section to be as follows:&lt;/p&gt;
&lt;pre&gt;
/app/users = ssl[8443],user
&lt;/pre&gt;
&lt;p&gt;
The key is that the /app/users url is now protected with the more relaxed &lt;a href=&quot;http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/filter/authc/UserFilter.html&quot;&gt;&lt;em&gt;user&lt;/em&gt; filter&lt;/a&gt; instead of the &lt;em&gt;authc&lt;/em&gt; filter.  However, you would typically want an account profile page (or credit card information page, or similar) protected with the authc filter instead to guarantee proof of identity for those sensitive operations.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/appfuse_2_1_released</id>
        <title type="html">AppFuse 2.1 Released!</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/appfuse_2_1_released"/>
        <published>2011-04-04T09:38:05-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="myfaces" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javaee" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ibatis" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tapestry5" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse-light" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsf2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="hibernate" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jpa" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;a href=&quot;http://appfuse.org&quot;&gt;&lt;img src=&quot;//static.appfuse.org/images/appfuse-icon.gif&quot; class=&quot;picture&quot; style=&quot;border: 0&quot;&gt;&lt;/a&gt;
The AppFuse Team is pleased to announce the release of AppFuse 2.1. This release includes upgrades to all dependencies to bring them up-to-date with their latest releases. Most notable are JPA 2, JSF 2, Tapestry 5 and Spring 3. In addition, we&apos;ve migrated from XFire to CXF and enabled REST for web services. There&apos;s even a new &lt;b&gt;appfuse-ws&lt;/b&gt; archetype that leverages &lt;a href=&quot;http://enunciate.codehaus.org&quot;&gt;Enunciate&lt;/a&gt; to generate web service endpoints, documentation and downloadable clients. This release fixes many issues with archetypes, improving startup time and allowing jetty:run to be used for quick turnaround while developing. For more details on specific changes see the &lt;a href=&quot;http://appfuse.org/display/APF/Release+Notes+2.1.0&quot; title=&quot;Release Notes 2.1.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is AppFuse?&lt;/strong&gt;&lt;br/&gt;AppFuse is an open source project and application that uses open source frameworks to help you develop Web applications with Java quickly and efficiently. It was originally developed to eliminate the ramp-up time when building new web applications. At its core, AppFuse is a project skeleton, similar to the one that&apos;s created by your IDE when you click through a wizard to create a new web project. If you use &lt;a href=&quot;http://appfuse.org/display/APF/Using+JRebel+with+IntelliJ+IDEA&quot;&gt;JRebel with IntelliJ&lt;/a&gt;, you can achieve zero-turnaround in your project and develop features without restarting the server.
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Release Details&lt;/b&gt;&lt;br/&gt;
&lt;a href=&quot;http://static.appfuse.org/archetypes.html&quot;&gt;Archetypes&lt;/a&gt; now include all the source for the web modules so using jetty:run and your IDE will work much smoother now. The backend is still embedded in JARs, enabling you to choose with persistence framework (Hibernate, iBATIS or JPA) you&apos;d like to use. If you want to modify the source for that, &lt;a href=&quot;http://appfuse.org/display/APF/AppFuse+Core+Classes&quot;&gt;add the core classes to your project&lt;/a&gt; or run &quot;appfuse:full-source&quot;. &lt;/p&gt;

&lt;p&gt;AppFuse comes in a number of different flavors. It offers &quot;light&quot;, &quot;basic&quot; and &quot;modular&quot; and archetypes. Light archetypes use an embedded H2 database and contain a simple CRUD example. Light archetypes allow code generation and full-source features, but do not currently support Stripes or Wicket. Basic archetypes have web services using CXF, authentication from Spring Security and features including signup, login, file upload and CSS theming. Modular archetypes are similar to basic archetypes, except they have multiple modules which allows you to separate your services from your web project.&lt;/p&gt;

&lt;p&gt;AppFuse provides archetypes for JSF, Spring MVC, Struts 2 and Tapestry 5. The light archetypes are available for these frameworks, as well as for Spring MVC + FreeMarker, Stripes and Wicket. You can see demos of these archetypes at &lt;a href=&quot;http://demo.appfuse.org&quot;&gt;http://demo.appfuse.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For information on creating a new project, please see the &lt;a href=&quot;http://appfuse.org/display/APF/AppFuse+QuickStart&quot;&gt;QuickStart Guide&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you have questions about AppFuse, please read the &lt;a href=&quot;http://appfuse.org/display/APF/FAQ&quot;&gt;FAQ&lt;/a&gt; or join the &lt;a href=&quot;http://appfuse.org/display/APF/Mailing+Lists&quot;&gt;user mailing list&lt;/a&gt;. If you find any issues, please report them on the mailing list or &lt;a href=&quot;http://issues.appfuse.org/secure/CreateIssue%21default.jspa&quot;&gt;create an issue in JIRA&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to everyone for their help contributing patches, writing documentation and participating on the mailing lists.&lt;/p&gt;
&lt;p style=&quot;border-top: 1px dotted silver; padding-top: 5px; color: #666&quot;&gt;We greatly appreciate the help from &lt;a href=&quot;http://appfuse.org/display/APF/Sponsors&quot; title=&quot;Sponsors&quot; style=&quot;color: #666&quot;&gt;our sponsors&lt;/a&gt;, particularly &lt;a href=&quot;http://www.atlassian.com/c/NPOS/10160&quot; style=&quot;color: #666&quot;&gt;Atlassian&lt;/a&gt;, &lt;a href=&quot;http://contegix.com&quot; style=&quot;color: #666&quot;&gt;Contegix&lt;/a&gt; and &lt;a href=&quot;http://www.jetbrains.com&quot; style=&quot;color: #666&quot;&gt;JetBrains&lt;/a&gt;. Atlassian and Contegix are especially awesome: &lt;a href=&quot;http://raibledesigns.com/rd/entry/appfuse_now_powered_by_contegix&quot; style=&quot;color: #666&quot;&gt;Atlassian has donated licenses to all its products and Contegix has donated an entire server&lt;/a&gt; to the AppFuse project.&lt;/p&gt;&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/adding_search_to_appfuse</id>
        <title type="html">Adding Search to AppFuse with Compass</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/adding_search_to_appfuse"/>
        <published>2011-03-15T17:11:12-06:00</published>
        <updated>2012-11-08T14:19:27-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="search" scheme="http://roller.apache.org/ns/tags/" />
        <category term="compass" scheme="http://roller.apache.org/ns/tags/" />
        <category term="elasticsearch" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Over 5 years ago, I recognized that &lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt; needed to have a search feature and &lt;a href=&quot;http://issues.appfuse.org/browse/APF-267&quot;&gt;entered an issue in JIRA&lt;/a&gt;. Almost 4 years later, a &lt;a href=&quot;http://code.google.com/p/pagingappfuse/wiki/CompassSearching&quot;&gt;Compass Tutorial&lt;/a&gt; was created and shortly after &lt;a href=&quot;http://www.kimchy.org/&quot;&gt;Shay Banon&lt;/a&gt; (Compass Founder), sent in a &lt;a href=&quot;http://issues.appfuse.org/browse/APF-267?focusedCommentId=12620&amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-12620&quot;&gt;patch&lt;/a&gt;. From the message he sent me:&lt;/p&gt;
&lt;div class=&quot;quote&quot; style=&quot;margin-left: 0; margin-bottom: 10px&quot;&gt;
&lt;p&gt;A quick breakdown of enabling search:
&lt;/p&gt;
&lt;ol style=&quot;margin-bottom: 0&quot;&gt;
&lt;li&gt;Added Searchable annotations to the User and Address.&lt;/li&gt;
&lt;li&gt;Defined Compass bean, automatically scanning the model package for mapped searchable classes. It also automatically integrates with Spring transaction manager, and stores the index on the file system ([work dir]/target/test-index).&lt;/li&gt;
&lt;li&gt;Defined CompassTemplate (similar in concept to HibernateTemplate).&lt;/li&gt;
&lt;li&gt;Defined CompassSearchHelper. Really helps to perform search since it does pagination and so on.&lt;/li&gt;
&lt;li&gt;Defined CompassGps, basically it allows for index operation allowing to completely reindex the data from the database. JPA and Hiberante also automatically mirror changes done through their API to the index. iBatis uses AOP. &lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;p&gt;Fast forward 2 years and I finally found the time/desire to put a UI on the backend Compass implementation that Shay provided. Yes, I realize that &lt;a href=&quot;http://www.kimchy.org/the_future_of_compass/&quot;&gt;Compass is being replaced by ElasticSearch&lt;/a&gt;. I may change to use ElasticSearch in the future; now that the search feature exists, I hope to see it evolve and improve.
&lt;/p&gt;
&lt;p&gt;Since Shay&apos;s patch integrated the necessary Spring beans for indexing and searching, the only thing I had to do was to implement the UI. Rather than having an &quot;all objects&quot; results page, I elected to implement it so you could search on an entity&apos;s list screen. I started with Spring MVC and added a search() method to the UserController:
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@RequestMapping(method = RequestMethod.GET)
public ModelAndView handleRequest(@RequestParam(required = false, value = &quot;q&quot;) String query) throws Exception {
    if (query != null &amp;&amp; !&quot;&quot;.equals(query.trim())) {
        return new ModelAndView(&quot;admin/userList&quot;, Constants.USER_LIST, search(query));
    } else {
        return new ModelAndView(&quot;admin/userList&quot;, Constants.USER_LIST, mgr.getUsers());
    }
}

public List&amp;lt;User&amp;gt; search(String query) {
    List&amp;lt;User&amp;gt; results = new ArrayList&amp;lt;User&amp;gt;();
    CompassDetachedHits hits = compassTemplate.findWithDetach(query);
    log.debug(&quot;No. of results for &apos;&quot; + query + &quot;&apos;: &quot; + hits.length());
    for (int i = 0; i &amp;lt; hits.length(); i++) {
        results.add((User) hits.data(i));
    }
    return results;
}
&lt;/pre&gt;
&lt;p&gt;At first, I used &lt;em&gt;compassTemplate.find()&lt;/em&gt;, but got an error because I wasn&apos;t using an OpenSessionInViewFilter. I decided to go with findWithDetach() and added the following search form to the top of the userList.jsp page:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
&amp;lt;div id=&quot;search&quot;&amp;gt;
&amp;lt;form method=&quot;get&quot; action=&quot;${ctx}/admin/users&quot; id=&quot;searchForm&quot;&amp;gt;
    &amp;lt;input type=&quot;text&quot; size=&quot;20&quot; name=&quot;q&quot; id=&quot;query&quot; value=&quot;${param.q}&quot;
           placeholder=&quot;Enter search terms&quot;/&amp;gt;
    &amp;lt;input type=&quot;submit&quot; value=&quot;&amp;lt;fmt:message key=&quot;button.search&quot;/&amp;gt;&quot;/&amp;gt;
&amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p style=&quot;color: #666; margin-left: 20px&quot;&gt;&lt;em&gt;NOTE: I tried using HTML5&apos;s &amp;lt;input type=&quot;search&quot;&amp;gt;, but found &lt;a href=&quot;http://lists.canoo.com/pipermail/webtest/2011q1/013697.html&quot; style=&quot;color: #666&quot;&gt;Canoo WebTest doesn&apos;t support it.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Next, I wrote a unit test to verify everything worked as expected. I found I had to call compassGps.index() as part of my test to make sure my index was created and up-to-date.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class UserControllerTest extends BaseControllerTestCase {
    @Autowired
    private CompassGps compassGps;
    @Autowired
    private UserController controller;

    public void testSearch() throws Exception {
        compassGps.index();
        ModelAndView mav = controller.handleRequest(&quot;admin&quot;);
        Map m = mav.getModel();
        List results = (List) m.get(Constants.USER_LIST);
        assertNotNull(results);
        assertTrue(results.size() &amp;gt;= 1);
        assertEquals(&quot;admin/userList&quot;, mav.getViewName());
    }
}
&lt;/pre&gt;
&lt;p&gt;After getting this working, I started integrating similar code into AppFuse&apos;s other web framework modules (Struts, JSF and Tapestry). When I was finished, they all looked pretty similar from a UI perspective.
&lt;/p&gt;
&lt;p&gt;&lt;strong style=&quot;color: #666&quot;&gt;Struts:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;div id=&quot;search&quot;&amp;gt;
&amp;lt;form method=&quot;get&quot; action=&quot;${ctx}/admin/users&quot; id=&quot;searchForm&quot;&amp;gt;
    &amp;lt;input type=&quot;text&quot; size=&quot;20&quot; name=&quot;q&quot; id=&quot;query&quot; value=&quot;${param.q}&quot;
           placeholder=&quot;Enter search terms...&quot;/&amp;gt;
    &amp;lt;input type=&quot;submit&quot; value=&quot;&amp;lt;fmt:message key=&quot;button.search&quot;/&amp;gt;&quot;/&amp;gt;
&amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;strong style=&quot;color: #666&quot;&gt;JSF:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;div id=&quot;search&quot;&amp;gt;
&amp;lt;h:form id=&quot;searchForm&quot;&amp;gt;
    &amp;lt;h:inputText id=&quot;q&quot; name=&quot;q&quot; size=&quot;20&quot; value=&quot;#{userList.query}&quot;/&amp;gt;
    &amp;lt;h:commandButton value=&quot;#{text&amp;#91;&apos;button.search&apos;&amp;#93;}&quot; action=&quot;#{userList.search}&quot;/&amp;gt;
&amp;lt;/h:form&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;strong style=&quot;color: #666&quot;&gt;Tapestry:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;div id=&quot;search&quot;&amp;gt;
&amp;lt;t:form method=&quot;get&quot; t:id=&quot;searchForm&quot;&amp;gt;
    &amp;lt;t:textfield size=&quot;20&quot; name=&quot;q&quot; t:id=&quot;q&quot;/&amp;gt;
    &amp;lt;input t:type=&quot;submit&quot; value=&quot;${message:button.search}&quot;/&amp;gt;
&amp;lt;/t:form&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;One frustrating thing I found was that &lt;a href=&quot;http://tapestry.1045711.n5.nabble.com/Is-there-any-way-to-render-the-quot-get-quot-method-of-form-td2643651.html&quot;&gt;Tapestry doesn&apos;t support method=&quot;get&quot;&lt;/a&gt; and AFAICT, neither does JSF 2. With JSF, I had to make my UserList bean session-scoped or the query parameter would be null when it listed the results. Tapestry took me the longest to implement, mainly because I had issues figuring out how it&apos;s easy-to-understand-once-you-know onSubmit() handlers worked and I had the proper @Property and @Persist annotations on my &quot;q&quot; property. &lt;a href=&quot;http://www.crazymcphee.net/x/2009/08/26/tapestry-5-web-framework/&quot;&gt;This tutorial&lt;/a&gt; was the greatest help for me. Of course, now that it&apos;s all finished, the code looks pretty intuitive.&lt;/p&gt;
&lt;p&gt;Feeling proud of myself for getting this working, I started integrating this feature into AppFuse&apos;s code generation and found I had to add quite a bit of code to the generated list pages/controllers. 
&lt;/p&gt;
&lt;p&gt;
So I went on a bike ride...&lt;/p&gt;
&lt;p&gt;While riding, I thought of a much better solution and added the following search method to AppFuse&apos;s GenericManagerImpl.java. In the code I added to pages/controllers previously, I&apos;d already refactored to use CompassSearchHelper and I continued to do so in the service layer implementation.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Autowired
private CompassSearchHelper compass;

public List&amp;lt;T&amp;gt; search(String q, Class clazz) {
    if (q == null || &quot;&quot;.equals(q.trim())) {
        return getAll();
    }

    List&amp;lt;T&amp;gt; results = new ArrayList&amp;lt;T&amp;gt;();

    CompassSearchCommand command = new CompassSearchCommand(q);
    CompassSearchResults compassResults = compass.search(command);
    CompassHit&amp;#91;&amp;#93; hits = compassResults.getHits();

    if (log.isDebugEnabled() &amp;amp;&amp;amp; clazz != null) {
        log.debug(&quot;Filtering by type: &quot; + clazz.getName());
    }

    for (CompassHit hit : hits) {
        if (clazz != null) {
            if (hit.data().getClass().equals(clazz)) {
                results.add((T) hit.data());
            }
        } else {
            results.add((T) hit.data());
        }
    }

    if (log.isDebugEnabled()) {
        log.debug(&quot;Number of results for &apos;&quot; + q + &quot;&apos;: &quot; + results.size());
    }

    return results;
}
&lt;/pre&gt;
&lt;p&gt;This greatly simplified my page/controller logic because now all I had to do was call manager.search(query, User.class) instead of doing the Compass login in the controller. Of course, it&apos;d be great if I didn&apos;t have to pass in the Class to filter by object, but that&apos;s the &lt;a href=&quot;http://javanotepad.blogspot.com/2007/09/instanceof-doesnt-work-with-generics.html&quot;&gt;nature of generics and type erasure&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Other things I learned along the way:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To index on startup, I added compassGps.index() to the StartupListener.&lt;/a&gt;.
&lt;li&gt;In unit tests that leveraged transactions around methods, I had to call compassGps.index() before any transactions started.&lt;/li&gt;
&lt;li&gt;To scan multiple packages for searchable classes, I had to add a &lt;a href=&quot;http://forum.compass-project.org/thread.jspa?threadID=216821&amp;tstart=0&quot;&gt;LocalCompassBeanPostProcessor&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But more than anything, I was reminded it always helps to take a bike ride when you don&apos;t like the design of your code. &lt;img src=&quot;https://raibledesigns.com/images/smileys/wink.gif&quot; class=&quot;smiley&quot; alt=&quot;;-)&quot; title=&quot;;-)&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;
This feature and many more will be in AppFuse 2.1, which I hope to &lt;a href=&quot;http://issues.appfuse.org/secure/IssueNavigator.jspa?mode=hide&amp;requestId=10160&quot; title=&quot;Open Issues for 2.1&quot;&gt;finish by the end of the month&lt;/a&gt;. In the meantime, please feel free to try out the &lt;a href=&quot;http://appfuse.org/display/APF/AppFuse+QuickStart&quot;&gt;latest snapshot&lt;/a&gt;.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/jsr_303_and_web_framework</id>
        <title type="html">JSR 303 and JVM Web Framework Support</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/jsr_303_and_web_framework"/>
        <published>2011-03-08T11:33:24-07:00</published>
        <updated>2012-11-08T14:30:37-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tapestry" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsr303" scheme="http://roller.apache.org/ns/tags/" />
        <category term="vaadin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="lift" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Emmanuel Bernard recently sent an email to the JSR 303 Experts Group about the next revision of the Bean Validation JSR (303). Rather than sending the proposed changes privately, he &lt;a href=&quot;http://in.relation.to/Bloggers/JSRBeanValidation11WhatToPutIn&quot;&gt;blogged about them&lt;/a&gt;. I left a comment with what I&apos;d like to see:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
+1 for Client-side validation. I&apos;d love to see an API that web frameworks can hook into to add &quot;required&quot; to their tags for HTML5. Or some service that can be registered so the client can make Ajax requests to an API to see if an object is valid.
&lt;/p&gt;
&lt;p&gt;Emmanuel replied that most of the necessary API already exists for this, but frameworks have been slow to adopt it.
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
Hi Matt,
&lt;br/&gt;&lt;br/&gt;
The sad thing is that the API is present on the Bean Validation side but presentation frameworks are slow to adopt it and use it :(
&lt;br/&gt;&lt;br/&gt;
RichFaces 4 now has support for it but I wished more presentation frameworks had worked on the integration. If you can convince a few people or have access to a few people, feel free to send them by me :)
&lt;br/&gt;&lt;br/&gt;
The integration API is &lt;a href=&quot;http://people.redhat.com/~ebernard/validation/#constraintmetadata&quot;&gt;described here&lt;/a&gt;. Let me know if you think some parts are missing or should be improved. We should definitely do some more buzz around it.
&lt;/p&gt;
&lt;p&gt;In the interest of generating more buzz around it, I decided to do some research and see what JVM Frameworks support JSR 303. Here&apos;s what I&apos;ve come up with so far (in no particular order):
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://relation.to/Bloggers/RichFaces4ClientSideValidation&quot;&gt;RichFaces 4 - Client Side Validation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://tapestry.apache.org/bean-validation.html&quot;&gt;Tapestry&apos;s JSR 303 - Bean Validation Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.zenika.com/index.php?post/2010/02/24/Wicket-JSR-303-Validators&quot;&gt;Wicket JSR-303 Validators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://static.springsource.org/spring/docs/3.0.x/reference/validation.html#validation-mvc-jsr303&quot;&gt;Configuring a JSR-303 Validator for use by Spring MVC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://code.google.com/p/gwt-validation/&quot;&gt;GWT Validation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://dev.vaadin.com/ticket/3156&quot;&gt;Vaadin Bean Validation JSR 303 support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://wstrange.wordpress.com/2009/12/07/inline-field-validation-in-scalalift-using-jpa-and-jsr-303/&quot;&gt;Inline field validation in Scala/Lift using JPA and JSR 303&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Struts 2 has an &lt;a href=&quot;https://issues.apache.org/jira/browse/WW-2563&quot;&gt;open issue&lt;/a&gt;, but doesn&apos;t seem to support JSR 303. Since I did a quick-n-dirty google search for most of these, I&apos;m not sure if they support client-side JavaScript or HTML5&apos;s required. If you know of other JVM-based web frameworks that support JSR 303, please let me know in the comments. </content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/fixing_xss_in_jsp_2</id>
        <title type="html">Fixing XSS in JSP 2</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/fixing_xss_in_jsp_2"/>
        <published>2011-02-28T14:08:46-07:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsp" scheme="http://roller.apache.org/ns/tags/" />
        <category term="xss" scheme="http://roller.apache.org/ns/tags/" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appsec" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Way back in 2007, I wrote about &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_frameworks_and_xss&quot;&gt;Java Web Frameworks and XSS&lt;/a&gt;. My main point was that JSP EL &lt;a href=&quot;http://www.sleberknight.com/blog/sleberkn/entry/20060721&quot;&gt;doesn&apos;t bother to handle XSS&lt;/a&gt;. &lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
Of course, the whole problem with JSP EL could be solved if Tomcat (and other containers) would allow a flag to turn on XML escaping by default. IMO, it&apos;s badly needed to make JSP-based webapps safe from XSS. &lt;/p&gt;
&lt;p&gt;A couple months later, I &lt;a href=&quot;http://raibledesigns.com/rd/entry/proposed_tomcat_enhancement_add_flag&quot;&gt;proposed a Tomcat enhancement to escape JSP&apos;s EL by default&lt;/a&gt;. I also entered an &lt;a href=&quot;http://issues.apache.org/bugzilla/show_bug.cgi?id=43497&quot;&gt;enhancement request&lt;/a&gt; for this feature and attached a patch. That issue has remained open and unfixed for 3 and 1/2 years. 
&lt;/p&gt;
&lt;p&gt;Yesterday, Chin Huang posted a handy-dandy &lt;a href=&quot;http://pukkaone.github.com/2011/01/03/jsp-cross-site-scripting-elresolver.html&quot;&gt;ELResolver that XML-escapes EL values&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I tried Chin&apos;s resolver in AppFuse today and it works as well as advertised. To do this, I copied his &lt;a href=&quot;https://github.com/pukkaone/webappenhance/tree/master/src/com/github/pukkaone/jsp&quot;&gt;EscapeXML*.java files&lt;/a&gt; into my project, changed the JSP API&apos;s Maven coordinates from javax.servlet:jsp-api:2.0 to javax.servlet.jsp:jsp-api:2.1 and added the listener to web.xml. 
&lt;/p&gt;
&lt;p&gt;
With Struts 2 and Spring MVC, I was previously able to have ${param.xss} and pass in ?xss=&amp;lt;script&amp;gt;alert(&apos;gotcha&apos;)&amp;lt;/script&gt; and it would show a JavaScript alert. After using Chin&apos;s ELResolver, it prints the string on the page instead of displaying an alert.&lt;/p&gt;
&lt;p&gt;Thanks to Chin Huang for this patch! If you&apos;re using JSP, I highly recommend you add this to your projects as well.
    
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/implementing_ajax_authentication_using_jquery</id>
        <title type="html">Implementing Ajax Authentication using jQuery, Spring Security and HTTPS</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/implementing_ajax_authentication_using_jquery"/>
        <published>2011-02-23T16:55:55-07:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="springsecurity" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jquery" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="owasp" scheme="http://roller.apache.org/ns/tags/" />
        <category term="authentication" scheme="http://roller.apache.org/ns/tags/" />
        <category term="overstock.com" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ajax" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse-light" scheme="http://roller.apache.org/ns/tags/" />
        <category term="https" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">I&apos;ve always had a keen interest in implementing security in webapps. I implemented container-managed authentication (CMA) in &lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt; in 2002, watched &lt;a href=&quot;http://raibledesigns.com/rd/entry/container_managed_authentication_enhancements_in&quot;&gt;Tomcat improve it&apos;s implementation in 2003&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/appfuse_refactorings_part_iii_remember&quot;&gt;implemented Remember Me with CMA&lt;/a&gt; in 2004. In 2005, I &lt;a href=&quot;http://raibledesigns.com/rd/entry/ann_appfuse_1_8_released&quot;&gt;switched from CMA to Acegi Security&lt;/a&gt; (now &lt;a href=&quot;http://static.springsource.org/spring-security/site/&quot;&gt;Spring Security&lt;/a&gt;) and never looked back. I&apos;ve been very happy with Spring Security over the years, but also hope to learn more about &lt;a href=&quot;http://shiro.apache.org/&quot;&gt;Apache Shiro&lt;/a&gt; and &lt;a href=&quot;http://www.quora.com/Is-OAuth-the-best-way-to-implement-security-for-a-JavaScript-API&quot;&gt;implementing OAuth to protect JavaScript APIs&lt;/a&gt; in the near future.
&lt;/p&gt;
&lt;p&gt;I was recently re-inspired to learn more about security when working on a new feature at &lt;a href=&quot;http://www.overstock.com&quot;&gt;Overstock.com&lt;/a&gt;. The feature hasn&apos;t been released yet, but basically boils down to allowing users to login without leaving a page. For example, if they want to leave a review on a product, they would click a link, be prompted to login, enter their credentials, then continue to leave their review. The login prompt and subsequent review would likely be implemented using a lightbox. While lightboxes are often seen in webapps these days because they look good, it&apos;s also possible &lt;a href=&quot;http://uxexchange.com/questions/1877/the-usability-of-lightbox-uis&quot;&gt;Lightbox UIs provide a poor user experience&lt;/a&gt;. User experience aside, I think it&apos;s interesting to see what&apos;s required to implement such a feature.
&lt;/p&gt;
&lt;p&gt;To demonstrate how we did it, I whipped up an example using AppFuse Light, jQuery and Spring Security. The source is available in my &lt;a href=&quot;https://github.com/mraible/ajax-login&quot;&gt;ajax-login&lt;/a&gt; project on GitHub. To begin, I wanted to accomplish a number of things to replicate the Overstock environment:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Force HTTPS for authentication.&lt;/li&gt;
&lt;li&gt;Allow testing HTTPS without installing a certificate locally.&lt;/li&gt;
&lt;li&gt;Implement a RESTful LoginService that allows users to login.&lt;/li&gt;
&lt;li&gt;Implement login with Ajax, with the request coming from an insecure page.&lt;/li&gt;
&lt;/ol&gt;
&lt;p id=&quot;force-https&quot;&gt;&lt;strong&gt;Forcing HTTPS with Spring Security&lt;/strong&gt;&lt;br/&gt;
The first feature was fairly easy to implement thanks to Spring Security. Its configuration supports a &lt;a href=&quot;http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html#ns-requires-channel&quot;&gt;requires-channel&lt;/a&gt; attribute that can be used for this. I used this to force HTTPS on the &quot;users&quot; page and it subsequently causes the login to be secure.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;intercept-url pattern=&quot;/app/users&quot; access=&quot;ROLE_ADMIN&quot; requires-channel=&quot;https&quot;/&amp;gt;
&lt;/pre&gt;
&lt;p id=&quot;testing-https&quot;&gt;&lt;strong&gt;Testing HTTPS without adding a certificate locally&lt;/strong&gt;&lt;br/&gt;
After making the above change in &lt;a href=&quot;https://github.com/mraible/ajax-login/blob/master/src/main/webapp/WEB-INF/security.xml&quot;&gt;security.xml&lt;/a&gt;, I had to modify my &lt;a href=&quot;https://github.com/mraible/ajax-login/blob/master/src/test/java/org/appfuse/examples/web/UserWebTest.java&quot;&gt;jWebUnit test&lt;/a&gt; to work with SSL. In reality, I didn&apos;t have to modify the test, I just had to modify the configuration that ran the test. In my &lt;a href=&quot;http://raibledesigns.com/rd/entry/integration_testing_with_http_https&quot;&gt;last post&lt;/a&gt;, I wrote about &lt;a href=&quot;http://blogs.sun.com/gc/entry/unable_to_find_valid_certification&quot;&gt;adding my &apos;untrusted&apos; cert to my JVM keystore&lt;/a&gt;. For some reason, this works for HttpClient, but not for jWebUnit/HtmlUnit. The good news is I figured out an easier solution - adding the trustStore and trustStore password as system properties to the maven-failsafe-plugin configuration.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;artifactId&amp;gt;maven-failsafe-plugin&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.7.2&amp;lt;/version&amp;gt;
&amp;lt;configuration&amp;gt;
    &amp;lt;includes&amp;gt;
        &amp;lt;include&amp;gt;**/*WebTest.java&amp;lt;/include&amp;gt;
    &amp;lt;/includes&amp;gt;
    &amp;lt;systemPropertyVariables&amp;gt;
      &amp;lt;javax.net.ssl.trustStore&amp;gt;${project.build.directory}/ssl.keystore&amp;lt;/javax.net.ssl.trustStore&amp;gt;
      &amp;lt;javax.net.ssl.trustStorePassword&amp;gt;appfuse&amp;lt;/javax.net.ssl.trustStorePassword&amp;gt;
    &amp;lt;/systemPropertyVariables&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The disadvantage to doing things this way is you&apos;ll have to pass these in as arguments when running unit tests in your IDE.&lt;/p&gt;
&lt;p id=&quot;login-service&quot;&gt;&lt;strong&gt;Implementing a LoginService&lt;/strong&gt;&lt;br/&gt;
Next, I set about implementing a LoginService as a Spring MVC Controller that returns JSON thanks to the &lt;a href=&quot;http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/&quot;&gt;@ResponseBody annotation and Jackson&lt;/a&gt;.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package org.appfuse.examples.web;

import org.appfuse.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(&quot;/api/login.json&quot;)
public class LoginService {

  @Autowired
  @Qualifier(&quot;authenticationManager&quot;)
  AuthenticationManager authenticationManager;

  @RequestMapping(method = RequestMethod.GET)
  @ResponseBody
  public LoginStatus getStatus() {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth != null &amp;&amp; !auth.getName().equals(&quot;anonymousUser&quot;) &amp;&amp; auth.isAuthenticated()) {
      return new LoginStatus(true, auth.getName());
    } else {
      return new LoginStatus(false, null);
    }
  }

  @RequestMapping(method = RequestMethod.POST)
  @ResponseBody
  public LoginStatus login(@RequestParam(&quot;j_username&quot;) String username,
                           @RequestParam(&quot;j_password&quot;) String password) {

    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
    User details = new User(username);
    token.setDetails(details);

    try {
      Authentication auth = authenticationManager.authenticate(token);
      SecurityContextHolder.getContext().setAuthentication(auth);
      return new LoginStatus(auth.isAuthenticated(), auth.getName());
    } catch (BadCredentialsException e) {
      return new LoginStatus(false, null);
    }
  }

  public class LoginStatus {

    private final boolean loggedIn;
    private final String username;

    public LoginStatus(boolean loggedIn, String username) {
      this.loggedIn = loggedIn;
      this.username = username;
    }

    public boolean isLoggedIn() {
      return loggedIn;
    }

    public String getUsername() {
      return username;
    }
  }
}
&lt;/pre&gt;
&lt;p&gt;To verify this class worked as expected, I wrote a unit test using JUnit and &lt;a href=&quot;http://mockito.org/&quot;&gt;Mockito&lt;/a&gt;. I used Mockito because Overstock is transitioning to it from EasyMock and I&apos;ve found it very simple to use.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package org.appfuse.examples.web;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Matchers;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

public class LoginServiceTest {

  LoginService loginService;
  AuthenticationManager authenticationManager;

  @Before
  public void before() {
    loginService = new LoginService();
    authenticationManager = mock(AuthenticationManager.class);
    loginService.authenticationManager = authenticationManager;
  }

  @After
  public void after() {
    SecurityContextHolder.clearContext();
  }

  @Test
  public void testLoginStatusSuccess() {
    Authentication auth = new TestingAuthenticationToken(&quot;foo&quot;, &quot;bar&quot;);
    auth.setAuthenticated(true);
    SecurityContext context = new SecurityContextImpl();
    context.setAuthentication(auth);
    SecurityContextHolder.setContext(context);

    LoginService.LoginStatus status = loginService.getStatus();
    assertTrue(status.isLoggedIn());
  }

  @Test
  public void testLoginStatusFailure() {
    LoginService.LoginStatus status = loginService.getStatus();
    assertFalse(status.isLoggedIn());
  }

  @Test
  public void testGoodLogin() {
    Authentication auth = new TestingAuthenticationToken(&quot;foo&quot;, &quot;bar&quot;);
    auth.setAuthenticated(true);
    when(authenticationManager.authenticate(Matchers.&amp;lt;Authentication&amp;gt;anyObject())).thenReturn(auth);
    LoginService.LoginStatus status = loginService.login(&quot;foo&quot;, &quot;bar&quot;);
    assertTrue(status.isLoggedIn());
    assertEquals(&quot;foo&quot;, status.getUsername());
  }

  @Test
  public void testBadLogin() {
    Authentication auth = new TestingAuthenticationToken(&quot;foo&quot;, &quot;bar&quot;);
    auth.setAuthenticated(false);
    when(authenticationManager.authenticate(Matchers.&lt;Authentication&gt;anyObject()))
        .thenThrow(new BadCredentialsException(&quot;Bad Credentials&quot;));
    LoginService.LoginStatus status = loginService.login(&quot;foo&quot;, &quot;bar&quot;);
    assertFalse(status.isLoggedIn());
    assertEquals(null, status.getUsername());
  }
}
&lt;/pre&gt;
&lt;p id=&quot;ajax-login&quot;&gt;&lt;strong&gt;Implement login with Ajax&lt;/strong&gt;&lt;br/&gt;
The last feature was the hardest to implement and still isn&apos;t fully working as I&apos;d hoped. I used jQuery and jQuery UI to implement a dialog that opens the login page on the same page rather than redirecting to the login page. The &quot;#demo&quot; locator refers to a button in the page.
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
Passing in the &quot;ajax=true&quot; parameter disables SiteMesh decoration on the login page, something that&apos;s described in my &lt;a href=&quot;http://raibledesigns.com/rd/entry/ajaxified_body&quot;&gt;Ajaxified Body&lt;/a&gt; article.
&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
var dialog = $(&apos;&amp;lt;div&gt;&amp;lt;/div&gt;&apos;);

$(document).ready(function() {
    $.get(&apos;/login?ajax=true&apos;, function(data) {
        dialog.html(data);
        dialog.dialog({
            autoOpen: false,
	       title: &apos;Authentication Required&apos;
        });
    });

    $(&apos;#demo&apos;).click(function() {
      dialog.dialog(&apos;open&apos;);
      // prevent the default action, e.g., following a link
      return false;
    });
});
&lt;/pre&gt;
&lt;p class=&quot;quote&quot;&gt;
Instead of adding a click handler to a specific id, it&apos;s probably better to use a CSS class that indicates authentication is required for a link, or -- even better -- use Ajax to see if the link is secured.
&lt;/p&gt;
&lt;p&gt;The login page then has the following JavaScript to add a click handler to the &quot;login&quot; button that submits the request securely to the LoginService.
&lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
var getHost = function() {
    var port = (window.location.port == &quot;8080&quot;) ? &quot;:8443&quot; : &quot;&quot;;
    return ((secure) ? &apos;https://&apos; : &apos;http://&apos;) + window.location.hostname + port;
};

var loginFailed = function(data, status) {
    $(&quot;.error&quot;).remove();
    $(&apos;#username-label&apos;).before(&apos;&amp;lt;div class=&quot;error&quot;&gt;Login failed, please try again.&amp;lt;/div&gt;&apos;);
};

$(&quot;#login&quot;).live(&apos;click&apos;, function(e) {
    e.preventDefault();
    $.ajax({url: getHost() + &quot;/api/login.json&quot;,
        type: &quot;POST&quot;,
        data: $(&quot;#loginForm&quot;).serialize(),
        success: function(data, status) {
            if (data.loggedIn) {
                // success
                dialog.dialog(&apos;close&apos;);
                location.href= getHost() + &apos;/users&apos;;
            } else {
                loginFailed(data);
            }
        },
        error: loginFailed
    });
});
&lt;/pre&gt;
&lt;p&gt;The biggest secret to making this all work (the HTTP -&gt; HTTPS communication, which is considered cross-domain), is the &lt;a href=&quot;http://www.sitepen.com/blog/2008/07/22/windowname-transport/&quot;&gt;window.name Transport&lt;/a&gt; and the &lt;a href=&quot;http://friedcellcollective.net/outbreak/jsjquerywindownameplugin/&quot;&gt;jQuery plugin&lt;/a&gt; that implements it. To make this plugin work with Firefox 3.6, I had to implement a Filter that adds Access-Control headers. &lt;a href=&quot;http://stackoverflow.com/questions/1099787/jquery-ajax-post-sending-options-as-request-method-in-firefox&quot;&gt;A question on Stackoverflow&lt;/a&gt; helped me figure this out.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class OptionsHeadersFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);
        response.setHeader(&quot;Access-Control-Allow-Methods&quot;, &quot;GET,POST&quot;);
        response.setHeader(&quot;Access-Control-Max-Age&quot;, &quot;360&quot;);
        response.setHeader(&quot;Access-Control-Allow-Headers&quot;, &quot;x-requested-with&quot;);

        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {
    }

    public void destroy() {
    }
}
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Issues&lt;/strong&gt;&lt;br/&gt;
I encountered a number of issues when implementing this in the &lt;a href=&quot;https://github.com/mraible/ajax-login&quot;&gt;ajax-login&lt;/a&gt; project. 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you try to run this with ports (e.g. 8080 and 8443) in your URLs, you&apos;ll get a 501 (Not Implemented) response. Removing the ports by fronting with &lt;a href=&quot;http://raibledesigns.com/rd/entry/apache_2_on_os_x&quot;&gt;Apache and mod_proxy&lt;/a&gt; solves this problem.
&lt;li&gt;If you haven&apos;t accepted the certificate in your browser, the Ajax request will fail. In the example, I solved this by clicking on the &quot;Users&quot; tab to make a secure request, then going back to the homepage to try and login.&lt;/li&gt;
&lt;li&gt;The jQuery window.name version 0.9.1 doesn&apos;t work with jQuery 1.5.0. The error is &quot;$.httpSuccess function not found.&quot;&lt;/li&gt;
&lt;li&gt;Finally, even though I was able to authenticate successfully, I was &lt;a href=&quot;http://stackoverflow.com/questions/5087137/is-it-possible-to-programmatically-authenticate-with-spring-security-and-make-it&quot;&gt;unable to make the authentication persist&lt;/a&gt;.  I tried adding the following to persist the updated SecurityContext to the session, but it doesn&apos;t work. I expect the solution is to create a secure JSESSIONID cookie somehow.
&lt;pre class=&quot;brush: java&quot;&gt;
@Autowired
SecurityContextRepository repository;

@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public LoginStatus login(@RequestParam(&quot;j_username&quot;) String username,
                         @RequestParam(&quot;j_password&quot;) String password,
                         HttpServletRequest request, HttpServletResponse response) {

    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
    ...

    try {
        Authentication auth = authenticationManager.authenticate(token);
        SecurityContextHolder.getContext().setAuthentication(auth);
        // save the updated context to the session
        repository.saveContext(SecurityContextHolder.getContext(), request, response);
        return new LoginStatus(auth.isAuthenticated(), auth.getName());
    } catch (BadCredentialsException e) {
        return new LoginStatus(false, null);
    }
}
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br/&gt;
This article has shown you how to force HTTPS for login, how to do integration testing with a self-generated certificate, how to implement a LoginService with Spring MVC and Spring Security, as well as how to use jQuery to talk to a service cross-domain with the window.name Transport. While I don&apos;t have everything working as much as I&apos;d like, I hope this helps you implement a similar feature in your applications. 
&lt;/p&gt;
&lt;p&gt;
One thing to be aware of is with lightbox/dialog logins and HTTP -&gt; HTTPS is that users won&apos;t see a secure icon in their address bar. If your app has sensitive data, you might want to force https for your entire app. OWASP&apos;s &lt;a href=&quot;http://www.owasp.org/index.php/SSL_Best_Practices#Secure_Login_Pages&quot;&gt;Secure Login Pages&lt;/a&gt; has a lot of good tips in this area.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I&apos;ve posted a &lt;a href=&quot;http://demo.raibledesigns.com/ajax-login/&quot;&gt;demo of the ajax-login webapp&lt;/a&gt;. Thanks to &lt;a href=&quot;http://www.contegix.com/&quot;&gt;Contegix&lt;/a&gt; for hosting the demo and helping obtain/install an SSL certificate so quickly.
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/implementing_extensionless_urls_with_tapestry</id>
        <title type="html">Implementing Extensionless URLs with Tapestry, Spring MVC, Struts 2 and JSF</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/implementing_extensionless_urls_with_tapestry"/>
        <published>2011-02-10T16:53:27-07:00</published>
        <updated>2011-02-11T00:04:52-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="tapestry5" scheme="http://roller.apache.org/ns/tags/" />
        <category term="extensionlessurls" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">For the past couple of weeks, I&apos;ve spent several evening hours implementing extensionless URLs in &lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt;. I&apos;ve been wanting to do this ever since I &lt;a href=&quot;http://raibledesigns.com/rd/entry/extensionless_urls_in_java_web&quot;&gt;wrote about how to do it&lt;/a&gt; a few years ago. This article details my experience and will hopefully help others implement this feature in their webapps.
&lt;/p&gt;
&lt;p&gt;First of all, I used the &lt;a href=&quot;http://www.tuckey.org/urlrewrite/&quot;&gt;UrlRewriteFilter&lt;/a&gt;, one of my favorite Java open source projects. Then I followed a pattern I found in Spring&apos;s &quot;mvc-basic&quot; sample app from &lt;a href=&quot;http://blog.springsource.com/2009/12/21/mvc-simplifications-in-spring-3-0/&quot;&gt;MVC Simplifications in Spring 3.0&lt;/a&gt;. The app has since changed (because SpringSource integrated UrlRewriteFilter-type functionality in Spring MVC), but the pattern was basically path-matching instead of extension-mapping. That is, the &quot;dispatcher&quot; for the web framework was mapped to /app/* instead of *.html. 
&lt;/p&gt;
&lt;p&gt;
Prior to the move to extensionless URLs, AppFuse used *.html for its mapping and this seemed to cause users problems when they wanted to serve up static HTML files. To begin with, I removed all extensions from URLs in tests (&lt;a href=&quot;http://webtest.canoo.com&quot;&gt;Canoo WebTest&lt;/a&gt; is used for testing the UI). I also did this for any links in the view pages and redirects in the Java code. This provided a decent foundation to verify my changes worked. Below are details about each framework I did this for, starting with the one that was easiest and moving to hardest.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tapestry 5&lt;/strong&gt;&lt;br/&gt;
Tapestry was by far the easiest to integrate extensionless URLs into. This is because it&apos;s a native feature of the framework and was already integrated as part of &lt;a href=&quot;http://issues.appfuse.org/browse/APF-1116&quot;&gt;Serge Eby&apos;s Tapestry 5 implementation&lt;/a&gt;. In the end, the only things I had to do where 1) add a couple entries for CXF (mapped to /services/*) and DWR (/dwr/*) to my urlrewrite.xml and 2) change the UrlRewriteFilter so it was only mapped to REQUEST instead of both REQUEST and FORWARD. Below are the mappings I added for CXF and DWR.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;urlrewrite default-match-type=&quot;wildcard&quot;&amp;gt;
    ...
    &amp;lt;rule&amp;gt;
        &amp;lt;from&amp;gt;/dwr/**&amp;lt;/from&amp;gt;
        &amp;lt;to&amp;gt;/dwr/$1&amp;lt;/to&amp;gt;
    &amp;lt;/rule&amp;gt;
    &amp;lt;rule&amp;gt;
        &amp;lt;from&amp;gt;/services/**&amp;lt;/from&amp;gt;
        &amp;lt;to&amp;gt;/services/$1&amp;lt;/to&amp;gt;
    &amp;lt;/rule&amp;gt;
&amp;lt;/urlrewrite&amp;gt;
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spring MVC&lt;/strong&gt;&lt;br/&gt;
I had a fair amount of experience with Spring MVC and extensionless URLs. Both the Spring MVC applications we developed last year at Time Warner Cable used them. To change from a *.html mapping to /app/* was pretty easy and involved removing more code than I added. Previously, I had a &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/common/src/main/java/org/appfuse/webapp/filter/StaticFilter.java?r=3250&quot;&gt;StaticFilter&lt;/a&gt; that looked for HTML files and if it didn&apos;t find them, it dispatched to Spring&apos;s DispatcherServlet. I was able to remove this class and make the web.xml file quite a bit cleaner. 
&lt;/p&gt;
&lt;p&gt;To make UrlRewriteFilter and Spring Security play well together, I had to move the securityFilter so it came &lt;em&gt;after&lt;/em&gt; the rewriteFilter and add an INCLUDE dispatcher so included JSPs would have a security context available to them. 
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;rewriteFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;securityFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;
    &amp;lt;dispatcher&amp;gt;REQUEST&amp;lt;/dispatcher&amp;gt;
    &amp;lt;dispatcher&amp;gt;FORWARD&amp;lt;/dispatcher&amp;gt;
    &amp;lt;dispatcher&amp;gt;INCLUDE&amp;lt;/dispatcher&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The only other things I had to change were &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/spring/src/main/webapp/WEB-INF/security.xml?r2=3458&amp;r1=3379&quot;&gt;security.xml&lt;/a&gt; and &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/spring/src/main/webapp/WEB-INF/dispatcher-servlet.xml?r2=3458&amp;r1=3334&quot;&gt;dispatcher-servlet.xml&lt;/a&gt; to remove the .html extensions. The urlrewrite.xml file was fairly straightforward. I used the following at the bottom as a catch-all for dispatching to Spring MVC.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;rule&amp;gt;
    &amp;lt;from&amp;gt;/**&amp;lt;/from&amp;gt;
    &amp;lt;to&amp;gt;/app/$1&amp;lt;/to&amp;gt;
&amp;lt;/rule&amp;gt;
&amp;lt;outbound-rule&amp;gt;
    &amp;lt;from&amp;gt;/app/**&amp;lt;/from&amp;gt;
    &amp;lt;to&amp;gt;/$1&amp;lt;/to&amp;gt;
&amp;lt;/outbound-rule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
Then I added a number of other rules for j_security_check, DWR, CXF and static assets (/images, /scripts, /styles, /favicon.ico). You can view the &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/spring/src/main/webapp/WEB-INF/urlrewrite.xml?r=HEAD&quot;&gt;current urlrewrite.xml in FishEye&lt;/a&gt;. The only major issue I ran into was that Spring Security recorded protected URLs as /app/URL so I had to add a rule to redirect when this happened after logging in.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;rule&amp;gt;
    &amp;lt;from&amp;gt;/app/**&amp;lt;/from&amp;gt;
    &amp;lt;to last=&quot;true&quot; type=&quot;redirect&quot;&amp;gt;%{context-path}/$1&amp;lt;/to&amp;gt;
&amp;lt;/rule&amp;gt;
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Struts 2&lt;/strong&gt;&lt;br/&gt;
Using extensionless URLs with Struts 2 is likely pretty easy thanks to the &lt;a href=&quot;http://struts.apache.org/2.1.8/docs/convention-plugin.html&quot;&gt;Convention Plugin&lt;/a&gt;. Even though this plugin is included in AppFuse, it&apos;s not configured with the proper &lt;a href=&quot;http://struts.apache.org/2.1.8/docs/converting-application-from-codebehind-to-convention-plugin.html&quot;&gt;constants&lt;/a&gt; and I have struts.convention.action.disableScanning=true in struts.xml. It looks like I had to do this when I &lt;a href=&quot;http://appfuse.markmail.org/thread/ktbqtx2mslvrkjkq&quot;&gt;upgraded from Struts 2.0.x to Struts 2.1.6&lt;/a&gt;. It&apos;s true AppFuse&apos;s Struts 2 support could use a bit of love to be aligned with Struts 2&apos;s recommended practices, but I didn&apos;t want to spend the time doing it as part of this exercise. 
&lt;/p&gt;
&lt;p&gt;With Struts 2, I tried the path-mapping like I did with Spring MVC, but ran into issues. Instead, I opted to use an &quot;.action&quot; extension by changing &lt;code&gt;struts.action.extension&lt;/code&gt; from &quot;html&quot; to &quot;action,&quot; in struts.xml. Then I had to do a bunch of filter re-ordering and dispatcher changes. Before, with a .html extension, I had all filters mapped to /* and in the following order.&lt;/p&gt;
&lt;table class=&quot;comparison&quot; style=&quot;width: 250px&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Filter Name&lt;/th&gt;&lt;th&gt;Dispatchers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;securityFilter&lt;/td&gt;
&lt;td&gt;request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rewriteFilter&lt;/td&gt;
&lt;td&gt;request, forward&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;struts-prepare&lt;/td&gt;
&lt;td&gt;request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sitemesh&lt;/td&gt;
&lt;td&gt;request, forward, include&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;staticFilter&lt;/td&gt;
&lt;td&gt;request, forward&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;struts&lt;/td&gt;
&lt;td&gt;request&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Similar to Spring MVC, I had to remove the rewriteFilter in front of the securityFilter and I was able to remove the staticFilter. I also had to map the struts filter to *.action instead of /* to stop Struts from trying to catch static asset and DWR/CXF requests. Below is the order of filters and their dispatchers that seems to work best.
&lt;table class=&quot;comparison&quot; style=&quot;width: 250px&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Filter Name&lt;/th&gt;&lt;th&gt;Dispatchers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;rewriteFilter&lt;/td&gt;
&lt;td&gt;request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;securityFilter&lt;/td&gt;
&lt;td&gt;request, forward, include&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;struts-prepare&lt;/td&gt;
&lt;td&gt;request, forward&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sitemesh&lt;/td&gt;
&lt;td&gt;request, forward, include&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;struts&lt;/td&gt;
&lt;td&gt;forward&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;From there, it was a matter of modifying &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/struts/src/main/webapp/WEB-INF/urlrewrite.xml?r=HEAD&quot;&gt;urlrewrite.xml&lt;/a&gt; to have the following catch-all and rules for static assets, j_security_check and DWR/CXF.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;rule match-type=&quot;regex&quot;&amp;gt;
    &amp;lt;from&amp;gt;^(&amp;#91;^?&amp;#93;*)/(&amp;#91;^?/\.&amp;#93;+)(\?.*)?$&amp;lt;/from&amp;gt;
    &amp;lt;to last=&quot;true&quot;&amp;gt;$1/$2.action$3&amp;lt;/to&amp;gt;
&amp;lt;/rule&amp;gt;
&amp;lt;outbound-rule match-type=&quot;regex&quot;&amp;gt;
    &amp;lt;from&amp;gt;^(.*)\.action(\?.*)?$&amp;lt;/from&amp;gt;
    &amp;lt;to last=&quot;false&quot;&amp;gt;$1$2&amp;lt;/to&amp;gt;
&amp;lt;/outbound-rule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;JSF&lt;/strong&gt;&lt;br/&gt;
JSF was by far the most difficult to get extensionless URLs working with. I&apos;m not convinced it&apos;s impossible, but I spent a several hours over a few days and was unsuccessful in completely removing them. I was able to make things work so I could request pages without an extension, but found when clicking buttons and links, the extension would often show up in the URL. I&apos;m also still using JSF 1.2, so it&apos;s possible that upgrading to 2.0 would solve many of the issues I encountered. &lt;/p&gt;
&lt;p&gt;For the time being, I&apos;ve changed my FacesServlet mapping from *.html to *.jsf. As with Struts, I had issues when I tried to map it to /app/*. Other changes include &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/jsf/src/main/webapp/WEB-INF/web.xml?r1=3384&amp;r2=3458#l188&quot;&gt;changing the order of dispatchers and filters&lt;/a&gt;, the good ol&apos; catch-all in &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/jsf/src/main/webapp/WEB-INF/urlrewrite.xml?r=HEAD&quot;&gt;urlrewrite.xml&lt;/a&gt; and &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/jsf/src/main/webapp/WEB-INF/security.xml?r1=3384&amp;r2=3458#l188&quot;&gt;modifying security.xml&lt;/a&gt;. For some reason, I wasn&apos;t able to get file upload working without adding an exception to the outbound-rule.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;rule match-type=&quot;regex&quot;&amp;gt;
    &amp;lt;from&amp;gt;^(&amp;#91;^?&amp;#93;*)/(&amp;#91;^?/\.&amp;#93;+)(\?.*)?$&amp;lt;/from&amp;gt;
    &amp;lt;to last=&quot;true&quot;&amp;gt;$1/$2.jsf&amp;lt;/to&amp;gt;
&amp;lt;/rule&amp;gt;
&amp;lt;outbound-rule match-type=&quot;regex&quot;&amp;gt;
  &amp;lt;!-- TODO: Figure out how to make file upload work w/o using *.jsf --&amp;gt;
    &amp;lt;condition type=&quot;path-info&quot;&amp;gt;selectFile&amp;lt;/condition&amp;gt;
    &amp;lt;from&amp;gt;^(.*)\.jsf(\?.*)?$&amp;lt;/from&amp;gt;
    &amp;lt;to last=&quot;false&quot;&amp;gt;$1$2&amp;lt;/to&amp;gt;
&amp;lt;/outbound-rule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;I also spent a couple hours trying to get &lt;a href=&quot;http://ocpsoft.com/prettyfaces/&quot;&gt;Pretty Faces&lt;/a&gt; to work. I wrote about my issues &lt;a href=&quot;http://ocpsoft.com/support/topic/rewrite-every-jsf&quot;&gt;on the forums&lt;/a&gt;. I tried writing a custom Processor to strip the extension, but found that I&apos;d get into an infinite loop where the processor kept getting called. To workaround this, I tried using Spring&apos;s RequestContextHolder to ensure the processor only got invoked once, but that proved fruitless. Finally, I tried inbound &lt;em&gt;and&lt;/em&gt; outbound custom processors, but failed to get those working. The final thing I tried was url-mappings for each page in pretty-config.xml.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;url-mapping&amp;gt;
  &amp;lt;pattern value=&quot;/admin/users&quot;/&amp;gt;
  &amp;lt;view-id value=&quot;/admin/users.jsf&quot;/&amp;gt;
&amp;lt;/url-mapping&amp;gt;
&amp;lt;url-mapping&amp;gt;
  &amp;lt;pattern value=&quot;/mainMenu&quot;/&amp;gt;
  &amp;lt;view-id value=&quot;/mainMenu.jsf&quot;/&amp;gt;
&amp;lt;/url-mapping&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The issue with doing this was that some of the navigation rules in my faces-config.xml stopped working. I didn&apos;t spend much time trying to diagnose the problem because I didn&apos;t like having to add an entry for each page in the application. The one nice thing about Pretty Faces is it did allow me to do things like the following, which I formerly did with a form that auto-submitted when the page loaded.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;url-mapping&amp;gt;
  &amp;lt;pattern value=&quot;/passwordHint/#{username}&quot;/&amp;gt;
  &amp;lt;view-id value=&quot;/passwordHint.jsf&quot;/&amp;gt;
  &amp;lt;action&amp;gt;#{passwordHint.execute}&amp;lt;/action&amp;gt;
&amp;lt;/url-mapping&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br/&gt;
My journey implementing extensionless URLs was an interesting one, and I solidified my knowledge about ordering of filters, dispatchers and the UrlRewriteFilter. I still think I have more to learn about properly implementing extensionless URLs in Struts 2 and JSF and I hope to do that in the near future. I believe Struts&apos; Convention Plugin will help me and JSF 2 + Pretty Faces will hopefully work nicely too. Of course, it&apos;d be great if all Java Web Frameworks had an easy mechanism for producing and consuming extensionless URLs. In the meantime, thank goodness for the UrlRewriteFilter.
&lt;/p&gt;
&lt;p&gt;If you&apos;d like to try AppFuse and its shiny new URLs, see the &lt;a href=&quot;http://appfuse.org/display/APF/AppFuse+QuickStart&quot;&gt;QuickStart Guide&lt;/a&gt; and choose the 2.1.0-SNAPSHOT version.

</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/how_i_calculated_ratings_for</id>
        <title type="html">How I Calculated Ratings for My JVM Web Frameworks Comparison</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/how_i_calculated_ratings_for"/>
        <published>2010-12-06T11:55:18-07:00</published>
        <updated>2014-05-08T19:47:26-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="devoxx2010" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jvm" scheme="http://roller.apache.org/ns/tags/" />
        <category term="lift" scheme="http://roller.apache.org/ns/tags/" />
        <category term="comparingwebframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworksmatrix" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="vaadin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="flex" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="wicket" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="stripes" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rubyonrails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="playframework" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">When I re-wrote my &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_comparing_jvm_web_frameworks&quot;&gt;Comparing JVM Web Frameworks presentation&lt;/a&gt; from scratch, I decided to add a &lt;a href=&quot;http://bit.ly/jvm-frameworks-matrix&quot;&gt;matrix&lt;/a&gt; that allows you to rate a framework based on &lt;a href=&quot;https://docs.google.com/document/pub?id=1jAGPWwlEcYikqOPg8faYgRV7cQNS_iCCoJ1VNc_99M4&quot;&gt;20 different criteria&lt;/a&gt;. The reason I did this was because I&apos;d used this method when &lt;a href=&quot;http://raibledesigns.com/rd/entry/ajax_framework_analysis_results&quot;&gt;choosing an Ajax framework for Evite&lt;/a&gt; last year. The matrix seemed to work well for selecting the top 5 frameworks, but it also inspired a lot of discussion in the community that my &lt;a href=&quot;http://ptrthomas.wordpress.com/2010/12/04/comparing-jvm-web-frameworks-a-response-to-matt-raible/&quot;&gt;ratings&lt;/a&gt; &lt;a href=&quot;http://blog.frankel.ch/critical-analysis-of-frameworks-comparison&quot;&gt;were&lt;/a&gt; &lt;a href=&quot;http://basementcoders.com/2010/12/episode-27-hudson-oracle-raible-and-astycrapper/&quot;&gt;wrong&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;I expected this, as I certainly don&apos;t know every framework as well as I&apos;d like. The mistake I made was asking for the community to provide feedback on my ratings without describing how I arrived at them. From &lt;a href=&quot;http://ptrthomas.wordpress.com/2010/12/04/comparing-jvm-web-frameworks-a-response-to-matt-raible/&quot;&gt;Peter Thomas&apos;s blog&lt;/a&gt;:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
What you are doing is adjusting ratings based on who in the community shouts the loudest. I can&apos;t help saying that this approach comes across as highly arrogant and condescending, you seem to expect framework developers and proponents to rush over and fawn over you to get better ratings, like waiters in a restaurant trying to impress a food-critic for Michelin stars.
&lt;/p&gt;
&lt;p&gt;
I apologize for giving this impression. It certainly wasn&apos;t my intent. By having simple numbers (1.0 == framework does well, 0.5 == framework is OK and 0 == framework not good at criteria) with no rationalization, I can see how the matrix can be interpreted as useless (or to put it bluntly, as &lt;a href=&quot;http://basementcoders.com/2010/12/episode-27-hudson-oracle-raible-and-astycrapper/&quot;&gt;something you should wipe your ass with&lt;/a&gt;). I don&apos;t blame folks for getting angry.&lt;/p&gt;
&lt;p&gt;For my Rich Web Experience presentation, I documented why I gave each framework the rating I did. Hopefully this will allow folks to critique my ratings more constructively and I can make the numbers more accurate. You can view this document below or &lt;a href=&quot;http://bit.ly/jvm-webfwk-ratings-logic&quot;&gt;on Google Docs&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;//docs.google.com/document/pub?id=1X_XvpJd6TgEAMe4a6xxzJ38yzmthvrA6wD7zGy2Igog&amp;amp;embedded=true&quot; style=&quot;width: 100%; border: 1px solid silver; height: 400px&quot;&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;In the end, what I was hoping to do with this matrix was to simply highlight a &lt;em&gt;technique&lt;/em&gt; for choosing a web framework. Furthermore, I think adding a &quot;weight&quot; to each criteria is important because things like books often aren&apos;t as important as REST support. To show how this might be done, I added a second sheet to the matrix and made up some weighting numbers. I&apos;d expect anyone that wants to use this to &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/JVM_Web_Framework_Matrix_20101206.xls&quot;&gt;downloaded the matrix&lt;/a&gt;, verify the ratings are accurate for your beliefs and weight the criteria accordingly.
&lt;/p&gt;
&lt;p&gt;
Of course, as I and many others have said, the best way to choose a web framework is to try them yourself. I emphasized this at the end of my presentation with the following two slides.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://www.flickr.com/photos/mraible/5238846712/&quot; title=&quot;Slide #77 from Comparing JVM Web Frameworks Talk at RWX2010&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5281/5238846712_375a63e4c6.jpg&quot; width=&quot;500&quot; height=&quot;375&quot; alt=&quot;Slide #77 from Comparing JVM Web Frameworks Talk at RWX2010&quot; /&gt;&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;a href=&quot;http://www.flickr.com/photos/mraible/5238846740/&quot; title=&quot;Slide #76 from Comparing JVM Web Frameworks Talk at RWX2010&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5129/5238846740_29b06ee0eb.jpg&quot; width=&quot;500&quot; height=&quot;375&quot; alt=&quot;Slide #76 from Comparing JVM Web Frameworks Talk at RWX2010&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/my_everything_you_ever_wanted</id>
        <title type="html">My Everything You Ever Wanted To Know About Online Video Presentation</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/my_everything_you_ever_wanted"/>
        <published>2010-12-03T10:16:44-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/The Web" label="The Web" />
        <category term="youtube" scheme="http://roller.apache.org/ns/tags/" />
        <category term="richweb" scheme="http://roller.apache.org/ns/tags/" />
        <category term="onlinevideo" scheme="http://roller.apache.org/ns/tags/" />
        <category term="hulu" scheme="http://roller.apache.org/ns/tags/" />
        <category term="video" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rwx2010" scheme="http://roller.apache.org/ns/tags/" />
        <category term="encoding" scheme="http://roller.apache.org/ns/tags/" />
        <category term="html5" scheme="http://roller.apache.org/ns/tags/" />
        <category term="netflix" scheme="http://roller.apache.org/ns/tags/" />
        <category term="richwebexperience" scheme="http://roller.apache.org/ns/tags/" />
        <category term="flash" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This week I&apos;ve had the pleasure of speaking at &lt;a href=&quot;http://www.therichwebexperience.com/conference/fort_lauderdale/2010/11/home&quot;&gt;The Rich Web Experience&lt;/a&gt; in Fort Lauderdale. I did two talks, one on Comparing JVM Web Frameworks and one titled &lt;a href=&quot;http://www.therichwebexperience.com/conference/fort_lauderdale/2010/11/session?id=20473&quot;&gt;Everything You Ever Wanted To Know About Online Video&lt;/a&gt;. Both talks had full rooms and very engaged audiences. 
&lt;/p&gt;
&lt;p&gt;
In the video talk, there were some audience members that knew &lt;em&gt;way&lt;/em&gt; more than me about the topic. This made for a very interactive session and one of the most fun presentations I&apos;ve ever done. It was also cool to talk about a lot of things I&apos;ve learned over the last year (for more details on that, check out my &lt;a href=&quot;http://raibledesigns.com/rd/entry/how_s_the_ol_team&quot;&gt;team status&lt;/a&gt; or &lt;a href=&quot;http://raibledesigns.com/rd/entry/how_we_hired_a_team&quot;&gt;team hiring&lt;/a&gt; posts). If you don&apos;t have Flash installed, you can &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/Everything_Online_Video_RWX2010.pdf&quot;&gt;download a PDF&lt;/a&gt; of this presentation.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;object id=&quot;__sse6011456&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=everythingonlinevideo-101202175612-phpapp01&amp;rel=0&amp;stripped_title=everything-you-ever-wanted-to-know-about-online-video&amp;userName=mraible&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;&lt;embed name=&quot;__sse6011456&quot; src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=everythingonlinevideo-101202175612-phpapp01&amp;rel=0&amp;stripped_title=everything-you-ever-wanted-to-know-about-online-video&amp;userName=mraible&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;The first talk about Comparing JVM Web Frameworks was largely an extension of the &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_comparing_jvm_web_frameworks&quot;&gt;one I presented at Devoxx&lt;/a&gt; two weeks ago. The main differences between this one and the last one is I extended it a bit and took into account some &lt;a href=&quot;http://blog.tapestry5.de/index.php/2010/11/21/response-to-matt-raibles-presentation-at-devoxx-2010/&quot;&gt;community&lt;/a&gt; &lt;a href=&quot;http://www.logemann.org/2010/11/on-matt-raibles-web-framework.html&quot;&gt;feedback&lt;/a&gt;. However, this seemed to simply &lt;a href=&quot;http://old.nabble.com/Matt-Raible%27s-JVM-Web-Framework-matrix-td30345655.html&quot;&gt;inspire&lt;/a&gt; &lt;a href=&quot;http://twitter.com/#!/ptrthomas/status/9818249143255040&quot;&gt;anger&lt;/a&gt;, so I&apos;ll pass on embedding it here. You can &lt;a href=&quot;http://www.slideshare.net/mraible/comparing-jvm-web-frameworks-rich-web-experience-2010&quot;&gt;view it on Slideshare&lt;/a&gt; or &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/Comparing_JVM_Web_Frameworks_RWX2010.pdf&quot;&gt;download the PDF&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;My Comparing Web Frameworks slides often inspire harsh words, but folks &lt;a href=&quot;http://twitter.com/#!/snicoll/status/5251494903291905&quot; title=&quot;you may disagree with some of the content but @mraible session was the most interesting session of devoxx 2010 so far IMO.&quot;&gt;really seem to like the presentation&lt;/a&gt;. I encourage you to watch my &lt;a href=&quot;http://parleys.com/d/2118&quot;&gt;Devoxx presentation on Parleys.com&lt;/a&gt; to see for yourself.
&lt;/p&gt;
&lt;p&gt;This marks the end of 2010 conferences for me. I had a blast speaking at The Rich Web Experience, as well as &lt;a href=&quot;http://raibledesigns.com/rd/entry/tssjs_2010_presentations_and_summary&quot;&gt;TheServerSide Java Symposium&lt;/a&gt;, &lt;a href=&quot;http://raibledesigns.com/rd/entry/presentations_from_the_irish_software&quot;&gt;The Irish Software Show&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_comparing_jvm_web_frameworks&quot;&gt;Devoxx&lt;/a&gt;. Now it&apos;s time to sit back, relax, get some powder days in and find my next gig.&lt;/p&gt;
&lt;p&gt;Hope y&apos;all have a great holiday season!</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/my_comparing_jvm_web_frameworks</id>
        <title type="html">My Comparing JVM Web Frameworks Presentation from Devoxx 2010</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/my_comparing_jvm_web_frameworks"/>
        <published>2010-11-18T05:23:10-07:00</published>
        <updated>2015-08-23T18:57:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="stripes" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rubyonrails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jvm" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx2010" scheme="http://roller.apache.org/ns/tags/" />
        <category term="playframework" scheme="http://roller.apache.org/ns/tags/" />
        <category term="lift" scheme="http://roller.apache.org/ns/tags/" />
        <category term="devoxx" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="wicket" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="vaadin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="flex" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This week, I&apos;ve been having a great time in Antwerp, Belgium at the &lt;a href=&quot;http://www.devoxx.com/display/Devoxx2K10/Home&quot;&gt;Devoxx&lt;/a&gt; Conference. This morning, I had the pleasure of delivering my &lt;a href=&quot;http://www.devoxx.com/display/Devoxx2K10/Comparing+JVM+Web+Frameworks&quot;&gt;Comparing JVM Web Frameworks&lt;/a&gt; talk. I thoroughly enjoyed giving this presentation, especially to such a large audience. You can view the presentation below (if you have Flash installed) or &lt;a href=&quot;http://static.raibledesigns.com/repository/presentations/Comparing_JVM_Web_Frameworks_Devoxx2010.pdf&quot;&gt;download it here&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/uBZoC22SGdjpFy&quot; width=&quot;510&quot; height=&quot;420&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen&gt; &lt;/iframe&gt;
&lt;/p&gt;
&lt;p&gt;
Unlike previous years, I chose to come up with a &lt;a href=&quot;http://bit.ly/jvm-frameworks-matrix&quot;&gt;spreadsheet matrix&lt;/a&gt; that shows why I chose the 5 I did. This spreadsheet and rankings given to each framework are likely to be debated, as I don&apos;t know all the frameworks as well as I&apos;d like to. Also, the missing column on this spreadsheet is a &quot;weighting&quot; column where you can prioritize certain criteria like I&apos;ve done in the past when &lt;a href=&quot;http://raibledesigns.com/rd/entry/ajax_framework_analysis_results&quot;&gt;Comparing Ajax Frameworks&lt;/a&gt;. If you believe there are incorrect numbers, please let me know and I&apos;ll try to get those fixed before I do this talk again at &lt;a href=&quot;http://www.therichwebexperience.com/conference/fort_lauderdale/2010/11/home&quot;&gt;The Rich Web Experience&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
One thing that doesn&apos;t come across in this presentation is that I believe &lt;em&gt;anyone&lt;/em&gt; can use this matrix, and weightings, to make &lt;em&gt;any&lt;/em&gt; of these frameworks come out on top. I also believe web frameworks are like spaghetti sauce in &lt;a href=&quot;http://www.gladwell.com/2004/2004_09_06_a_ketchup.html&quot;&gt;The Ketchup Conundrum&lt;/a&gt;. That is, the only way to make more happy spaghetti sauce lovers was to make more &lt;em&gt;types&lt;/em&gt; of spaghetti sauce. You can read more about this in my &lt;a href=&quot;http://raibledesigns.com/rd/entry/there_is_no_best_web&quot;&gt;There is no &quot;best&quot; web framework&lt;/a&gt; article.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; If you disagree with the various ratings I gave to web frameworks in this presentation, please provide your opinions by &lt;a href=&quot;http://bit.ly/webmatrixsurvey&quot;&gt;filling out this survey&lt;/a&gt;. Thanks to &lt;a href=&quot;http://twitter.com/sarbogast&quot;&gt;Sebastien Arbogast&lt;/a&gt; for setting this up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Sebastien has posted his survey results at &lt;a href=&quot;http://sebastien-arbogast.com/2010/11/19/jvm-web-framework-survey-first-results/&quot;&gt;JVM Web Framework Survey, First Results&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 12/6:&lt;/strong&gt; A video of this presentation is &lt;a href=&quot;http://parleys.com/d/2118&quot;&gt;now available on Parleys.com&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;border-top: 1px dotted silver; padding-top: 5px; color: #666&quot;&gt;
P.S. My current gig is ending in mid-December. If you&apos;re looking for a UI Architect with a passion for open source frameworks, please &lt;a href=&quot;http://raibledesigns.com/contact.jsp&quot;&gt;let me know&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/appfuse_2_1_milestone_2</id>
        <title type="html">AppFuse 2.1 Milestone 2 Released</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/appfuse_2_1_milestone_2"/>
        <published>2010-11-15T15:28:57-07:00</published>
        <updated>2010-11-15T22:37:10-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="myfaces" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse-light" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="freemarker" scheme="http://roller.apache.org/ns/tags/" />
        <category term="wicket" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <category term="stripes" scheme="http://roller.apache.org/ns/tags/" />
        <category term="hibernate" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java5" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ibatis" scheme="http://roller.apache.org/ns/tags/" />
        <category term="archetypes" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jpa" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tapestry" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven3" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">I&apos;m pleased to announce the 2nd milestone release of AppFuse 2.1. This release includes upgrades to all dependencies to bring them up-to-date with their latest releases. Most notable are Spring 3 and Struts 2.1. This release fixes many issues with archetypes and contains many improvements to support Maven 3. For more details on specific changes see the &lt;a href=&quot;http://appfuse.org/display/APF/Release+Notes+2.1.0+M2&quot;&gt;2.1.0 M2 release notes&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;What is AppFuse?&lt;/strong&gt;&lt;br/&gt;
AppFuse is an open source project and application that uses open source frameworks to help you develop Web applications quickly and efficiently. It was originally developed to eliminate the ramp-up time when building new web applications. At its core, AppFuse is a project skeleton, similar to the one that&apos;s created by your IDE when you click through a wizard to create a new web project. If you use &lt;a href=&quot;http://raibledesigns.com/rd/entry/using_jrebel_with_intellij_idea&quot;&gt;JRebel with AppFuse&lt;/a&gt;, you can achieve zero-turnaround in your project and develop features without restarting the server.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;
Release Details&lt;/strong&gt;&lt;br/&gt;
Archetypes now include all the source for the web modules so using jetty:run and your IDE will work much smoother now. The backend is still embedded in JARs, enabling you to choose with persistence framework (Hibernate, iBATIS or JPA) you&apos;d like to use. If you want to modify the source for that, &lt;a href=&quot;http://appfuse.org/display/APF/AppFuse+Core+Classes&quot;&gt;add the core classes to your project&lt;/a&gt; or run &quot;appfuse:full-source&quot;.
&lt;/p&gt;
&lt;p&gt;
AppFuse comes in a number of different flavors. It offers &quot;light&quot;, &quot;basic&quot; and &quot;modular&quot; and archetypes. Light archetypes use an embedded H2 database and contain a simple CRUD example. In the final 2.1.0 release, the light archetypes will allow code generation like the basic and modular archetypes. Basic archetypes have web services using CXF, authentication from Spring Security and features including signup, login, file upload and CSS theming. Modular archetypes are similar to basic archetypes, except they have multiple modules which allows you to separate your services from your web project.
&lt;/p&gt;
&lt;p&gt;
AppFuse provides &lt;a href=&quot;http://static.appfuse.org/archetype.html&quot;&gt;archetypes&lt;/a&gt; for JSF, Spring MVC, Struts 2 and Tapestry 5. The light archetypes are available for these frameworks, as well as for Spring MVC + FreeMarker, Stripes and Wicket.
&lt;/p&gt;
&lt;p&gt;
Please note that this release does not contain updates to the documentation. Code generation will work, but it&apos;s likely that some content in the &lt;a href=&quot;http://appfuse.org/display/APF/Tutorials&quot;&gt;tutorials&lt;/a&gt; won&apos;t match. For example, you can use annotations (vs. XML) for Spring MVC and Tapestry is a whole new framework. I&apos;ll be working on documentation over the next several weeks in preparation for the 2.1 final release.
&lt;/p&gt;
&lt;p&gt;
For information on creating a new project, please see the &lt;a href=&quot;http://appfuse.org/display/APF/AppFuse+QuickStart&quot;&gt;QuickStart Guide&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
If you have questions about AppFuse, please read the &lt;a href=&quot;http://appfuse.org/display/APF/FAQ&quot;&gt;FAQ&lt;/a&gt; or join the &lt;a href=&quot;http://appfuse.org/display/APF/Mailing+Lists&quot;&gt;user mailing list&lt;/a&gt;. If you find bugs, please &lt;a href=&quot;http://issues.appfuse.org/browse/APF&quot;&gt;create an issue in JIRA&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Thanks to everyone for their help contributing patches, writing documentation and participating on the mailing lists.
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/re_moving_from_spring_to</id>
        <title type="html">RE: Moving from Spring to Java EE 6: The Age of Frameworks is Over</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/re_moving_from_spring_to"/>
        <published>2010-10-16T15:19:07-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="javaee" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="frameworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last Tuesday, Cameron McKenzie wrote an interesting article on TheServerSide titled &lt;a href=&quot;http://www.theserverside.com/discussions/thread.tss?thread_id=61023&quot;&gt;Moving from Spring to Java EE 6: The Age of Frameworks is Over&lt;/a&gt;. In this article, Cameron says the following:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
J2EE represents the past, and Java EE 6 represents the future. Java EE 6 promises us the ability to go beyond frameworks. Frameworks like Spring are really just a bridge between the mistakes of the J2EE past and the success of the Java EE 6 future. Frameworks are out, and extensions to the Java EE 6 platform are in. Now is the time to start looking past Spring, and looking forward to Seam and Weld and CDI technologies.
&lt;/p&gt;
&lt;p&gt;He then links to an article titled &lt;a href=&quot;http://ocpsoft.com/java/spring-to-java-ee-a-migration-guide-cdi-jsf-jpa-jta-ejb/&quot;&gt;Spring to Java EE - A Migration Experience&lt;/a&gt;, an article written by JBoss&apos;s Lincoln Baxter. In this article, Lincoln talks about many of the technologies in Java EE 6, namely JPA, EJB, JSF, CDI and JAX-RS. He highlights all the various XML files you&apos;ll need to know about and the wide variety of Java EE 6 application servers: JBoss AS 6 and GlassFish v3.&lt;/p&gt;
&lt;p&gt;I don&apos;t have a problem with Lincoln&apos;s article, in fact I think it&apos;s very informative and some of the best documentation I&apos;ve seen for Java EE 6. 
&lt;/p&gt;
&lt;p&gt;
I do have some issues with Cameron&apos;s statements that frameworks are mistakes of the J2EE past and that Java EE 6 represents the future. Open source frameworks made J2EE successful. Struts and Hibernate came out in the early days of J2EE and still exist today. Spring came out shortly after and has turned into the do-everything J2EE implementation it was trying to fix. Java EE 6 &lt;em&gt;might be&lt;/em&gt; a better foundation to build upon, but it&apos;s certainly not going to replace frameworks.
&lt;/p&gt;
&lt;p&gt;
To prove my point, let&apos;s start by looking at the persistence layer. We used to have Hibernate based on JDBC, now we have JPA implementations built on top of the JPA API. Is JPA a replacement for all persistence frameworks? I&apos;ve worked with it and think it&apos;s a good API, but the 2.0 version &lt;a href=&quot;https://repository.sonatype.org/index.html#nexus-search;quick~javax.persistence&quot;&gt;isn&apos;t available in a Maven repo&lt;/a&gt; and &lt;a href=&quot;http://wiki.alfresco.com/wiki/Alfresco_Community_3.4.a#Hibernate_Removal&quot;&gt;Alfresco recently moved away from Hibernate&lt;/a&gt; (which == JPA IMO) to iBATIS for greater data access layer control and scalability. Looks like the age of frameworks isn&apos;t over for persistence frameworks.&lt;/p&gt;
&lt;p&gt;The other areas that Java EE 6 covers that I believe frameworks will continue to excel in: EJB, CDI, JSF and JAX-RS. Personally, I don&apos;t have a problem with EJB 3 and think it&apos;s a vast improvement on EJB 2.x. I don&apos;t have an issue with CDI either, and as long as it resembles Guice for dependency injection, it works for me. However, when you get into the space I&apos;ve been living in for the last couple years (high-traffic public internet sites), EJB and things like the &quot;conversation-scope&quot; feature of CDI don&apos;t buy you much. The way to make web application scale is to eliminate state and cache as much as possible, both of which Java EE doesn&apos;t provide much help for. In fact, to disable sessions in a servlet-container, you have to write a Filter like the following:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class DisabledSessionFilter extends OncePerRequestFilter {

    /**
     * Filters requests to disable URL-based session identifiers.
     */
    @Override
    protected void doFilterInternal(final HttpServletRequest request,
                                    final HttpServletResponse response,
                                    final FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequestWrapper wrappedRequest = new HttpServletRequestWrapper(request) {

            @Override
            public HttpSession getSession(final boolean create) {
                if (create) {
                    throw new UnsupportedOperationException(&quot;Session support disabled&quot;);
                }
                return null;
            }

            @Override
            public HttpSession getSession() {
                throw new UnsupportedOperationException(&quot;Session support disabled&quot;);
            }
        };

        // process next request in chain
        chain.doFilter(wrappedRequest, response);
    }
}
&lt;/pre&gt;
&lt;p&gt;What about JAX-RS? Does it replace the need for frameworks? I like the idea of having a REST API in Java. However, its reference implementation is &lt;a href=&quot;https://jersey.dev.java.net/&quot;&gt;Jersey&lt;/a&gt;, which seems more like a framework than just Java EE. If you choose to use JAX-RS in your application, you still have to choose between CXF, Jersey, RESTEasy and Restlet. &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_experience_with_java_rest&quot;&gt;I compared these frameworks last year&lt;/a&gt; and found the Java EE implementation lacking in the features I needed. 
&lt;/p&gt;
&lt;p&gt;Finally, let&apos;s talk about my-least-framework-web-framework: JSF. The main reason I don&apos;t like JSF is because of its 1.x version. JSF 1.0 was released a year before the Ajax term was coined (see timeline below). Not only did it take forever to develop as a spec, but it tried to be a client-component framework that was very stateful by default. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4067/4378559350_aef7d39d06_o.png&quot; title=&quot;History of Web Frameworks&quot; rel=&quot;lightbox&quot;&gt;
&lt;img src=&quot;//farm5.static.flickr.com/4067/4378559350_13f0755403.jpg&quot; width=&quot;500&quot; height=&quot;234&quot; alt=&quot;History of Web Frameworks&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Now that JSF 2.0 is out, it has Ajax integrated and allows you to use GET instead of POST-for-everything. However, the only people that like Ajax integrated into their web frameworks are programmers scared of JavaScript (who probably shouldn&apos;t be developing your UI). Also, the best component development platform for the web &lt;em&gt;is&lt;/em&gt; JavaScript. I recommend using an Ajax framework for your components if you really want a rich UI. 
&lt;/p&gt;
&lt;p&gt;
Sure you can use the likes of Tapestry and Wicket if you like POJO-based web development, but if you&apos;re looking to develop a webapp that&apos;s easy to maintain and understand, chances are that you&apos;ll do much better with traditional MVC frameworks like Spring MVC and Struts 2. The simplicity and popularity of Rails and Grails further emphasize that developers prefer these types of web frameworks.&lt;/p&gt;
&lt;p&gt;Another reason I don&apos;t like JSF: there&apos;s very few developers in the wild happy with it. The major promoters of JSF are book authors, trainers, Java EE Vendors and MyFaces developers. Whenever I speak at conferences, I ask folks to raise their hands for the various web frameworks they&apos;re using. I always ask the JSF users to keep their hands up if they like it. Rarely do they stay up.
&lt;/p&gt;
&lt;p&gt;
So it looks like we still need web frameworks. 
&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jandiandme.blogspot.com/2010/10/spring-vs-java-ee-and-why-i-dont-care.html&quot;&gt;Eberhard Wolff has an interesting post&lt;/a&gt; where he defends Spring and talks about the productivity comparisons between Spring and Java EE. He recommends using Grails or Spring Roo if you want the level of productivity that Ruby on Rails provides. That&apos;s a valid recommendation if you&apos;re building CRUD-based webapps, but I haven&apos;t developed those in quite some time. Nowadays, the apps I develop are true SOFEA apps, where the backend serves up XML or JSON and the frontend client is HTML/JavaScript/CSS, Android, iPad or Sony Blu-Ray players. On my current project, our services don&apos;t even talk to a database, they talk to a CMS via RESTful APIs. We use Spring&apos;s RestTemplate for this and HttpClient when it doesn&apos;t have the features we need. Not much in Java EE 6 for this type of communication. Sure, &lt;a href=&quot;http://blogs.sun.com/enterprisetechtips/entry/consuming_restful_web_services_with&quot;&gt;Jersey has a client&lt;/a&gt;, but it&apos;s certainly not part of the Java EE spec.
&lt;/p&gt;
&lt;p&gt;As far as getting Ruby on Rails&apos; zero-turnaround productivity, I don&apos;t need Grails or Spring Roo, I simply use &lt;a href=&quot;http://www.jetbrains.com/idea/&quot;&gt;IDEA&lt;/a&gt; and &lt;a href=&quot;http://www.zeroturnaround.com/jrebel/&quot;&gt;JRebel&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br/&gt;
I don&apos;t see how new features in Java EE 6 can mean the age of frameworks is over. Java SE and J2EE have always been foundations for frameworks. The Java EE 6 features are often frameworks in themselves that can be used outside of a Java EE container. Furthermore, Java EE 6 doesn&apos;t provide all the features you need to build a high-scale web app today. There&apos;s no caching, no stateless web framework that can serve up JSON and HTML and no hot-reload productivity enhancements like JRebel. Furthermore, there&apos;s real excitement in Javaland for languages like Scala, Groovy and JRuby. All of these languages have web frameworks that&apos;ve made many developers happy. 
&lt;/p&gt;
&lt;p&gt;
Here&apos;s to the Age of Frameworks - may it live as long as the JVM!
&lt;/p&gt;
&lt;p style=&quot;padding-top: 5px; border-top: 1px dotted silver; color: #666&quot;&gt;
P.S. If you&apos;d like to hear me talk about web frameworks on the JVM, I&apos;ll be speaking at &lt;a href=&quot;http://www.meetup.com/csopensource/calendar/15088624/&quot; style=&quot;color: #666&quot;&gt;The Colorado Springs Open Source Meetup&lt;/a&gt; and &lt;a href=&quot;http://www.devoxx.com/display/Devoxx2K10/Comparing+JVM+Web+Frameworks&quot; style=&quot;color: #666&quot;&gt;Devoxx 2010&lt;/a&gt; in the near future.&lt;/p&gt;
&lt;p&gt;
&lt;!--p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; I am an independent consultant and don&apos;t have any affiliations with Java EE vendors. I do have an affection for open source frameworks, particularly Spring and web frameworks. This is because I&apos;ve seen them successfully implemented at high scale web sites such as LinkedIn, Evite and Time Warner Cable.&lt;/p--&gt; </content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/my_incredible_trip_to_ireland</id>
        <title type="html">My Incredible Trip to Ireland</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/my_incredible_trip_to_ireland"/>
        <published>2010-06-14T23:42:55-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="kalin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="guinness" scheme="http://roller.apache.org/ns/tags/" />
        <category term="irishsoftwareshow" scheme="http://roller.apache.org/ns/tags/" />
        <category term="johnwillis" scheme="http://roller.apache.org/ns/tags/" />
        <category term="dublin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="joshlong" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jameson" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jamievandyke" scheme="http://roller.apache.org/ns/tags/" />
        <category term="iss2010" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="glendalough" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ireland" scheme="http://roller.apache.org/ns/tags/" />
        <category term="dublinia" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;em&gt;If you ever get a chance to travel to Ireland, take it!&lt;/em&gt; I don&apos;t know when I heard these words, or how they came into my head, but I remembered them clearly when I was first introduced to &lt;a href=&quot;http://ie.linkedin.com/in/irishdev&quot;&gt;Barry Alistair&lt;/a&gt; by &lt;a href=&quot;http://www.linkedin.com/in/jgenender&quot;&gt;Jeff Genender&lt;/a&gt;. Soon after, I was able to negotiate my way into being a speaker at &lt;a href=&quot;http://epicenter.ie/2010.html&quot;&gt;The 2010 Irish Software Show&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
The show was last week and I had a blast traveling to Dublin to speak and explore. &lt;a href=&quot;http://twitter.com/kraible&quot;&gt;My sister&lt;/a&gt; came me on this trip, but missed a connection in Seattle and had to join me a day late.  I left Denver at noon on Monday and arrived at &lt;a href=&quot;http://www.dublinairport.com/&quot;&gt;Dublin Airport&lt;/a&gt; at 7 am. I was on the same flight as &lt;a href=&quot;http://www.joshlong.com/&quot;&gt;Josh Long&lt;/a&gt; and thoroughly enjoyed my iPad as a travel companion. When I got off the plane, my battery life was at 60% and I&apos;d been watching movies and listening to music for 6 hours. 
&lt;/p&gt;
&lt;p&gt;I took a cab through the misty, cool morning to &lt;a href=&quot;http://en.wikipedia.org/wiki/Trinity_Capital_Hotel&quot;&gt;my hotel&lt;/a&gt;. I grabbed a coffee, cleaned up, and walked a few blocks to &lt;a href=&quot;http://www.tcd.ie/&quot;&gt;Trinity College&lt;/a&gt; for the conference. I made it in time for the &lt;a href=&quot;http://epicenter.ie/2010.html?zone_id=19&amp;amp;mode=agenda&amp;amp;session=164%23session&quot;&gt;opening keynote&lt;/a&gt; by &lt;a href=&quot;http://chrisjhorn.wordpress.com&quot;&gt;Chris Horn&lt;/a&gt;. It was an interesting talk, focusing on what needed to happen to make Ireland the Innovation Hub of Europe. After that, I attended &lt;a href=&quot;http://augusttechgroup.com/tim/blog&quot;&gt;Tim Berglund&apos;s&lt;/a&gt; session on &lt;a href=&quot;http://epicenter.ie/2010.html?zone_id=19&amp;amp;mode=agenda&amp;amp;session=160%23session&quot;&gt;Complexity Theory and Software Development&lt;/a&gt;. After lunch and a few more talks, I teamed up with &lt;a href=&quot;http://www.jroller.com/aalmiray/&quot;&gt;Andres Almiray&lt;/a&gt; and Josh Long for a pint at the hotel bar.
&lt;/p&gt;
&lt;p&gt;That evening, we attended &lt;a href=&quot;http://www.linkedin.com/in/jgenender&quot;&gt;Jeff Genender&apos;s&lt;/a&gt; talk on &lt;a href=&quot;http://epicenter.ie/2010.html?zone_id=19&amp;amp;mode=agenda&amp;amp;session=189%23session&quot;&gt;Getting into Open Source&lt;/a&gt;. The free drinks loosened everyone up and Jeff did a great job with a humorous presentation on how to get Committer Status. After Jeff&apos;s talk, about 10 of us headed to a Moroccan restaurant for a late dinner. I was in bed around midnight.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm2.static.flickr.com/1297/4699497085_b551c7a58f.jpg&quot; title=&quot;Andres Almiray and Josh Long&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm2.static.flickr.com/1297/4699497085_b551c7a58f_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Andres Almiray and Josh Long&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4029/4699497659_19812e51bf.jpg&quot; title=&quot;The Genenders&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4029/4699497659_19812e51bf_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;The Genenders&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4049/4700126996_f29207d60c.jpg&quot; title=&quot;Heading for Indian After Jeff&apos;s Talk&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4049/4700126996_f29207d60c_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Heading for Indian After Jeff&apos;s Talk&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4070/4699498241_c076566b11.jpg&quot; title=&quot;Streets of Dublin in the early morning&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4070/4699498241_c076566b11_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Streets of Dublin in the early morning&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;
Wednesday morning, my sister arrived in my hotel room at 8 and promptly fell into bed. I set my alarm to sleep an hour and closed the Vegas-style, no-light-allowed curtains. We awoke much later (12:30) than we&apos;d planned (9:00). We quickly got up and headed for some sight-seeing in Dublin. First off, we hit &lt;a href=&quot;http://www.dublinia.ie/&quot;&gt;Dublinia&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Christ_Church_Cathedral,_Dublin&quot;&gt;Christ Church Cathedral&lt;/a&gt;. Both sites were spectacular and we both learned a lot about the history of Dublin. From there, we skipped across the bridge to &lt;a href=&quot;http://www.jamesonwhiskey.com/Heritage-US/Visitor-Centres/The-Old-Jameson-Distillery-Tour-Info.aspx&quot;&gt;The Old Jameson Distillery&lt;/a&gt; for a tour and a bit of whiskey. &lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4063/4699499527_602302bea9.jpg&quot; title=&quot;Runes Exhibit in Dublinia&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4063/4699499527_602302bea9_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Runes Exhibit in Dublinia&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4070/4700130192_25a9cfcf52.jpg&quot; title=&quot;Christ Church Cathedral and Dublinia&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4070/4700130192_25a9cfcf52_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Christ Church Cathedral and Dublinia&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4022/4699501899_b92347236e.jpg&quot; title=&quot;Tasting Whiskey&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4022/4699501899_b92347236e_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Tasting Whiskey&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm2.static.flickr.com/1279/4700131426_db95eb5c9b.jpg&quot; title=&quot;The 18 Year&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm2.static.flickr.com/1279/4700131426_db95eb5c9b_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;The 18 Year&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The picture below was taken on the &lt;a href=&quot;http://en.wikipedia.org/wiki/Ha%27penny_Bridge&quot;&gt;Ha&apos;penny Bridge&lt;/a&gt; as we were heading back from Jameson. The expression of the girl on the left is priceless. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4033/4700134408_d5f99cb5d0.jpg&quot; title=&quot;Kalin on the Half Penny&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4033/4700134408_d5f99cb5d0_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Kalin on the Half Penny&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;A couple hours later and I was delivering my talk on &lt;a href=&quot;http://raibledesigns.com/rd/entry/presentations_from_the_irish_software&quot;&gt;The Future of Web Frameworks&lt;/a&gt;. The crowd was lively; the Guinness I drank while talking was lovely. My session was followed by a Web Framework Experts Panel with &lt;a href=&quot;http://www.cacoethes.co.uk/blog/&quot;&gt;Peter Ledbrook&lt;/a&gt; (Grails), &lt;a href=&quot;http://www.jamievandyke.com/&quot;&gt;Jamie van Dyke&lt;/a&gt; (Rails), &lt;a href=&quot;http://www.ironshay.com/&quot;&gt;Shay Friedman&lt;/a&gt; (ASP.NET MVC), &lt;a href=&quot;http://blog.fitzell.ca/&quot;&gt;Julian Fitzell&lt;/a&gt; (Seaside) and myself (Java Frameworks). The debate was good and there was much discussion about the right apps for each framework and how important statelessness is for scalable applications. After 3 hours of talking, my sister and I headed back to the hotel. I was particularly happy about the evening since it was the first time a family member of mine had seen me speak.
&lt;/p&gt;
&lt;p style=&quot;font-style: italic; color: #666&quot; class=&quot;quote&quot;&gt;Correction from my Dad: This wasn&apos;t the first time a family member saw me speak. He attended my talk at &lt;a href=&quot;http://raibledesigns.com/rd/entry/what_a_trip_amsterdam_was&quot;&gt;ApacheCon EU 2007&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;A block from the hotel, we spotted a nice looking pub (&lt;a href=&quot;http://www.doylesintown.com/&quot;&gt;Doyles&lt;/a&gt;) and stopped in for a pint. As we bellied up to the end of the bar, we recognized Jamie (from the panel) and got introduced to his friend &lt;a href=&quot;http://yrobs.blogspot.com/&quot;&gt;Rob&lt;/a&gt;. We quickly got lost in conversation, stories and laughter and were surprised when we discovered it was 2:30am. Since I had a talk first thing in the morning, we ducked out shortly after.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4017/4699506393_3b1fedd531.jpg&quot; title=&quot;Web Framework Experts Panel&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4017/4699506393_3b1fedd531_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Web Framework Experts Panel&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4048/4700135162_f3099a46c4.jpg&quot; title=&quot;Barry on Evangelist Night&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4048/4700135162_f3099a46c4_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Barry on Evangelist Night&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4008/4700135912_6b71bcd50c.jpg&quot; title=&quot;The Night we met Jamie and Rob&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4008/4700135912_6b71bcd50c_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;The Night we met Jamie and Rob&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Thursday started with my talk &lt;a href=&quot;http://raibledesigns.com/rd/entry/presentations_from_the_irish_software&quot;&gt;Comparing Kick-Ass Web Frameworks&lt;/a&gt;. Then my sister and I did some more site-seeing, starting at the &lt;a href=&quot;http://www.guinness-storehouse.com/en/Index.aspx&quot;&gt;Guinness Storehouse&lt;/a&gt;. We met Josh and &lt;a href=&quot;http://www.johnmwillis.com/&quot;&gt;John Willis&lt;/a&gt; as they were leaving and they advised we go straight to The Gravity Bar at the top. We took there advise and were getting great views of Dublin and savoring sweet pints of Guinness moments later. The tour facility was freakin&apos; awesome and I loved how it was shaped like a pint glass. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4006/4699508311_77a05c609a.jpg&quot; title=&quot;Straight to the top!&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4006/4699508311_77a05c609a_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Straight to the top!&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4015/4699508737_612d1b1b42.jpg&quot; title=&quot;Mmmmm, Guinness&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4015/4699508737_612d1b1b42_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Mmmmm, Guinness&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4052/4700141820_3943b0dea6.jpg&quot; title=&quot;The Storehouse is shaped like a pint glass&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4052/4700141820_3943b0dea6_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;The Storehouse is shaped like a pint glass&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm2.static.flickr.com/1285/4700143032_120cd3d789.jpg&quot; title=&quot;Brainwave&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm2.static.flickr.com/1285/4700143032_120cd3d789_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Brainwave&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;
We grabbed some gear from the gift shopped and landed (by accident) at &lt;a href=&quot;http://www.brazenhead.com/&quot;&gt;The Brazen Head&lt;/a&gt; (Ireland&apos;s Oldest Pub, Est. 1198) for a pint of cider and Guinness. Since my sister &lt;a href=&quot;http://raibledesigns.com/rd/entry/chelan_hard_cider&quot;&gt;used to be in the cider business&lt;/a&gt;, she was particularly happy there was so much on tap in Ireland.
&lt;/p&gt;
&lt;p&gt;
From the pub, we headed to &lt;a href=&quot;http://www.johnmwillis.com/&quot;&gt;John Willis&apos;s&lt;/a&gt; session on &lt;a href=&quot;http://epicenter.ie/2010.html?zone_id=21&amp;amp;mode=agenda&amp;amp;session=157#session&quot;&gt;The Cambrian Cloud Explosion&lt;/a&gt;. Following John&apos;s session, we headed to the Speaker&apos;s Dinner for a very fun evening with the hosts and speakers of the conference.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4027/4700144746_2a6f095f07.jpg&quot; title=&quot;John Willis and Barry Alistair&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4027/4700144746_2a6f095f07_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;John Willis and Barry Alistair&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4053/4699515883_49068fc757.jpg&quot; title=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4053/4699515883_49068fc757_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4039/4700145482_9e809aa875.jpg&quot; title=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4039/4700145482_9e809aa875_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4067/4699516499_61333b6e25.jpg&quot; title=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4067/4699516499_61333b6e25_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4004/4699516869_9bdda79ac4.jpg&quot; title=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4004/4699516869_9bdda79ac4_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4022/4699517415_46575ba674.jpg&quot; title=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4022/4699517415_46575ba674_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4016/4700153542_a46fca1c58.jpg&quot; title=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4016/4700153542_a46fca1c58_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Speaker&apos;s Dinner at Irish Software Show 2010&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
On Friday, we woke up in the early afternoon and quickly decided the &lt;a href=&quot;http://en.wikipedia.org/wiki/Book_of_Kells&quot;&gt;Book of Kells&lt;/a&gt; was our best chance of getting some site seeing in. After visiting the Book of Kells, my favorite quote of the conference happened in the courtyard. 
&lt;/p&gt;
&lt;p&gt;
Josh looked at Jamie (with his bad hangover) and exclaimed, &quot;My God Man. Your skin is so white it&apos;s hurting my eyes!&quot;. You probably had to be there (or know Josh) to enjoy the humor, but I wanted to capture the memory in this post so I could laugh whenever I read this in the future. After that, Jamie, Josh, Kalin and I enjoyed a Starbuck&apos;s patio talking about living in the South of France for a couple hours. Then we walked 2 blocks to the &lt;a href=&quot;http://www.porterhousebrewco.com/&quot;&gt;Porterhouse Brewing Co.&lt;/a&gt; to watch the World Cup and enjoy more interesting conversations. 
&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4049/4699526381_b93c7d22a4.jpg&quot; title=&quot;The Book of Kells&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4049/4699526381_b93c7d22a4_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;The Book of Kells&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4025/4700168324_26c13c6b46.jpg&quot; title=&quot;Jamie with the Wenches&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4025/4700168324_26c13c6b46_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Jamie with the Wenches&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4066/4700168582_88b49c92c2.jpg&quot; title=&quot;Lovely Wenches&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4066/4700168582_88b49c92c2_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Lovely Wenches&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4006/4699540829_ca5481a452.jpg&quot; title=&quot;Jamie and his Lady Drink&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4006/4699540829_ca5481a452_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Jamie and his Lady Drink&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Jamie left the conference that evening and we joined a whole slew of other speakers for dinner at an excellent Lebanese restaurant near Temple Bar. Good times where had afterwards at a nearby Silent Disco.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4044/4700172766_b7b82c29b5.jpg&quot; title=&quot;Kalin and Craig&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4044/4700172766_b7b82c29b5_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Kalin and Craig&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4071/4699543397_e997b2b8ff.jpg&quot; title=&quot;Post Absinthe&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4071/4699543397_e997b2b8ff_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Post Absinthe&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Saturday, we woke up early to catch a tour bus out to &lt;a href=&quot;http://en.wikipedia.org/wiki/Glendalough&quot;&gt;Glendalough&lt;/a&gt; with Josh and John. The bus ride was not pleasant, but the destination was spectacular. We hung out there for several hours, exploring the buildings, walking to the lake and humoring each other.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4068/4700176486_aa86563fbf.jpg&quot; title=&quot;Glendalough&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4068/4700176486_aa86563fbf_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Glendalough&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm2.static.flickr.com/1287/4699547639_3904ddaaf1.jpg&quot; title=&quot;Beautiful Views at Glendalough&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm2.static.flickr.com/1287/4699547639_3904ddaaf1_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Beautiful Views at Glendalough&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4031/4700178148_23b6c2852a.jpg&quot; title=&quot;Glendalough&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4031/4700178148_23b6c2852a_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Glendalough&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4070/4699549013_40916ab088.jpg&quot; title=&quot;Lower Lake at Glendalough&quot; rel=&quot;lightbox[ireland2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4070/4699549013_40916ab088_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Lower Lake at Glendalough&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Our last night in Dublin was an early, relaxing one. As you can tell, I really enjoyed this trip, particularly hanging out with my sister and all the cool people we met. I can easily say that this trip registers as one of my favorite conference experiences to date.
&lt;/p&gt;
&lt;p style=&quot;border-top: 1px dotted silver; padding-top: 5px; color: #666&quot;&gt;
To see all the pictures I took on this trip, check out my &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157624148828777/&quot; style=&quot;color: #555&quot;&gt;Irish Software Show 2010 set on Flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/presentations_from_the_irish_software</id>
        <title type="html">My Presentations from The Irish Software Show 2010</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/presentations_from_the_irish_software"/>
        <published>2010-06-10T07:11:35-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="iss2010" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rubyonrails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="flex" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This week I&apos;ve been enjoying Dublin, Ireland thanks to the 2nd Annual &lt;a href=&quot;http://epicenter.ie/2010.html&quot;&gt;Irish Software Show&lt;/a&gt;. On Wednesday night, I spoke about &lt;a href=&quot;http://epicenter.ie/2010.html?zone_id=20&amp;amp;mode=agenda&amp;amp;session=152#session&quot;&gt;The Future of Web Frameworks&lt;/a&gt; and  participated in a panel with Grails, Rails, ASP.NET MVC and Seaside developers. It was a fun night with lots of lively discussion. Below is my presentation from this event.&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;&lt;object id=&quot;__sse3271151&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=thefutureofwebframeworks-100225012146-phpapp02&amp;amp;stripped_title=the-future-of-web-frameworks&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;&lt;embed name=&quot;__sse3271151&quot; src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=thefutureofwebframeworks-100225012146-phpapp02&amp;amp;stripped_title=the-future-of-web-frameworks&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;This morning, I delivered my &lt;a href=&quot;http://epicenter.ie/2010.html?zone_id=20&amp;amp;mode=agenda&amp;amp;session=151#session&quot;&gt;Comparing Kick-Ass Web Frameworks&lt;/a&gt; talk. This presentation contains updated statistics for various metrics comparing Rails vs. Grails and Flex vs. GWT. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object id=&quot;__sse2644393&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=comparingkickasswebframeworks-091203145644-phpapp02&amp;stripped_title=comparing-kick-ass-web-frameworks&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;&lt;embed name=&quot;__sse2644393&quot; src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=comparingkickasswebframeworks-091203145644-phpapp02&amp;stripped_title=comparing-kick-ass-web-frameworks&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;
Thanks to all who attended my talks this week!
&lt;/p&gt;
&lt;p style=&quot;border-top: 1px dotted silver; padding-top: 5px; color: #666&quot;&gt;
P.S. I believe audio was recorded on Wednesday night, but I&apos;m unsure how it turned out. I&apos;m pretty sure no recordings were done on this morning&apos;s session. 
&lt;/p&gt;&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/2009_a_year_in_review</id>
        <title type="html">2009 - A Year in Review</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/2009_a_year_in_review"/>
        <published>2010-01-11T10:06:09-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Roller" label="Roller" />
        <category term="2010" scheme="http://roller.apache.org/ns/tags/" />
        <category term="newyear" scheme="http://roller.apache.org/ns/tags/" />
        <category term="yearinreview" scheme="http://roller.apache.org/ns/tags/" />
        <category term="blogging" scheme="http://roller.apache.org/ns/tags/" />
        <category term="roller" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">I wrote my first &quot;year in review&quot; post in &lt;a href=&quot;http://raibledesigns.com/rd/entry/2005_a_year_in_review&quot;&gt;2005&lt;/a&gt; and continued the tradition in &lt;a href=&quot;http://raibledesigns.com/rd/entry/2006_a_year_in_review&quot;&gt;2006&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/2008_a_year_in_review&quot;&gt;2008&lt;/a&gt;. This year, my December was filled with &lt;a href=&quot;http://twitter.com/mraible/status/6376757616&quot; title=&quot;Arrived home to the sound of a waterfall. Water pipes burst in guest room. Doh!&quot;&gt;unplanned circumstances&lt;/a&gt;, a new job and a houseful of family for the holidays, so I never had time to sit down and write this post. As things are returning to normal, I figured it&apos;s about time I kicked off 2010 with one of my favorite writing reflections.
&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;http://farm4.static.flickr.com/3099/3218234204_c8a83629c6.jpg&quot; title=&quot;Experts Only&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3099/3218234204_c8a83629c6_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Experts Only&quot; class=&quot;picture&quot; /&gt;&lt;/a&gt;
2009 started off with a bang: I wrote about my Mom &lt;a href=&quot;http://raibledesigns.com/rd/entry/happy_birthday_mom&quot;&gt;nailing a bear&apos;s nuts to a tree after she killed it&lt;/a&gt;. My new gig (at Evite) started out fun with &lt;a href=&quot;http://raibledesigns.com/rd/entry/choosing_an_ajax_framework&quot;&gt;choosing an Ajax framework&lt;/a&gt; and a &lt;a href=&quot;http://raibledesigns.com/rd/entry/la_tech_meetup_tonight&quot;&gt;Tech Meetup in LA&lt;/a&gt;. My &lt;a href=&quot;http://raibledesigns.com/rd/entry/r_i_p_giant_fcr3&quot;&gt;bike got stolen&lt;/a&gt;, I started &lt;a href=&quot;http://raibledesigns.com/rd/entry/running_to_work&quot;&gt;running to work&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/traveling_to_tahoe_without_a&quot;&gt;traveled to Tahoe without an ID&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;
February started off with an &lt;a href=&quot;http://raibledesigns.com/rd/entry/epic_weekend_at_silverton_mountain&quot;&gt;epic weekend at Silverton&lt;/a&gt;. I went to &lt;a href=&quot;http://north09.webdirections.org/&quot;&gt;Web Directions North&lt;/a&gt; and attended many good talks:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/changes_in_the_languages_of&quot;&gt;Changes in the Languages of The Web&lt;/a&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/the_state_of_the_web&quot;&gt;The State of the Web 2009&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/ajax_the_state_of_the&quot;&gt;Ajax: The State of the Art&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wrote my first &lt;a href=&quot;http://raibledesigns.com/rd/entry/testing_gwt_applications&quot; title=&quot;Testing GWT Applications&quot;&gt;GWT-related entry&lt;/a&gt; and a few posts related to independent consulting.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/how_to_setup_your_own&quot;&gt;How To Setup Your Own Software Development Company&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/writing_off_home_office_space&quot;&gt;Writing Off Home Office Space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/what_s_the_best_retirement&quot;&gt;What&apos;s the Best Retirement Plan for Independent Consultants?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I ended February with a &lt;a href=&quot;http://raibledesigns.com/rd/entry/enhancing_your_gwt_application_with&quot; title=&quot;Enhancing your GWT Application with the UrlRewriteFilter&quot;&gt;couple&lt;/a&gt; &lt;a href=&quot;http://raibledesigns.com/rd/entry/gwttestsuite_makes_builds_faster_but&quot; title=&quot;GWTTestSuite makes builds faster, but requires JUnit 4.1&quot;&gt;more&lt;/a&gt; GWT-related entries.
&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;http://farm4.static.flickr.com/3658/3343506648_caa24e1d39.jpg&quot; title=&quot;On the top&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3658/3343506648_caa24e1d39_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;On the top&quot; class=&quot;picture&quot;/&gt;&lt;/a&gt;

In March, I bought a &lt;a href=&quot;http://raibledesigns.com/rd/entry/new_15_macbook_pro_with&quot;&gt;new 15&quot; MacBook Pro&lt;/a&gt; and shipped it back shortly after to get a 256 GB SSD. I still have nothing but good things to say about the machine. I discovered &lt;a href=&quot;http://raibledesigns.com/rd/entry/nexus_is_a_kick_ass&quot;&gt;Nexus is awesome&lt;/a&gt; and the kids and I went on our &lt;a href=&quot;http://raibledesigns.com/rd/entry/1st_hike_of_2009&quot;&gt;first hike of the year&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;My GWT Journey continued with &lt;a href=&quot;http://raibledesigns.com/rd/entry/gxt_s_mvc_framework&quot;&gt;GXT MVC&lt;/a&gt;, &lt;a href=&quot;http://raibledesigns.com/rd/entry/modularizing_gwt_applications_with_gwt&quot;&gt;modularization&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/optimizing_a_gwt_application_with&quot;&gt;optimization&lt;/a&gt;. I got a &lt;a href=&quot;http://raibledesigns.com/rd/entry/new_office_and_new_bike&quot;&gt;new office and new bike&lt;/a&gt; and proudly witnessed my &lt;a href=&quot;http://raibledesigns.com/rd/entry/congratulations_on_retiring_dad&quot;&gt;Dad&apos;s Retirement&lt;/a&gt;.&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;April came and I &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_drunk_on_software_interview&quot;&gt;got Drunk on Software&lt;/a&gt;, had a blast at &lt;a href=&quot;http://raibledesigns.com/rd/entry/jason_and_holly_s_wedding&quot;&gt;Holly and Jason&apos;s Wedding&lt;/a&gt; and published our &lt;a href=&quot;http://raibledesigns.com/rd/entry/ajax_framework_analysis_results&quot;&gt;Ajax Framework Analysis Results&lt;/a&gt;. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm4.static.flickr.com/3545/3461916124_11582cee7c.jpg&quot; title=&quot;Mr. and Mrs. Harris&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3545/3461916124_11582cee7c_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Mr. and Mrs. Harris&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;At the end of April, I started &lt;a href=&quot;http://raibledesigns.com/rd/entry/life_update_new_treehouse_new&quot;&gt;building the kids a treehouse and inspired smiles with two new kittens&lt;/a&gt;. On May 7th, I had PRK eye surgery and &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_eye_surgery_experience&quot;&gt;wrote about my experience in early June&lt;/a&gt;. I continue to be extremely happy with the results.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm4.static.flickr.com/3656/3471565132_7a5e4ebdb2.jpg&quot; title=&quot;Day 3 - They love it!&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3656/3471565132_7a5e4ebdb2_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Day 3 - They love it!&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3545/3470751035_d016beb0d9.jpg&quot; title=&quot;Day 4 - Floor completed&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3545/3470751035_d016beb0d9_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Day 4 - Floor completed&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3360/3505899171_3cb4e849b1.jpg&quot; title=&quot;Jack and Olivia&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3360/3505899171_3cb4e849b1_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Jack and Olivia&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3562/3506709142_21fa103252.jpg&quot; title=&quot;Abbie and Mittens&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3562/3506709142_21fa103252_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Abbie and Mittens&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;May ended with &lt;a href=&quot;http://raibledesigns.com/rd/entry/ryan_and_breanne_s_wedding&quot;&gt;Ryan and Breanne&apos;s Wedding in Playa Del Carmen&lt;/a&gt;. Having so many great friends around and the Nuggets vs. Lakers playoffs the same week made this one of the best vacations of my life.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm4.static.flickr.com/3618/3580803902_449464cf49.jpg&quot; title=&quot;Ready for the Ceremony&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3618/3580803902_449464cf49_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Ready for the Ceremony&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3644/3579992115_05c0cb7b7f.jpg&quot; title=&quot;Vows&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3644/3579992115_05c0cb7b7f_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Vows&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3153/3580823360_3e2e997894.jpg&quot; title=&quot;Mariachi Band&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3153/3580823360_3e2e997894_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Mariachi Band&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3374/3580011379_fa403528cb.jpg&quot; title=&quot;Mr. and Mrs. Johnson&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3374/3580011379_fa403528cb_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Mr. and Mrs. Johnson&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;June brought the news that the &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_end_of_colorado_software&quot;&gt;Colorado Software Summit was over&lt;/a&gt;. There&apos;s been several times in the past few months that I&apos;ve missed the annual experience. Can someone please start a conference at a Colorado mountain resort in the near future? Pretty please! I&apos;ve always experienced this conference with &lt;a href=&quot;http://bsnyderblog.blogspot.com/&quot;&gt;Bruce&lt;/a&gt; and we continued another tradition (riding to Red Rocks) with &lt;a href=&quot;http://raibledesigns.com/rd/entry/2nd_row_at_red_rocks&quot;&gt;2nd Row seats at Big Head Todd&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;My GWT posts continued with a &lt;a href=&quot;http://raibledesigns.com/rd/entry/creating_a_facebook_style_autocomplete&quot;&gt;Facebook-style Autocomplete&lt;/a&gt;, &lt;a href=&quot;http://raibledesigns.com/rd/entry/implementing_oauth_with_gwt&quot;&gt;Implementing OAuth&lt;/a&gt;, &lt;a href=&quot;http://raibledesigns.com/rd/entry/json_parsing_with_javascript_overlay&quot;&gt;JSON Parsing with JavaScript Overlays&lt;/a&gt; and a preview of &lt;a href=&quot;http://raibledesigns.com/rd/entry/how_to_use_gwt_2&quot;&gt;GWT 2.0&lt;/a&gt;. I wrote about &lt;a href=&quot;http://raibledesigns.com/rd/entry/enhancing_evite_com_with_gwt&quot;&gt;implementing SOFEA with GWT and Grails at Evite.com&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/a_fun_father_s_day&quot;&gt;had a blast at the Great Sand Dunes on Father&apos;s Day&lt;/a&gt;. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm3.static.flickr.com/2461/3655577467_c84ac6e9d7.jpg&quot; title=&quot;Abbie and Cookie at The Dunes&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2461/3655577467_c84ac6e9d7_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Abbie and Cookie at The Dunes&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
My &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_good_ol_job_hunt1&quot;&gt;job hunt&lt;/a&gt; began and I started a month-long vacation in Montana with &lt;a href=&quot;http://raibledesigns.com/rd/entry/raible_road_trip_13&quot;&gt;Raible Road Trip #13&lt;/a&gt;. Vacationing for a summer month in Montana has been one of my goals for several years. Accomplishing it this year made me extremely happy and I hope to make it a summer tradition.&lt;/p&gt;
&lt;p&gt;July was an awesome month in 2009. Granted, April and May were special with tropical weddings, but Montana in July is a particularly tasty treat. &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_summer_vacation_in_montana&quot;&gt;My Summer Vacation in Montana&lt;/a&gt; attempts to capture how much fun we had. It was particularly enjoyable because my parents, children and many life-long friends were involved.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm3.static.flickr.com/2568/3769250242_a002f5d6cb.jpg&quot; title=&quot;View of the Missions from Holland Falls&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2568/3769250242_a002f5d6cb_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;View of the Missions from Holland Falls&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm3.static.flickr.com/2431/3769250820_19d03c599b.jpg&quot; title=&quot;Ready for the Celebrate the Swan Race&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2431/3769250820_19d03c599b_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Ready for the Celebrate the Swan Race&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3293/3769258046_9613fca22c.jpg&quot; title=&quot;Horseshoes&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3293/3769258046_9613fca22c_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Horseshoes&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3612/3768465807_39e1cf17f6.jpg&quot; title=&quot;Floor Pouring Crew&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3612/3768465807_39e1cf17f6_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Floor Pouring Crew&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
As summer began to set, I decided to get back into speaking at conferences, starting with the &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_2009_rich_web_experience&quot;&gt;Rich Web Experience&lt;/a&gt;. I wrote about &lt;a href=&quot;http://raibledesigns.com/rd/entry/how_to_do_cross_domain&quot; title=&quot;How to do cross-domain GWT RPC with a ProxyServlet&quot;&gt;initial&lt;/a&gt; &lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_gwt_with_spring_security&quot; title=&quot;Integrating GWT with Spring Security&quot;&gt;GWT&lt;/a&gt; &lt;a href=&quot;http://raibledesigns.com/rd/entry/browser_based_username_password_autocomplete&quot; title=&quot;My attempt at browser-based username/password autocomplete with GWT&quot;&gt;work&lt;/a&gt; at my &lt;a href=&quot;http://chordiant.com/&quot; title=&quot;Chordiant Software&quot;&gt;new client&lt;/a&gt;, which included an interesting &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_experience_with_java_rest&quot; title=&quot;My Experience with Java REST Frameworks (specifically Jersey and CXF)&quot;&gt;experience with Java REST Frameworks&lt;/a&gt;. The month ended with one of my favorite holidays: &lt;a href=&quot;http://raibledesigns.com/rd/entry/happy_birthday_jack3&quot;&gt;Jack&apos;s Birthday&lt;/a&gt;.

&lt;/p&gt;
&lt;p&gt;September was nice and uneventful. I learned about &lt;a href=&quot;http://raibledesigns.com/rd/entry/concurrency_on_the_jvm_using&quot; title=&quot;Concurrency on the JVM Using Scala with Venkat Subramaniam&quot;&gt;Concurrency on the JVM Using Scala&lt;/a&gt;, started using &lt;a href=&quot;http://raibledesigns.com/rd/entry/building_gwt_applications_with_mvp&quot; title=&quot;Building GWT Applications with MVP and Issues with Overlay Types&quot;&gt;MVP with GWT&lt;/a&gt; and learned how to &lt;a href=&quot;http://raibledesigns.com/rd/entry/lean_teams_doing_more_with&quot; title=&quot;Lean Teams: Doing more with less (Derailed)&quot;&gt;do more with less&lt;/a&gt;. I also ran in a &lt;a href=&quot;http://www.fansonthefield.com/&quot;&gt;10K&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;October started out with a family trip to Washington for &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_sister_s_fabulous_wedding&quot;&gt;my sister&apos;s fabulous wedding&lt;/a&gt;. People flew in from all over the US and we had a sweet condo on Lake Chelan for the week. Playing golf, wine tasting and celebrating with good people made for a great start to the fall season.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm3.static.flickr.com/2537/4142221061_af166b8b3b.jpg&quot; title=&quot;Kalin and Mya&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2537/4142221061_af166b8b3b_m.jpg&quot; width=&quot;240&quot; height=&quot;160&quot; alt=&quot;Kalin and Mya&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;http://farm3.static.flickr.com/2737/4104358666_a4628d6e38.jpg&quot; title=&quot;Abbie and Charles&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2737/4104358666_a4628d6e38_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Abbie and Charles&quot; class=&quot;picture&quot; /&gt;&lt;/a&gt;
In November, I started writing more, mostly because I was gearing up for &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_future_of_web_frameworks&quot; title=&quot;The Future of Web Frameworks at TSSJS&quot;&gt;upcoming&lt;/a&gt; &lt;a href=&quot;http://raibledesigns.com/rd/entry/consulting_sofea_grails_and_gwt&quot; title=&quot;Building SOFEA Applications with GWT and Grails&quot;&gt;talks&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/a_letter_to_the_appfuse&quot; title=&quot;A Letter to the AppFuse Community&quot;&gt;thinking about&lt;/a&gt; / &lt;a href=&quot;http://raibledesigns.com/rd/entry/appfuse_2_1_milestone_1&quot; title=&quot;AppFuse 2.1 Milestone 1 Released&quot;&gt;working on AppFuse&lt;/a&gt;. I celebrated &lt;a href=&quot;http://raibledesigns.com/rd/entry/happy_birthday_abbie5&quot;&gt;Abbie&apos;s Birthday&lt;/a&gt;, did some &lt;a href=&quot;http://raibledesigns.com/rd/entry/javascript_and_css_concatenation&quot;&gt;website&lt;/a&gt; &lt;a href=&quot;http://raibledesigns.com/rd/entry/adding_expires_headers_with_oscache&quot;&gt;optimization&lt;/a&gt; and chuckled at the comments about my &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_hunting_season_adventure_at&quot;&gt;hunting season adventure&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Right before Thanksgiving, I got a call from my client letting me know that their budget had run out my contract would end soon. Luckily, I had an interview setup the next day and had great success in finding a new gig.&lt;/p&gt;
&lt;p&gt;I ended November with a trip to Oregon for Thanksgiving and ran in the &lt;a href=&quot;http://www.omroadrace.org/&quot;&gt;Oregon Mid-Valley Road Race&lt;/a&gt;. The followed week, I flew with my kids and parents to The Rich Web Experience and learned about &lt;a href=&quot;http://raibledesigns.com/rd/entry/introduction_to_objective_j_and&quot;&gt;Objective-J and Cappuccino&lt;/a&gt;. I had a near-perfect (high 70s, no lines) Disney World experience with my family, watched the Ducks with the &lt;a href=&quot;http://en.wikipedia.org/wiki/Civil_War_%28college_football_game%29&quot;&gt;Civil War&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/comparing_kick_ass_web_frameworks&quot;&gt;compared kick-ass web frameworks&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm3.static.flickr.com/2767/4253979011_4bc9a5e350.jpg&quot; title=&quot;Kids at Loews Portofino, Universal Studios Florida&quot; rel=&quot;lightbox[2009yearinreview]&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2767/4253979011_4bc9a5e350_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Kids at Loews Portofino, Universal Studios Florida&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;In December, I didn&apos;t do much blogging - mostly because I arrived home from Florida to discover a waterfall in my guest room. The water pipes were routed through the ceiling, had &lt;a href=&quot;http://twitpic.com/s9xo9&quot;&gt;busted from the cold&lt;/a&gt;, and water was pouring everywhere. Dealing with that and starting a new job occupied most of my time and I never got a chance to write much down. I ran in the &lt;a href=&quot;http://www.arthritis.org/jingle-bell-run.php&quot;&gt;Jingle Bell 5K&lt;/a&gt; and watched the Broncos lose a lot. Shortly after, my family came for Christmas and a good time was had by all.
&lt;/p&gt;
&lt;p&gt;As I reflect back on last year, my biggest surprise is that I got into running. I ended up running in 5 races last year and even enjoyed doing it a few times. It&apos;s still not my favorite activity (skiing and mountain biking win that title), but I enjoy it enough to do it a couple times each week. The goals I wrote down for last year were: visit 3 foreign countries, take 3 months of vacation and spend 1 month in Montana. I only made it to 1 foreign country (Mexico), but I did take 2 months of vacation and got my month in Montana. I&apos;ll take that.&lt;/p&gt;
&lt;p&gt;In 2010, I hope to speak at (or attend) 3 conferences, finish up The Bus and do a whole bunch of skiing and mountain biking. More than anything, I plan to continue having a lot of fun with my family and implementing a lot of cool technologies along the way. &lt;/p&gt;
&lt;p&gt;It&apos;s gonna be a great year.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/introduction_to_objective_j_and</id>
        <title type="html">Introduction to Objective-J and Cappuccino with Tom Robinson</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/introduction_to_objective_j_and"/>
        <published>2009-12-03T11:21:59-07:00</published>
        <updated>2009-12-03T18:42:43-07:00</updated> 
        <category term="/The Web" label="The Web" />
        <category term="tlrobinson" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javascript" scheme="http://roller.apache.org/ns/tags/" />
        <category term="dom" scheme="http://roller.apache.org/ns/tags/" />
        <category term="objectivej" scheme="http://roller.apache.org/ns/tags/" />
        <category term="richwebexperience" scheme="http://roller.apache.org/ns/tags/" />
        <category term="richweb" scheme="http://roller.apache.org/ns/tags/" />
        <category term="280north" scheme="http://roller.apache.org/ns/tags/" />
        <category term="cappuccino" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This morning, I attended &lt;a href=&quot;http://tlrobinson.net/&quot;&gt;Tom Robinson&apos;s&lt;/a&gt; talk on &lt;a href=&quot;http://www.therichwebexperience.com/conference/orlando/2009/12/session?id=15958&quot;&gt;Objective-J and Cappuccino&lt;/a&gt;. Tom is one of the founders of &lt;a href=&quot;http://280north.com/&quot;&gt;280 North&lt;/a&gt; and creators of the &lt;a href=&quot;http://cappuccino.org/&quot;&gt;Cappuccino framework&lt;/a&gt; and Objective-J language, so I was very interested in hearing about Cappuccino from &lt;em&gt;the source&lt;/em&gt;. The text below are my notes, but they&apos;re also mostly Tom&apos;s words, not mine. I&apos;ve added a &quot;Thoughts&quot; section at the end that are my words.&lt;/p&gt;
&lt;p&gt;Tom&apos;s Team was Cocoa programmers before they started building Cappuccino. They wanted to focus on building Desktop Class Web Applications (for example, Google Maps, Meebo and 280 Slides). Tom showed a  demo of 280 Slides and how it can rotate and scale images very easily, something you don&apos;t often see in web applications. 
&lt;/p&gt;
&lt;p&gt;
To build desktop class web applications, you can use Flash or Silverlight, but they&apos;re controlled by Adobe and Microsoft. Also, they have no iPhone support and poor Mac and Linux performance. The other option is JavaScript + DOM. They&apos;re open standards, available almost everywhere (including mobile devices) and its a very rich ecosystem with lots of competition. The downside to JavaScript is standards bodies, many incompatibilities, technical limitations (e.g. can&apos;t access web cam) and the DOM is very document-centric.
&lt;/p&gt;
&lt;p&gt;The bottom line is we can&apos;t fix Flash, but we can fix JavaScript. 
&lt;/p&gt;
&lt;p&gt;
This is what 280 North is trying to do with Objective-J. It&apos;s a proper superset of JavaScript, has a few syntax additions, has a powerful runtime and is implemented &lt;em&gt;in&lt;/em&gt; JavaScript. Objective-J is analogous to Objective-C. It adds to JavaScript like Objective-C adds to C. &lt;/p&gt;
&lt;p&gt;One of the first things Objective-J adds is Dependency Management. You can import from search paths:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@import &amp;lt;Foundation/CPObject.j&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Or from relative paths:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@import &quot;ApplicationController.j&quot;
&lt;/pre&gt;
&lt;p&gt;@import prevents duplicate loads has asynchronous downloading and synchronous execution. That means all files are downloaded before evaluation begins, but to the programmer, it seems to happen synchronously.&lt;/p&gt;
&lt;p&gt;The thing that sets Cappuccino apart from other libraries is its inheritance model. It uses  classical OO inheritance (using Objective-C syntax).
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@implementation Person : CPObject {
    String firstName @accessors;
    String lastName @accessors;
}

- (String) fullName {
    return firstName + lastName;
}

@end
&lt;/pre&gt;
&lt;p&gt;The type definitions (String) are ignored for now and primarily used for documentation. In the future, they plan to add optional static typing, hence the reason for having them. Tom is unsure if you can leave off the String type or if the compiler requires it.&lt;/p&gt;
&lt;p&gt;@implementation has proper support for &lt;code&gt;super&lt;/code&gt; and language syntax support. One of the reasons they chose Objective-C is because classical inheritance works great for UI Frameworks. &lt;/p&gt;
&lt;p&gt;Objective-J uses &quot;send a message&quot; syntax instead of &quot;call a method&quot; syntax. In the code snippets below, the first line is JavaScript, the second is Objective-J:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
object.method()
[object method]

object.methodWithFoot(arg1)
[object methodWithFoo:arg1]

object.methodWithFooBar(arg1, arg2)
[object methodWithFoo:arg1 bar:arg2]
&lt;/pre&gt;
&lt;p&gt;Dynamic Dispatch is one of the most interesting parts of Objective-J. &lt;em&gt;forwardInvocation&lt;/em&gt; in Objective-C is like &lt;em&gt;method_missing&lt;/em&gt; in Ruby. Methods can be used as references, for example:
&lt;/p&gt;
&lt;pre&gt;
var action = @selector(someMethod:);
&lt;/pre&gt;
&lt;p&gt;Runtime mutability is important for KeyValueCoding (KVC) and KeyValueObserving (KVO). KVC allows you to swap classes at runtime and KVO allows you to listen for when property values change. At runtime, a $KVO_ClassName is generated. This class notifies any registered observers when values are changed and then calls the original class to change the property.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cappuccino&lt;/strong&gt;&lt;br/&gt;
Cappuccino is an application framework, not a library. It uses the &lt;em&gt;Hollywood Principle&lt;/em&gt;: &quot;Don&apos;t call us, we&apos;ll call you&quot;. 
&lt;/p&gt;
&lt;p&gt;
The Framework handles document management (open, save, revert), content editing (undo, redo, copy, paste) and graphics manipulation. The DOM is designed for documents (same is true for HTML and CSS). Tom doesn&apos;t like the DOM as its not a good API for building applications. Proof is all the JavaScript libraries built to make the DOM better. &lt;/p&gt;
&lt;p&gt;Cappuccino has an MVC framework and CPView is its View. It&apos;s analogous to a &amp;lt;div&amp;gt; and represents a rectangle on the screen. Everything visible is a CPView or one of its subclasses. It defines resizing and layout behavior. CoreGraphics is Cappuccino&apos;s canvas-like drawing API. It uses VML on IE, canvas on everything else. &lt;/p&gt;
&lt;p&gt;Very little of the code in Cappuccino talks to the DOM (less than 2%). It&apos;s not just about providing widgets that work in all browsers, it&apos;s a way to write platform independent display code. &lt;/p&gt;
&lt;p&gt;Events are done very differently than most JavaScript libraries. Browser&apos;s dispatching is not used. A single event listener is registered for each type of event on the window. These events are captured and sent to the objects that need to know about them. This allows for consistent events across all browsers, even keyboard events. It also allows for creating custom event flows and easily creating custom events. Cappuccino events allow you to get around a common problem with DOM Events where you can&apos;t click on overlapping rectangles.&lt;/p&gt;
&lt;p&gt;Notifications can be registered and sent very easily. Both &quot;scoped&quot; and private notifications can be created.&lt;/p&gt;
&lt;p&gt;Undo Management is included in Cappuccino. It manages a stack of undos for you. Redos are &quot;free&quot; and undo functionality is part of the document architecture. This makes it easy to integrate with auto-save functionality.&lt;/p&gt;
&lt;p&gt;Run loops (also called event loops) are an advanced feature of Cappuccino. They allow you to perform actions on every run loop. This enables complex optimizations for DOM/Graphic operations and undo grouping. &lt;/p&gt;
&lt;p&gt;The final part of Cappuccino is Keyed Archiving. Keyed Archiving stores a graph of Objective-J objects. It handles reference cycles, conditional inclusions, has an efficient data format and works on the client and server (Objective-J can be run on the server). The data format is similar like binary, but it&apos;s UTF-8. Keyed Archiving is used for archiving views and used heavily in &lt;a href=&quot;http://280slides.com/&quot;&gt;280 Slides&lt;/a&gt; for storing, retrieving, and exporting presentations. 
&lt;/p&gt;
&lt;p&gt;Other applications implemented with Cappuccino include &lt;a href=&quot;http://almost.at&quot;&gt;almost.at&lt;/a&gt; 
and &lt;a href=&quot;http://gomockingbird.com&quot;&gt;Mockingbird&lt;/a&gt;. &lt;a href=&quot;http://enstore.com&quot;&gt;EnStore&lt;/a&gt; uses it too, but only for its admin interface.&lt;/p&gt;
&lt;p&gt;An interesting extension for Rails developers is &lt;a href=&quot;http://github.com/nciagra/Cappuccino-Extensions/tree/master/CPActiveRecord/&quot;&gt;CPActiveRecord&lt;/a&gt;, a reimplementation of Rails&apos; ActiveRecord in Cappuccino.
&lt;/p&gt;
&lt;p&gt;There are several tools included with Cappuccino:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;objj: command line Objective-J&lt;/li&gt;
&lt;li&gt;objcc: &quot;compile&quot; ahead of time&lt;/li&gt;
&lt;li&gt;press: optimize code and resources&lt;/li&gt;
&lt;li&gt;nib2cib: convert Mac OS X nibs&lt;/li&gt;
&lt;li&gt;capp: project creation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All these tools are built on &lt;a href=&quot;http://github.com/tlrobinson/narwhal&quot;&gt;Narwhal&lt;/a&gt; (which conforms to the CommonJS standard).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CommonJS&lt;/strong&gt;&lt;br/&gt;
&lt;a href=&quot;http://wiki.commonjs.org/wiki/CommonJS&quot;&gt;CommonJS&lt;/a&gt; is an effort among server-side JavaScript projects to standardize non-browser JavaScript APIs. There&apos;s numerous API specifications (so far):
&lt;ul&gt;
&lt;li&gt;Binary, File, IO&lt;/li&gt;
&lt;li&gt;stdin, stdout, stderr, args, env&lt;/li&gt;
&lt;li&gt;Web server gateway (&lt;a href=&quot;http://jackjs.org/jsgi-spec.html&quot;&gt;JSGI&lt;/a&gt;) - similar to &lt;a href=&quot;http://wsgi.org/wsgi/&quot;&gt;WSGI&lt;/a&gt; and &lt;a href=&quot;http://rack.rubyforge.org/&quot;&gt;Rack&lt;/a&gt; for Python and Ruby&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To learn more about CommonJS, see &lt;a href=&quot;http://arstechnica.com/web/news/2009/12/commonjs-effort-sets-javascript-on-path-for-world-domination.ars&quot;&gt;CommonJS effort sets JavaScript on path for world domination&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Narwhal is 280 North&apos;s implementation of CommonJS APIs. It works with multiple JavaScript engines, including Rhino, JavaScriptCore (SquirrelFish) and XUL Runner. According to Tom, Rhino is an order of magnitude slower than JavaScriptCore and V8. Of course, Narwhal supports Objective-J too.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Aristo&lt;/strong&gt;&lt;br/&gt;
Aristo is the new default theme in Cappuccino and was created by the &lt;a href=&quot;http://www.madebysofa.com/&quot;&gt;Sofa&lt;/a&gt; design firm. It includes windows, tabs and menus and is &lt;a href=&quot;http://wiki.github.com/280north/aristo&quot;&gt;open source&lt;/a&gt; so you can modify. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Atlas&lt;/strong&gt;&lt;br/&gt;
Atlas is an IDE for Cappuccino, focused on building user interfaces graphically. Atlas is a downloadable application for OS X. It&apos;s written almost entirely in Cappuccino. The desktop version bridges Cappuccino windows to native windows. Tom did a demo of Atlas and showed how its layout feature allows you pin, center and align very easily. It&apos;s all done with JavaScript because doing layouts with CSS is often very painful. After that, he showed us how can you Atlas to very easily build a Web Application and then export it as a native OS X application without changing a line of code. Atlas includes Mozilla&apos;s &lt;a href=&quot;https://bespin.mozilla.com/&quot;&gt;Bespin&lt;/a&gt; for code editing. &lt;/p&gt;
&lt;p&gt;
&lt;p&gt;To learn more about Aristo and Atlas, you might want to checkout Ajaxian&apos;s &lt;a href=&quot;http://ajaxian.com/archives/big-news-from-cappuccino-aristo-and-atlas&quot;&gt;Big News from Cappuccino: Aristo and Atlas&lt;/a&gt; from earlier this year.&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://280atlas.com&quot;&gt;Atlas&lt;/a&gt; has a $20 &lt;a href=&quot;https://atlas-beta.heroku.com/users/new&quot;&gt;Beta Program&lt;/a&gt; if you&apos;re interested in trying it out.&lt;/p&gt;
&lt;p style=&quot;border-top: 1px dotted silver; padding-top: 10px&quot;&gt;
&lt;strong&gt;My Thoughts&lt;/strong&gt;&lt;br/&gt;
Cappuccino looks like a very cool web framework. It reminds me of GWT in that you have to learn a new language to use it. However, Atlas takes a lot of that pain away. I particularly like how it has document and undo/redo support built-in. On my current GWT project, this would be very useful as we&apos;ve had to build this functionality by hand. </content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/appfuse_2_1_milestone_1</id>
        <title type="html">AppFuse 2.1 Milestone 1 Released</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/appfuse_2_1_milestone_1"/>
        <published>2009-11-19T07:16:36-07:00</published>
        <updated>2014-05-08T19:47:26-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tapestry" scheme="http://roller.apache.org/ns/tags/" />
        <category term="archetypes" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse-light" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="freemarker" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="wicket" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="stripes" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="hibernate" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java5" scheme="http://roller.apache.org/ns/tags/" />
        <category term="myfaces" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ibatis" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jpa" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;a href=&quot;http://appfuse.org&quot;&gt;&lt;img src=&quot;//appfuse.dev.java.net/images/icon.gif&quot; class=&quot;picture&quot; style=&quot;border: 0&quot;&gt;&lt;/a&gt;
The AppFuse Team is pleased to announce the first milestone release of AppFuse 2.1. This release includes upgrades to all dependencies to bring them up-to-date with their latest releases. Most notable are &lt;a href=&quot;http://raibledesigns.com/rd/entry/upgrading_hibernate_to_3_4&quot;&gt;Hibernate&lt;/a&gt;, &lt;a href=&quot;http://raibledesigns.com/rd/entry/moving_from_spring_s_xml&quot;&gt;Spring&lt;/a&gt; and Tapestry 5. 
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is AppFuse?&lt;/strong&gt;&lt;br/&gt;
AppFuse is an open source project and application that uses open source tools built on the Java platform to help you develop Web applications quickly and efficiently. It was originally developed to eliminate the ramp-up time found when building new web applications for customers. At its core, AppFuse is a project skeleton, similar to the one that&apos;s created by your IDE when you click through a wizard to create a new web project.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Release Details&lt;/strong&gt;&lt;br/&gt;
&lt;a href=&quot;http://static.appfuse.org/archetypes.html&quot;&gt;Archetypes&lt;/a&gt; now include all the source for the web modules so using &lt;em&gt;jetty:run&lt;/em&gt; and your IDE will work much smoother now. The backend is still embedded in JARs, enabling you to choose which persistence framework (Hibernate, iBATIS or JPA) you&apos;d like to use. If you want to modify the source for that, &lt;a href=&quot;http://appfuse.org/display/APF/AppFuse+Core+Classes&quot;&gt;add the core classes to your project&lt;/a&gt; or run &lt;em&gt;appfuse:full-source&lt;/em&gt;. 
&lt;/p&gt;
&lt;p&gt;
In addition, AppFuse Light has been &lt;a href=&quot;http://raibledesigns.com/rd/entry/appfuse_light_converted_to_maven&quot;&gt;converted to Maven&lt;/a&gt; and has archetypes available. AppFuse provides archetypes for JSF, Spring MVC, Struts 2 and Tapestry 5. The &lt;em&gt;light&lt;/em&gt; archetypes are available for these frameworks, as well as for Spring MVC + FreeMarker, Stripes and Wicket.
&lt;/p&gt;
&lt;p&gt;Other notable improvements:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Added &lt;a href=&quot;http://issues.appfuse.org/browse/APF-267&quot;&gt;Compass support&lt;/a&gt; thanks to a patch from &lt;a href=&quot;http://www.kimchy.org/&quot;&gt;Shay Banon&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Upgraded from &lt;a href=&quot;http://issues.appfuse.org/browse/APF-1125&quot;&gt;XFire to CXF&lt;/a&gt; for Web Services.&lt;/li&gt;
&lt;li&gt;Moved Maven repository to &lt;a href=&quot;https://docs.sonatype.com/display/NX/OSS+Repository+Hosting&quot;&gt;Sonatype&apos;s OSS Repository Hosting&lt;/a&gt; for snapshots and releasing to Maven Central. There are no longer any AppFuse-specific artifacts, all are available in central. Thanks to &lt;a href=&quot;http://sonatype.com&quot;&gt;Sonatype&lt;/a&gt; for this great service and its &lt;a href=&quot;http://raibledesigns.com/rd/entry/nexus_is_a_kick_ass&quot;&gt;excellent repository manager&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Upgraded to Canoo WebTest 3.0. &lt;em&gt;Now if we could just get its &lt;a href=&quot;http://people.apache.org/~sgoeschl/download/maven-plugins/webtest-maven-plugin/site/index.html&quot;&gt;Maven Plugin&lt;/a&gt; moved to Codehaus.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Added &lt;a href=&quot;http://raibledesigns.com/rd/entry/ajaxified_body&quot;&gt;Ajaxified Body&lt;/a&gt; to AppFuse Light archetypes.&lt;/li&gt;
&lt;li&gt;Infrastructure upgrades, including &lt;a href=&quot;http://issues.appfuse.org/&quot;&gt;JIRA 4&lt;/a&gt;, &lt;a href=&quot;http://appfuse.org/&quot;&gt;Confluence 3&lt;/a&gt;, &lt;a href=&quot;http://source.appfuse.org&quot;&gt;FishEye 2&lt;/a&gt;, &lt;a href=&quot;http://builds.appfuse.org&quot;&gt;Bamboo 2&lt;/a&gt; and &lt;a href=&quot;http://login.appfuse.org&quot;&gt;Crowd 1.6&lt;/a&gt;. Many thanks to &lt;a href=&quot;http://www.atlassian.com/c/NPOS/10160&quot;&gt;Atlassian&lt;/a&gt; and &lt;a href=&quot;http://contegix.com&quot;&gt;Contegix&lt;/a&gt; for their excellent products and services.&lt;/li&gt;
&lt;li&gt;For more details on specific changes see the &lt;a href=&quot;http://appfuse.org/display/APF/Release+Notes+2.1.0+M1&quot; title=&quot;Release Notes 2.1.0 M1&quot;&gt;release notes&lt;/a&gt;.
&lt;/ul&gt;
&lt;p&gt;Please note that this release does not contain updates to the documentation. Code generation will work, but it&apos;s likely that some content in the &lt;a href=&quot;http://appfuse.org/display/APF/Tutorials&quot;&gt;tutorials&lt;/a&gt; won&apos;t match. For example, you can use annotations (vs. XML) for dependency injection and Tapestry is a whole new framework. I&apos;ll be working on documentation over the next several weeks in preparation for Milestone 2.
&lt;/p&gt;
&lt;p&gt;AppFuse is available as several Maven archetypes. For information on creating a new project, please see the &lt;a href=&quot;http://appfuse.org/display/APF/AppFuse+QuickStart&quot; title=&quot;AppFuse QuickStart&quot;&gt;QuickStart Guide&lt;/a&gt;.
&lt;/p&gt;
&lt;p class=&quot;smokey&quot;&gt;
To learn more about AppFuse, please read Ryan Withers&apos; &lt;a href=&quot;http://www.ociweb.com/jnb/jnbMay2008.html&quot;&gt;Igniting your applications with AppFuse&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;The 2.x series of AppFuse has a minimum requirement of the following specification versions:&lt;/p&gt;

&lt;ul class=&quot;glassList&quot;&gt;
	&lt;li&gt;Java Servlet 2.4 and JSP 2.0 (2.1 for JSF)&lt;/li&gt;
	&lt;li&gt;Java 5+&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have questions about AppFuse, please read the &lt;a href=&quot;http://appfuse.org/display/APF/FAQ&quot; title=&quot;FAQ&quot;&gt;FAQ&lt;/a&gt; or join the &lt;a href=&quot;http://appfuse.org/display/APF/Mailing+Lists&quot; title=&quot;Mailing Lists&quot;&gt;user mailing list&lt;/a&gt;. If you find bugs, please &lt;a href=&quot;http://issues.appfuse.org/secure/CreateIssue!default.jspa&quot;&gt;create an issue in JIRA&lt;/a&gt;.&lt;/p&gt; 

&lt;p&gt;Thanks to everyone for their help contributing code, writing documentation, posting to the mailing lists, and logging issues. </content>
    </entry>
</feed>

