<?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 [param] in weblog rd</title>
    <subtitle type="html">Search results for [param] within weblog Raible Designs</subtitle>
    <id>https://raibledesigns.com/rd/feed/entries/atom?q=param</id>

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

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

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

    <link rel="first" type="application/atom+xml" href="https://raibledesigns.com/rd/feed/entries/atom?q=param" />
    <link rel="next" type="application/atom+xml" href="https://raibledesigns.com/rd/feed/entries/atom?q=param&amp;page=1" />
    <updated>2026-03-30T03:31:45-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/testing_angular_2_0_rc1</id>
        <title type="html">Testing Angular 2.0 RC1 Applications</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/testing_angular_2_0_rc1"/>
        <published>2016-06-06T09:57:13-06:00</published>
        <updated>2016-06-21T05:06:24-06:00</updated> 
        <category term="/The Web" label="The Web" />
        <category term="protractor" scheme="http://roller.apache.org/ns/tags/" />
        <category term="asciidoctor" scheme="http://roller.apache.org/ns/tags/" />
        <category term="npm" scheme="http://roller.apache.org/ns/tags/" />
        <category term="angular2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javascript" scheme="http://roller.apache.org/ns/tags/" />
        <category term="karma" scheme="http://roller.apache.org/ns/tags/" />
        <category term="git" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jasmine" scheme="http://roller.apache.org/ns/tags/" />
        <category term="node" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;As mentioned &lt;a href=&quot;//raibledesigns.com/rd/entry/getting_started_with_angular_2_rc1&quot;&gt;on Friday&lt;/a&gt;, there&apos;s been
    quite a bit that&apos;s changed with Angular 2 between its
    Beta 9 and RC 1 releases. This article is an update to the
    &lt;a href=&quot;//raibledesigns.com/rd/entry/testing_angular_2_applications&quot;&gt;Testing Angular 2 Applications&lt;/a&gt; I wrote in
    March.
    That tutorial was based on Angular 2.0 Beta 9. Rather than simply updating that
    tutorial and blog post for 2.0 RC1, I decided to create a new version for posterity&apos;s sake. The 2.0 Beta 9 version
    will
    remain on my blog and I&apos;ve &lt;a href=&quot;https://github.com/mraible/angular2-tutorial/releases/tag/2.0.0-beta.9&quot;&gt;tagged
        the source on GitHub&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;If you&apos;ve already read the first version of &lt;a href=&quot;//raibledesigns.com/rd/entry/testing_angular_2_applications&quot;&gt;Testing
    Angular 2 Applications&lt;/a&gt;,
    checkout the &lt;a
        href=&quot;https://github.com/mraible/angular2-tutorial/pull/2/files#diff-c5cd85f8ff52aad4b08a3dd38575dddf&quot;&gt;
        diff of the Asciidoctor version&lt;/a&gt; to see what&apos;s changed.&lt;/p&gt;
&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;what_you_ll_build&quot;&gt;What you&apos;ll build&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;You&apos;ll learn to use &lt;a href=&quot;http://jasmine.github.io/&quot;&gt;Jasmine&lt;/a&gt; for unit testing controllers and &lt;a
                href=&quot;http://www.protractortest.org/&quot;&gt;Protractor&lt;/a&gt; for
                integration testing. See Angular 2&apos;s &lt;a href=&quot;https://angular.io/docs/ts/latest/guide/testing.html&quot;&gt;guide
                    to unit testing&lt;/a&gt;
                if you&apos;d like more information on testing and why it&apos;s important.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;The best reason for writing tests is to automate your testing. Without tests, you&apos;ll likely be testing
                manually.
                This manual testing will take longer and longer as your codebase grows.&lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;what_you_ll_need&quot;&gt;What you&apos;ll need&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;ulist&quot;&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. I recommend using &lt;a
                    href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt;.
                &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;get_the_tutorial_project&quot;&gt;Get the tutorial project&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Clone the &lt;a href=&quot;https://github.com/mraible/angular2-tutorial&quot;&gt;angular2-tutorial repository&lt;/a&gt;, checkout the &lt;code&gt;testing-start&lt;/code&gt; branch, and install its dependencies.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;git clone https://github.com/mraible/angular2-tutorial.git
cd angular2-tutorial
git checkout testing-start
npm install&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;If you haven&apos;t completed the &lt;a href=&quot;//raibledesigns.com/rd/entry/getting_started_with_angular_2_rc1&quot;&gt;Getting
                Started with Angular 2.0 RC1&lt;/a&gt; tutorial,
                you should peruse it so you understand how this application works.
                You can also simply start the app with &lt;code&gt;npm start&lt;/code&gt; and view it in your browser at &lt;a
                    href=&quot;http://localhost:5555/&quot; class=&quot;bare&quot;&gt;http://localhost:5555/&lt;/a&gt;.
            &lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</summary>
        <content type="html">&lt;p&gt;As mentioned &lt;a href=&quot;//raibledesigns.com/rd/entry/getting_started_with_angular_2_rc1&quot;&gt;on Friday&lt;/a&gt;, there&apos;s been
    quite a bit that&apos;s changed with Angular 2 between its
    Beta 9 and RC 1 releases. This article is an update to the
    &lt;a href=&quot;//raibledesigns.com/rd/entry/testing_angular_2_applications&quot;&gt;Testing Angular 2 Applications&lt;/a&gt; I wrote in
    March.
    That tutorial was based on Angular 2.0 Beta 9. Rather than simply updating that
    tutorial and blog post for 2.0 RC1, I decided to create a new version for posterity&apos;s sake. The 2.0 Beta 9 version
    will
    remain on my blog and I&apos;ve &lt;a href=&quot;https://github.com/mraible/angular2-tutorial/releases/tag/2.0.0-beta.9&quot;&gt;tagged
        the source on GitHub&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;If you&apos;ve already read the first version of &lt;a href=&quot;//raibledesigns.com/rd/entry/testing_angular_2_applications&quot;&gt;Testing
    Angular 2 Applications&lt;/a&gt;,
    checkout the &lt;a
        href=&quot;https://github.com/mraible/angular2-tutorial/pull/2/files#diff-c5cd85f8ff52aad4b08a3dd38575dddf&quot;&gt;
        diff of the Asciidoctor version&lt;/a&gt; to see what&apos;s changed.&lt;/p&gt;
&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;what_you_ll_build&quot;&gt;What you&apos;ll build&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;You&apos;ll learn to use &lt;a href=&quot;http://jasmine.github.io/&quot;&gt;Jasmine&lt;/a&gt; for unit testing controllers and &lt;a
                href=&quot;http://www.protractortest.org/&quot;&gt;Protractor&lt;/a&gt; for
                integration testing. See Angular 2&apos;s &lt;a href=&quot;https://angular.io/docs/ts/latest/guide/testing.html&quot;&gt;guide
                    to unit testing&lt;/a&gt;
                if you&apos;d like more information on testing and why it&apos;s important.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;The best reason for writing tests is to automate your testing. Without tests, you&apos;ll likely be testing
                manually.
                This manual testing will take longer and longer as your codebase grows.&lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;what_you_ll_need&quot;&gt;What you&apos;ll need&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;ulist&quot;&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. I recommend using &lt;a
                    href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt;.
                &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;get_the_tutorial_project&quot;&gt;Get the tutorial project&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Clone the &lt;a href=&quot;https://github.com/mraible/angular2-tutorial&quot;&gt;angular2-tutorial repository&lt;/a&gt;, checkout the &lt;code&gt;testing-start&lt;/code&gt; branch, and install its dependencies.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;git clone https://github.com/mraible/angular2-tutorial.git
cd angular2-tutorial
git checkout testing-start
npm install&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;If you haven&apos;t completed the &lt;a href=&quot;//raibledesigns.com/rd/entry/getting_started_with_angular_2_rc1&quot;&gt;Getting
                Started with Angular 2.0 RC1&lt;/a&gt; tutorial,
                you should peruse it so you understand how this application works.
                You can also simply start the app with &lt;code&gt;npm start&lt;/code&gt; and view it in your browser at &lt;a
                    href=&quot;http://localhost:5555/&quot; class=&quot;bare&quot;&gt;http://localhost:5555/&lt;/a&gt;.
            &lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;unit_test_the_searchservice&quot;&gt;Unit test the SearchService&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Create &lt;code&gt;src/client/app/shared/search/search.service.spec.ts&lt;/code&gt; and setup the test&apos;s
                infrastructure using &lt;a
                    href=&quot;https://angular.io/docs/js/latest/api/http/testing/MockBackend-class.html&quot;&gt;MockBackend&lt;/a&gt;
                and &lt;a href=&quot;https://angular.io/docs/js/latest/api/http/BaseRequestOptions-class.html&quot;&gt;BaseRequestOptions&lt;/a&gt;.
            &lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
import {
  beforeEachProviders,
  it,
  describe,
  expect,
  inject,
  fakeAsync,
  tick
} from &apos;@angular/core/testing&apos;;
import { MockBackend } from &apos;@angular/http/testing&apos;;
import { provide } from &apos;@angular/core&apos;;
import { Http, ConnectionBackend, BaseRequestOptions, Response, ResponseOptions } from &apos;@angular/http&apos;;
import { SearchService } from &apos;./search.service&apos;;

export function main() {
  describe(&apos;Search Service&apos;, () =&gt; {
    beforeEachProviders(() =&gt; {
      return [BaseRequestOptions, MockBackend, SearchService,
        provide(Http, {
          useFactory: (backend:ConnectionBackend, defaultOptions:BaseRequestOptions) =&gt; {
            return new Http(backend, defaultOptions);
          }, deps: [MockBackend, BaseRequestOptions]
        }),
      ];
    });
  });
}

&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;If you run &lt;code&gt;npm test&lt;/code&gt;, all tests will pass, but you don&apos;t see &quot;Search Service&quot; as a listed
                test. You can fix this by adding the first test of &lt;code&gt;getAll()&lt;/code&gt;.
                This test shows how &lt;code&gt;MockBackend&lt;/code&gt; can be used to mock results and set the response.&lt;/p&gt;
        &lt;/div&gt;
        &lt;p class=&quot;alert alert-success&quot;&gt;&lt;b&gt;TIP&lt;/b&gt;: When you are testing code that returns either a Promise or an RxJS
            Observable, you can use the &lt;code&gt;fakeAsync&lt;/code&gt; helper to test that code as
            if it were synchronous.
            Promises are be fulfilled and Observables are notified immediately after you call &lt;code&gt;tick()&lt;/code&gt;.&lt;/p&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;The test below should be on the same level as &lt;code&gt;beforeEachProviders&lt;/code&gt;.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;it(&apos;should retrieve all search results&apos;,
  inject([SearchService, MockBackend], fakeAsync((searchService:SearchService, mockBackend:MockBackend) =&amp;gt; {
    var res:Response;
    mockBackend.connections.subscribe(c =&amp;gt; {
      expect(c.request.url).toBe(&apos;app/shared/search/data/people.json&apos;);
      let response = new ResponseOptions({body: &apos;[{&quot;name&quot;: &quot;John Elway&quot;}, {&quot;name&quot;: &quot;Gary Kubiak&quot;}]&apos;});
      c.mockRespond(new Response(response));
    });
    searchService.getAll().subscribe((response) =&amp;gt; {
      res = response;
    });
    tick();
    expect(res[0].name).toBe(&apos;John Elway&apos;);
  }))
);
&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Running &lt;code&gt;npm test&lt;/code&gt; should result in &quot;12 tests completed&quot;. Add a couple more tests for
                filtering by search term and fetching by id.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
it(&apos;should filter by search term&apos;,
  inject([SearchService, MockBackend], fakeAsync((searchService:SearchService, mockBackend:MockBackend) =&gt; {
    var res;
    mockBackend.connections.subscribe(c =&gt; {
      expect(c.request.url).toBe(&apos;app/shared/search/data/people.json&apos;);
      let response = new ResponseOptions({body: &apos;[{&quot;name&quot;: &quot;John Elway&quot;}, {&quot;name&quot;: &quot;Gary Kubiak&quot;}]&apos;});
      c.mockRespond(new Response(response));
    });
    searchService.search(&apos;john&apos;).subscribe((response) =&gt; {
      res = response;
    });
    tick();
    expect(res[0].name).toBe(&apos;John Elway&apos;);
  }))
);

it(&apos;should fetch by id&apos;,
  inject([SearchService, MockBackend], fakeAsync((searchService:SearchService, mockBackend:MockBackend) =&gt; {
    var res;
    mockBackend.connections.subscribe(c =&gt; {
      expect(c.request.url).toBe(&apos;app/shared/search/data/people.json&apos;);
      let response = new ResponseOptions({body: &apos;[{&quot;id&quot;: 1, &quot;name&quot;: &quot;John Elway&quot;}, {&quot;id&quot;: 2, &quot;name&quot;: &quot;Gary Kubiak&quot;}]&apos;});
      c.mockRespond(new Response(response));
    });
    searchService.search(&apos;2&apos;).subscribe((response) =&gt; {
      res = response;
    });
    tick();
    expect(res[0].name).toBe(&apos;Gary Kubiak&apos;);
  }))
);
&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;If you want to have tests continually run as you add them, you can run the following commands in separate
                shell windows.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;npm run build.test.watch
npm run karma.start&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;p&gt;NOTE: See &lt;a
            href=&quot;https://www.jetbrains.com/help/idea/15.0/running-unit-tests-on-karma.html?origin=old_help&quot;&gt;Running
            Unit Tests on Karma&lt;/a&gt; to
            learn how to run your tests from IntelliJ IDEA.&lt;/p&gt;

    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;unit_test_the_searchcomponent&quot;&gt;Unit test the SearchComponent&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;To unit test the &lt;code&gt;SearchComponent&lt;/code&gt;, create a &lt;code&gt;MockSearchProvider&lt;/code&gt; that has &lt;a
                href=&quot;http://angular-tips.com/blog/2014/03/introduction-to-unit-test-spies/&quot;&gt;spies&lt;/a&gt;.
                These allow you to &lt;em&gt;spy&lt;/em&gt; on functions to check if they were called.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Create &lt;code&gt;src/client/app/shared/search/mocks/search.service.ts&lt;/code&gt; and populate it with spies for
                each method, as well as methods to set the response and subscribe to results.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
import { provide } from &apos;@angular/core&apos;;
import { SpyObject } from &apos;./helper&apos;;

import { SearchService } from &apos;../search.service&apos;;
import Spy = jasmine.Spy;

export class MockSearchService extends SpyObject {
  getAllSpy:Spy;
  getByIdSpy:Spy;
  searchSpy:Spy;
  saveSpy:Spy;
  fakeResponse:any;

  constructor() {
    super(SearchService);

    this.fakeResponse = null;
    this.getAllSpy = this.spy(&apos;getAll&apos;).andReturn(this);
    this.getByIdSpy = this.spy(&apos;get&apos;).andReturn(this);
    this.searchSpy = this.spy(&apos;search&apos;).andReturn(this);
    this.saveSpy = this.spy(&apos;save&apos;).andReturn(this);
  }

  subscribe(callback:any) {
    callback(this.fakeResponse);
  }

  setResponse(json:any):void {
    this.fakeResponse = json;
  }

  getProviders():Array&amp;lt;any&amp;gt; {
    return [provide(SearchService, {useValue: this})];
  }
}
&lt;/pre&gt;
                &lt;p&gt;
                    In this same directory, create a &lt;code&gt;helper.ts&lt;/code&gt; class to implement the
                    &lt;code&gt;SpyObject&lt;/code&gt;
                    that &lt;code&gt;MockSearchService&lt;/code&gt; extends.
                &lt;/p&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
import {StringMapWrapper} from &apos;@angular/core/src/facade/collection&apos;;

export interface GuinessCompatibleSpy extends jasmine.Spy {
  /** By chaining the spy with and.returnValue, all calls to the function will return a specific
   * value. */
  andReturn(val: any): void;
  /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied
   * function. */
  andCallFake(fn: Function): GuinessCompatibleSpy;
  /** removes all recorded calls */
  reset();
}

export class SpyObject {
  static stub(object = null, config = null, overrides = null) {
    if (!(object instanceof SpyObject)) {
      overrides = config;
      config = object;
      object = new SpyObject();
    }

    var m = StringMapWrapper.merge(config, overrides);
    StringMapWrapper.forEach(m, (value, key) =&amp;gt; { object.spy(key).andReturn(value); });
    return object;
  }

  constructor(type = null) {
    if (type) {
      for (var prop in type.prototype) {
        var m = null;
        try {
          m = type.prototype&amp;#91;prop&amp;#93;;
        } catch (e) {
          // As we are creating spys for abstract classes,
          // these classes might have getters that throw when they are accessed.
          // As we are only auto creating spys for methods, this
          // should not matter.
        }
        if (typeof m === &apos;function&apos;) {
          this.spy(prop);
        }
      }
    }
  }

  spy(name) {
    if (!this&amp;#91;name&amp;#93;) {
      this&amp;#91;name&amp;#93; = this._createGuinnessCompatibleSpy(name);
    }
    return this&amp;#91;name&amp;#93;;
  }

  prop(name, value) { this&amp;#91;name&amp;#93; = value; }

  /** @internal */
  _createGuinnessCompatibleSpy(name): GuinessCompatibleSpy {
    var newSpy: GuinessCompatibleSpy = &amp;lt;any&amp;gt;jasmine.createSpy(name);
    newSpy.andCallFake = &amp;lt;any&amp;gt;newSpy.and.callFake;
    newSpy.andReturn = &amp;lt;any&amp;gt;newSpy.and.returnValue;
    newSpy.reset = &amp;lt;any&amp;gt;newSpy.calls.reset;
    // revisit return null here (previously needed for rtts_assert).
    newSpy.and.returnValue(null);
    return newSpy;
  }
}
&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Alongside, create &lt;code&gt;routes.ts&lt;/code&gt; to mock Angular&apos;s &lt;code&gt;RouteSegment&lt;/code&gt; and passing
                parameters between components.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
import { RouteSegment } from &apos;@angular/router&apos;;

export class MockRouteSegment implements RouteSegment {
  urlSegments:any;
  parameters:any;
  outlet:string;
  _type:any;
  _componentFactory:any;
  type:any;
  stringifiedUrlSegments:string;

  constructor(parameters?:{ [key:string]:any; }) {
    this.parameters = parameters;
  }

  getParam(param:string) {
    return this.parameters[param];
  }
}
&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;With mocks in place, you can create a spec for &lt;code&gt;SearchComponent&lt;/code&gt; that uses these as providers.
                Create a file at &lt;code&gt;src/search/components/search.component.spec.ts&lt;/code&gt; and populate it with the
                following code.
            &lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
import { provide } from &apos;@angular/core&apos;;
import { TestComponentBuilder } from &apos;@angular/compiler/testing&apos;;
import {
  it,
  describe,
  expect,
  inject,
  beforeEachProviders,
} from &apos;@angular/core/testing&apos;;

import { RouteSegment } from &apos;@angular/router&apos;;
import { MockRouteSegment } from &apos;../shared/search/mocks/routes&apos;;
import { MockSearchService } from &apos;../shared/search/mocks/search.service&apos;;

import { SearchComponent } from &apos;./search.component&apos;;

export function main() {
  describe(&apos;Search component&apos;, () =&gt; {
    var mockSearchService:MockSearchService;

    beforeEachProviders(() =&gt; {
      mockSearchService = new MockSearchService();

      return [
        mockSearchService.getProviders(),
        provide(RouteSegment, { useValue: new MockRouteSegment({ &apos;term&apos;: &apos;peyton&apos; }) })
      ];
    });
  });
}
&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Add two tests, one to verify a search term is used when it&apos;s set on the component and a second to verify
                search is called when a term is passed in as a route
                parameter.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
it(&apos;should search when a term is set and search() is called&apos;, inject([TestComponentBuilder], (tcb:TestComponentBuilder) =&gt; {
  return tcb.createAsync(SearchComponent).then((fixture) =&gt; {
    let searchComponent = fixture.debugElement.componentInstance;
    searchComponent.query = &apos;M&apos;;
    searchComponent.search();
    expect(mockSearchService.searchSpy).toHaveBeenCalledWith(&apos;M&apos;);
  });
}));

it(&apos;should search automatically when a term is on the URL&apos;, inject([TestComponentBuilder], (tcb:TestComponentBuilder) =&gt; {
  return tcb.createAsync(SearchComponent).then((fixture) =&gt; {
    fixture.detectChanges();
    expect(mockSearchService.searchSpy).toHaveBeenCalledWith(&apos;peyton&apos;);
  });
}));
&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Add a spec for the &lt;code&gt;EditComponent&lt;/code&gt; as well, verifying fetching a single record works. Notice
                how you can access the component directly with
                &lt;code&gt;fixture.debugElement.componentInstance&lt;/code&gt;, or its rendered version with &lt;code&gt;fixture.debugElement.nativeElement&lt;/code&gt;.
                Create a file at &lt;code&gt;src/search/components/edit.component.spec.ts&lt;/code&gt; and populate it with the code
                below.
            &lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
import { provide } from &apos;@angular/core&apos;;
import { TestComponentBuilder } from &apos;@angular/compiler/testing&apos;;
import {
  it,
  describe,
  expect,
  inject,
  beforeEachProviders,
} from &apos;@angular/core/testing&apos;;

import { RouteSegment } from &apos;@angular/router&apos;;
import { ROUTER_FAKE_PROVIDERS } from &apos;@angular/router/testing&apos;;
import { MockRouteSegment } from &apos;../shared/search/mocks/routes&apos;;
import { MockSearchService } from &apos;../shared/search/mocks/search.service&apos;;

import { EditComponent } from &apos;./edit.component&apos;;

export function main() {
  describe(&apos;Edit component&apos;, () =&gt; {
    var mockSearchService:MockSearchService;

    beforeEachProviders(() =&gt; {
      mockSearchService = new MockSearchService();

      return [
        mockSearchService.getProviders(),
        ROUTER_FAKE_PROVIDERS,
        provide(RouteSegment, { useValue: new MockRouteSegment({ &apos;id&apos;: &apos;1&apos; }) })
      ];
    });

    it(&apos;should fetch a single record&apos;, inject([TestComponentBuilder], (tcb:TestComponentBuilder) =&gt; {
      return tcb.createAsync(EditComponent).then((fixture) =&gt; {
        let person = {name: &apos;Emmanuel Sanders&apos;, address: {city: &apos;Denver&apos;}};
        mockSearchService.setResponse(person);

        fixture.detectChanges();
        // verify service was called
        expect(mockSearchService.getByIdSpy).toHaveBeenCalledWith(1);

        // verify data was set on component when initialized
        let editComponent = fixture.debugElement.componentInstance;
        expect(editComponent.editAddress.city).toBe(&apos;Denver&apos;);

        // verify HTML renders as expected
        var compiled = fixture.debugElement.nativeElement;
        expect(compiled.querySelector(&apos;h3&apos;)).toHaveText(&apos;Emmanuel Sanders&apos;);
      });
    }));
  });
}
&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;You should see &quot;&lt;span style=&quot;color: green&quot;&gt;&amp;#10004; 22 tests completed&lt;/span&gt;&quot; in the shell window that&apos;s
                running &lt;code&gt;npm run karma.start&lt;/code&gt;. If you don&apos;t, try cancelling the command and restarting.&lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;integration_test_the_search_ui&quot;&gt;Integration test the search UI&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;To test if the application works end-to-end, you can write tests with &lt;a
                href=&quot;http://angular.github.io/protractor&quot;&gt;Protractor&lt;/a&gt;. These are also known as integration tests,
                since they test the &lt;em&gt;integration&lt;/em&gt; between all layers of your application.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;To verify end-to-end tests work in the project before you begin, run the following commands in three
                different console windows.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;# npm run webdriver-update &amp;lt;- You will need to run this the first time
npm run webdriver-start
npm run serve.e2e
npm run e2e&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;You should receive an error stating that the &quot;nav text for About&quot; is incorrect.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div id=&quot;protractor-nav-error&quot; class=&quot;imageblock&quot;&gt;
            &lt;div style=&quot;text-align: center&quot;&gt;

                &lt;a href=&quot;https://c6.staticflickr.com/8/7393/27377971101_9a4bdfee36_c.jpg&quot;
                   title=&quot;Protractor nav test error&quot; rel=&quot;lightbox[testing-angular2.0rc1]&quot;
                   data-href=&quot;https://www.flickr.com/photos/mraible/27377971101/in/datetaken-public/&quot;&gt;&lt;img
                    src=&quot;https://c6.staticflickr.com/8/7393/27377971101_9a4bdfee36_z.jpg&quot; width=&quot;640&quot;
                    alt=&quot;Protractor nav test error&quot;&gt;&lt;/a&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;This happens because we added a Search link to the navbar and didn&apos;t update the test (in &lt;code&gt;app.component.e2e.ts&lt;/code&gt;)
                that looks for the last child. &lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;it(&apos;should have correct nav text for About&apos;, () =&amp;gt; {
    expect(element(by.css(&apos;sd-app sd-navbar nav a:last-child&apos;)).getText()).toEqual(&apos;ABOUT&apos;);
});
&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Replace this test with the one below, and add a new one to verify the Search link is last.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;listingblock&quot;&gt;
            &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;it(&apos;should have correct nav text for About&apos;, () =&amp;gt; {
  expect(element(by.css(&apos;sd-app sd-navbar nav a:nth-child(2)&apos;)).getText()).toEqual(&apos;ABOUT&apos;);
});

it(&apos;should have correct nav text for Search&apos;, () =&amp;gt; {
  expect(element(by.css(&apos;sd-app sd-navbar nav a:last-child&apos;)).getText()).toEqual(&apos;SEARCH&apos;);
});
&lt;/pre&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;Now when you run &lt;code&gt;npm run e2e&lt;/code&gt;, all specs should pass.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect2&quot;&gt;
            &lt;h3 id=&quot;_testing_the_search_feature&quot;&gt;Testing the search feature&lt;/h3&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Create a new &lt;code&gt;search.component.e2e-spec.ts&lt;/code&gt; spec in the same directory as your &lt;code&gt;SearchComponent&lt;/code&gt;.
                    Add tests to verify elements are rendered correctly and
                    search works. At the time of this writing, Protractor&apos;s &lt;code&gt;by.model&lt;/code&gt; and
                    &lt;code&gt;by.repeater&lt;/code&gt; don&apos;t work with Angular 2. For this reason, I used &lt;code&gt;by.css&lt;/code&gt; to
                    verify the HTML renders as expected.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;listingblock&quot;&gt;
                &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
describe(&apos;Search&apos;, () =&gt; {

  beforeEach(() =&gt; {
    browser.get(&apos;/search&apos;);
  });

  it(&apos;should have an input and search button&apos;, () =&gt; {
    expect(element(by.css(&apos;sd-app sd-search form input&apos;)).isPresent()).toEqual(true);
    expect(element(by.css(&apos;sd-app sd-search form button&apos;)).isPresent()).toEqual(true);
  });

  it(&apos;should allow searching&apos;, () =&gt; {
    let searchButton = element(by.css(&apos;button&apos;));
    let searchBox = element(by.css(&apos;input&apos;));
    searchBox.sendKeys(&apos;M&apos;);
    searchButton.click().then(() =&gt; {
      // doesn&apos;t work as expected - results in 0
      //expect(element.all(by.repeater(&apos;person of searchResults&apos;)).count()).toEqual(3);
      var list = element.all(by.css(&apos;sd-search table tbody tr&apos;));
      expect(list.count()).toBe(3);
    });
  });
});
&lt;/pre&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect2&quot;&gt;
            &lt;h3 id=&quot;_testing_the_edit_feature&quot;&gt;Testing the edit feature&lt;/h3&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Create a &lt;code&gt;edit.component.e2e-spec.ts&lt;/code&gt; spec to verify the &lt;code&gt;EditComponent&lt;/code&gt;
                    renders a person&apos;s information and that you can update their information.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;listingblock&quot;&gt;
                &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;
describe(&apos;Edit&apos;, () =&gt; {

  beforeEach(() =&gt; {
    browser.get(&apos;/edit/1&apos;);
  });

  let name = element(by.id(&apos;name&apos;));
  let street = element(by.id(&apos;street&apos;));
  let city = element(by.id(&apos;city&apos;));

  it(&apos;should allow viewing a person&apos;, () =&gt; {
    expect(element(by.css(&apos;h3&apos;)).getText()).toEqual(&apos;Peyton Manning&apos;);
    expect(name.getAttribute(&apos;value&apos;)).toEqual(&apos;Peyton Manning&apos;);
    expect(street.getAttribute(&apos;value&apos;)).toEqual(&apos;1234 Main Street&apos;);
    expect(city.getAttribute(&apos;value&apos;)).toEqual(&apos;Greenwood Village&apos;);
  });

  it(&apos;should allow updating a name&apos;, function () {
    let save = element(by.id(&apos;save&apos;));
    // send individual characters since sendKeys passes partial values sometimes
    // https://github.com/angular/protractor/issues/698
    &apos; Won!&apos;.split(&apos;&apos;).forEach((c) =&gt; name.sendKeys(c));
    save.click();
    // verify one element matched this change
    var list = element.all(by.css(&apos;sd-search table tbody tr&apos;));
    expect(list.count()).toBe(1);
  });
});
&lt;/pre&gt;
                    &lt;p&gt;
                        Run &lt;code&gt;npm run e2e&lt;/code&gt; to verify all your end-to-end tests pass. You might receive a
                        failure for the &quot;Home&quot; test.
                    &lt;/p&gt;
                    &lt;div style=&quot;text-align: center&quot;&gt;
                        &lt;a href=&quot;https://c1.staticflickr.com/8/7227/27173055360_80b1055f07_c.jpg&quot;
                           data-href=&quot;https://www.flickr.com/photos/mraible/27173055360/in/datetaken-public/&quot;
                           title=&quot;Protractor home error&quot; rel=&quot;lightbox[testing-angular2.0rc1]&quot;&gt;&lt;img
                            src=&quot;https://c1.staticflickr.com/8/7227/27173055360_80b1055f07_z.jpg&quot; width=&quot;640&quot;
                            alt=&quot;Protractor home error&quot;&gt;&lt;/a&gt;
                    &lt;/div&gt;
                    &lt;p&gt;If you do, open &lt;code&gt;src/client/app/+home/home.component.e2e-spec.ts&lt;/code&gt; and change line 17
                        from this:&lt;/p&gt;
&lt;pre class=&quot;brush: css&quot;&gt;
element(by.css(&apos;sd-home form input&apos;)).sendKeys(&apos;Tim Berners-Lee&apos;);
&lt;/pre&gt;
                    &lt;p&gt;To this:&lt;/p&gt;
&lt;pre class=&quot;brush: css&quot;&gt;
let input = element(by.css(&apos;sd-home form input&apos;));
&apos;Tim Berners-Lee&apos;.split(&apos;&apos;).forEach((c) =&gt; input.sendKeys(c));
&lt;/pre&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Run &lt;code&gt;npm run e2e&lt;/code&gt; again. You should see a success message similar to the one below in your
                    terminal window.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div id=&quot;protractor-success&quot; class=&quot;imageblock&quot;&gt;
                &lt;div style=&quot;text-align: center&quot;&gt;
                    &lt;a href=&quot;https://c1.staticflickr.com/8/7345/26840174984_01e6906f98_c.jpg&quot;
                       title=&quot;Protractor success&quot; rel=&quot;lightbox[testing-angular2.0rc1]&quot;
                       data-href=&quot;https://www.flickr.com/photos/mraible/26840174984/in/datetaken-public/&quot;&gt;&lt;img
                        src=&quot;https://c1.staticflickr.com/8/7345/26840174984_01e6906f98_z.jpg&quot; width=&quot;640&quot;
                        alt=&quot;Protractor success&quot;&gt;&lt;/a&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;If you made it this far and have all 13 specs passing - congratulations!
                    You&apos;re well on your way to writing quality code with Angular 2 and verifying it works.&lt;/p&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
   &lt;h3 id=&quot;_continuous_integration&quot;&gt;Continuous Integration&lt;/h3&gt;
    &lt;div class=&quot;paragraph&quot;&gt;
        &lt;p&gt;The angular2-seed project ships with a &lt;code&gt;.travis.yml&lt;/code&gt; that you can use to run continuous integration for this application
            through &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis CI&lt;/a&gt;. To enable builds on Travis CI, login and enable builds for the
            GitHub repo you created the project in. Then trigger your first build with a &lt;code&gt;git push&lt;/code&gt;.&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class=&quot;paragraph&quot;&gt;
        &lt;p&gt;When I first tried this, I received a &lt;a href=&quot;https://travis-ci.org/mraible/angular2-tutorial/jobs/135517549#L1189&quot;&gt;failure&lt;/a&gt; because
            Protractor on Travis CI is &lt;a href=&quot;https://github.com/mgechev/angular2-seed/issues/970&quot;&gt;unable to navigate directly&lt;/a&gt;
            to the search and edit components. I was able to workaround this by modifying &lt;code&gt;search.component.e2e-spec.ts&lt;/code&gt; to start
            at the top and navigate to the component.&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class=&quot;listingblock&quot;&gt;
        &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;beforeEach(() =&amp;gt; {
  browser.get(&apos;/&apos;);
  element(by.linkText(&apos;SEARCH&apos;)).click();
});&lt;/pre&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;paragraph&quot;&gt;
        &lt;p&gt;I did something similar with &lt;code&gt;edit.component.e2e-spec.ts&lt;/code&gt;:&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class=&quot;listingblock&quot;&gt;
        &lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;brush: js&quot;&gt;beforeEach(() =&amp;gt; {
  browser.get(&apos;/&apos;);
  element(by.linkText(&apos;SEARCH&apos;)).click();
  let search = element(by.css(&apos;sd-search form input&apos;));
  &apos;Man&apos;.split(&apos;&apos;).forEach((c) =&amp;gt; search.sendKeys(c));
  element(by.css(&apos;sd-search form button&apos;)).click();
  element(by.linkText(&apos;Peyton Manning&apos;)).click();
});&lt;/pre&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;paragraph&quot;&gt;
        &lt;p&gt;After making these changes, &lt;a href=&quot;https://travis-ci.org/mraible/angular2-tutorial/builds/135598015&quot;&gt;all e2e tests passed in Travis CI&lt;/a&gt;.&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;source_code&quot;&gt;Source code&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;paragraph&quot;&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/angular2-tutorial&quot;&gt;https://github.com/mraible/angular2-tutorial&lt;/a&gt;.
                If you have ideas for improvements, please leave a comment or send a pull request.
            &lt;/p&gt;
            &lt;p&gt;
                I wrote this tutorial in &lt;a href=&quot;http://asciidoctor.org/&quot;&gt;Asciidoctor&lt;/a&gt; so you can also &lt;a href=&quot;https://github.com/mraible/angular2-tutorial/blob/master/TESTING.adoc&quot;&gt;read this tutorial on GitHub&lt;/a&gt; or
                &lt;a href=&quot;http://gist.asciidoctor.org/?github-mraible%2Fangular2-tutorial%2F%2FTESTING.adoc&quot;&gt;using DocGist&lt;/a&gt;.
            &lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;sect1&quot;&gt;
    &lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
    &lt;div class=&quot;sectionbody&quot;&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;I hope you&apos;ve enjoyed this quick-and-easy tutorial on testing Angular 2.0 RC1 applications. You can see
                the test coverage of your project by running
                &lt;code&gt;npm run serve.coverage&lt;/code&gt;. You&apos;ll notice that the new components and service could use some
                additional coverage. I&apos;ll leave that as a task
                for the reader.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div id=&quot;test-coverage&quot; class=&quot;imageblock&quot;&gt;
            &lt;div style=&quot;text-align: center&quot;&gt;
                &lt;a href=&quot;https://c3.staticflickr.com/8/7381/27350245922_7e184fc630_c.jpg&quot; title=&quot;Test Coverage&quot;
                   rel=&quot;lightbox[testing-angular2.0rc1]&quot;
                   data-href=&quot;https://www.flickr.com/photos/mraible/27350245922/in/datetaken-public/&quot;&gt;&lt;img
                    src=&quot;https://c3.staticflickr.com/8/7381/27350245922_7e184fc630_z.jpg&quot; width=&quot;640&quot;
                    alt=&quot;Test Coverage&quot;&gt;&lt;/a&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
            &lt;p&gt;I learned a lot about testing from &lt;a href=&quot;https://www.ng-book.com/2/&quot;&gt;ng-book 2&lt;/a&gt; and
                its Testing chapter. If you have any Angular 2 testing tips and tricks you&apos;d like to share, I&apos;d love to
                hear about them.&lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/the_scenic_way_to_santa</id>
        <title type="html">The Scenic Way to Santa Fe</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/the_scenic_way_to_santa"/>
        <published>2014-07-27T11:56:52-06:00</published>
        <updated>2014-07-27T21:02:24-06:00</updated> 
        <category term="/General" label="General" />
        <category term="syncro" scheme="http://roller.apache.org/ns/tags/" />
        <category term="santafe" scheme="http://roller.apache.org/ns/tags/" />
        <category term="colorado" scheme="http://roller.apache.org/ns/tags/" />
        <category term="roadtrip" scheme="http://roller.apache.org/ns/tags/" />
        <category term="vacation" scheme="http://roller.apache.org/ns/tags/" />
        <category term="newmexico" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;After having a &lt;a href=&quot;http://raibledesigns.com/rd/entry/farewell_to_the_2013_2014&quot;&gt;successful run at ski season&lt;/a&gt; with our VW Syncro, Trish and I figured we&apos;d see how it performed in the
    summer. We took it &lt;a href=&quot;http://raibledesigns.com/rd/entry/syncro_solstice_2014&quot;&gt;4x4ing in Moab&lt;/a&gt;, &lt;a href=&quot;http://raibledesigns.com/rd/entry/rafting_the_yampa_through_dinosaur&quot;&gt;rafting in Dinosaur National Monument&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/father_s_day_weekend_on1&quot;&gt;camping for Father&apos;s Day Weekend&lt;/a&gt;. It
    was a trusty steed for our kids, dogs, skis and raft. Earlier this month, we planned a week-long road trip to Santa Fe to see
    one of my old college roommates. Because of the holiday weekend, it turned into a 10-day road trip. We left Denver
    in style on the morning of the 4th.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3863/14652909092_86c4660f23_c.jpg&quot; title=&quot;Happy 4th from our Red, White and Blues! by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14652909092&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3863/14652909092_86c4660f23.jpg&quot; width=&quot;500&quot; alt=&quot;Happy 4th from our Red, White and Blues!&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    The motorcycle on the back didn&apos;t seem to slow us down much. We drove from Denver to Winter Park, taking the long way
    over Squaw Pass to avoid traffic.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm3.staticflickr.com/2932/14652910062_3eb2ccf747_c.jpg&quot; title=&quot;The Scenic Route over Squaw Pass by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14652910062&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2932/14652910062_3eb2ccf747_m.jpg&quot; width=&quot;240&quot; alt=&quot;The Scenic Route over Squaw Pass&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;https://farm4.staticflickr.com/3897/14466694318_dedbc0665b_c.jpg&quot; title=&quot;Colorado High Country by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466694318&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3897/14466694318_dedbc0665b_m.jpg&quot; width=&quot;240&quot; alt=&quot;Colorado High Country&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    When we arrived at our Ski Shack, the engine was making a loud knocking sound. We dismissed it as a random
    occurrence. When I drove to the gas station 45 minutes later, the knocking was loud enough that heads turned when I drove past. After fueling up, I started the van and began driving back to our condo. The engine sputtered, the tires screeched and then the engine died. I pulled to the side, conveniently still in the gas station&apos;s parking lot. The engine would no longer turn over.
&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;After having a &lt;a href=&quot;http://raibledesigns.com/rd/entry/farewell_to_the_2013_2014&quot;&gt;successful run at ski season&lt;/a&gt; with our VW Syncro, Trish and I figured we&apos;d see how it performed in the
    summer. We took it &lt;a href=&quot;http://raibledesigns.com/rd/entry/syncro_solstice_2014&quot;&gt;4x4ing in Moab&lt;/a&gt;, &lt;a href=&quot;http://raibledesigns.com/rd/entry/rafting_the_yampa_through_dinosaur&quot;&gt;rafting in Dinosaur National Monument&lt;/a&gt; and &lt;a href=&quot;http://raibledesigns.com/rd/entry/father_s_day_weekend_on1&quot;&gt;camping for Father&apos;s Day Weekend&lt;/a&gt;. It
    was a trusty steed for our kids, dogs, skis and raft. Earlier this month, we planned a week-long road trip to Santa Fe to see
    one of my old college roommates. Because of the holiday weekend, it turned into a 10-day road trip. We left Denver
    in style on the morning of the 4th.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3863/14652909092_86c4660f23_c.jpg&quot; title=&quot;Happy 4th from our Red, White and Blues! by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14652909092&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3863/14652909092_86c4660f23.jpg&quot; width=&quot;500&quot; alt=&quot;Happy 4th from our Red, White and Blues!&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    The motorcycle on the back didn&apos;t seem to slow us down much. We drove from Denver to Winter Park, taking the long way
    over Squaw Pass to avoid traffic.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm3.staticflickr.com/2932/14652910062_3eb2ccf747_c.jpg&quot; title=&quot;The Scenic Route over Squaw Pass by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14652910062&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2932/14652910062_3eb2ccf747_m.jpg&quot; width=&quot;240&quot; alt=&quot;The Scenic Route over Squaw Pass&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;https://farm4.staticflickr.com/3897/14466694318_dedbc0665b_c.jpg&quot; title=&quot;Colorado High Country by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466694318&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3897/14466694318_dedbc0665b_m.jpg&quot; width=&quot;240&quot; alt=&quot;Colorado High Country&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    When we arrived at our Ski Shack, the engine was making a loud knocking sound. We dismissed it as a random
    occurrence. When I drove to the gas station 45 minutes later, the knocking was loud enough that heads turned when I drove past. After fueling up, I started the van and began driving back to our condo. The engine sputtered, the tires screeched and then the engine died. I pulled to the side, conveniently still in the gas station&apos;s parking lot. The engine would no longer turn over.
&lt;/p&gt;
&lt;p&gt;
    Below is the email I sent to Mike at &lt;a href=&quot;http://www.rockymountainwesty.com/&quot;&gt;Rocky Mountain Westy&lt;/a&gt; while walking back to our condo.
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
    Happy Fourth of July! Our van&apos;s engine gave up the ghost today. There was a loud knocking, then it felt like is
    slammed on the back brakes, a screech of the tires and it died. Now it won&apos;t even turn over. Sounds like it&apos;s seized
    to me.
    &lt;br&gt;&lt;br&gt;
    This happened in Fraser today. I have AAA so could probably get it towed to you.
    &lt;br&gt;&lt;br&gt;
    Can you help us find and install a new engine? I&apos;d like something with similar HP. Would you recommend a 1.8T, a 3.0
    liter or something else?
&lt;/p&gt;
&lt;p&gt;It was the best breakdown I&apos;ve ever had. I was able to walk home (one mile) and it didn&apos;t even rain on me. From
    there, we continued to celebrate the 4th and refactor our road-trip plans. With the Syncro, we were planning on
    camping at The Great Sand Dunes, Pagosa Springs and Mesa Verde. We decided we&apos;d drive our new sedan instead
    (recently gifted from Trish&apos;s Dad). I took the train to Denver, drove it up on July 5th and we departed Winter Park
    on Sunday, July 6.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3846/14466698438_dfdfb9e3b7_c.jpg&quot; title=&quot;It&apos;s a beautiful day for a train ride! by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466698438&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3846/14466698438_dfdfb9e3b7_q.jpg&quot; width=&quot;150&quot; alt=&quot;It&apos;s a beautiful day for a train ride!&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm6.staticflickr.com/5577/14466884067_d0dc70c4da_c.jpg&quot; title=&quot;On Day 3 of our road trip, we shipped the Syncro off to Fort Collins for repairs. Thanks to Don and AAA, especially Don, who&apos;ll likely endure horrendous traffic on I-70. by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466884067&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5577/14466884067_d0dc70c4da_q.jpg&quot; width=&quot;150&quot; alt=&quot;On Day 3 of our road trip, we shipped the Syncro off to Fort Collins for repairs. Thanks to Don and AAA, especially Don, who&apos;ll likely endure horrendous traffic on I-70.&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm3.staticflickr.com/2924/14466629090_228393c9a4_c.jpg&quot; title=&quot;Introducing Max, our new trusty steed, gifted from Trish&apos;s Dad a few weeks ago. The road trip must go on! by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466629090&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2924/14466629090_228393c9a4_q.jpg&quot; width=&quot;150&quot; alt=&quot;Introducing Max, our new trusty steed, gifted from Trish&apos;s Dad a few weeks ago. The road trip must go on!&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    Instead of camping in beautiful campgrounds, we changed our plans to stay at B&amp;amp;Bs. In the meantime, Mike
    replied and said he thought he&apos;d be able to install an H6 3.0 by the end of the month. He recommended it as a good
    replacement for our SVX engine, particularly because it was more reliable and likely to endure more miles. We agreed
    to the repairs and had AAA tow it to his shop in Fort Collins.&lt;/p&gt;
&lt;p&gt;Our first destination was &lt;a href=&quot;http://www.broadmoor.com/&quot;&gt;The Broadmoor&lt;/a&gt;. We took the back way through
    Breckenridge and skipped the holiday traffic. We arrived around 5pm and were warmly welcomed, dogs and all. We
    celebrated our one-year anniversary early with excellent Italian food, golf on the West course and a fun pub crawl on
    Monday night.&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[santafe2014]&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[santafe2014]&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[santafe2014]&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;The Broadmoor was named the &lt;a href=&quot;http://www.thebroadmoorblog.com/2014/02/1-golf-resort-in-north-america/&quot;&gt;#1 Golf Resort in North
    America by Golf magazine readers&lt;/a&gt;. We certainly enjoyed the course, but it&apos;s also the first time Trish and I declined beers from the cart
    lady. Our games were so bad, we weren&apos;t in the mood to celebrate anything.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3853/14466890217_20b528c719_c.jpg&quot; title=&quot;Golf at The Broadmoor by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466890217&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3853/14466890217_20b528c719.jpg&quot; width=&quot;500&quot; alt=&quot;Golf at The Broadmoor&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
    That afternoon, we took our dogs to the
    excellent &lt;a href=&quot;http://www.yelp.com/biz/bear-creek-dog-park-colorado-springs&quot;&gt;Bear Creek Dog Park&lt;/a&gt; and sampled some beers at nearby breweries. Our favorite was the &lt;a href=&quot;http://www.broadmoor.com/golden-bee/&quot;&gt;Golden Bee&lt;/a&gt; and their &lt;em&gt;real&lt;/em&gt; yards of Guinness.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3894/14650072121_4e99c36dff_c.jpg&quot; title=&quot;Love this bark park! by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14650072121&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3894/14650072121_4e99c36dff_q.jpg&quot; width=&quot;150&quot; alt=&quot;Love this bark park!&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm3.staticflickr.com/2902/14466642180_8c2d9a4cac_c.jpg&quot; title=&quot;Real yards of beer! by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466642180&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2902/14466642180_8c2d9a4cac_q.jpg&quot; width=&quot;150&quot; alt=&quot;Real yards of beer!&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3843/14754351093_7e5147a137_c.jpg&quot; title=&quot;Yards at the Golden Bee by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14754351093&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3843/14754351093_7e5147a137_q.jpg&quot; width=&quot;150&quot; alt=&quot;Yards at the Golden Bee&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;On Tuesday afternoon, we left Colorado Springs for Pagosa Springs. There, we enjoyed a country B&amp;amp;B, soaked
    in the hot springs and had a great hike to &lt;a href=&quot;http://pagosa.com/adventureguide/fourmile-falls-hike/&quot;&gt;Fourmile
        Falls&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3874/14547866610_b3cca53f03_c.jpg&quot; title=&quot;View from Pagosa B&amp;amp;B by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14547866610&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3874/14547866610_b3cca53f03.jpg&quot; width=&quot;500&quot; alt=&quot;View from Pagosa B&amp;amp;B&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://farm3.staticflickr.com/2920/14466902057_a93e39327b_c.jpg&quot; title=&quot;Beautiful Dinner View by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466902057&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2920/14466902057_a93e39327b_q.jpg&quot; width=&quot;150&quot; alt=&quot;Beautiful Dinner View&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3853/14650082561_44ff45c654_c.jpg&quot; title=&quot;Hiking to Falls Creek Waterfall by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14650082561&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3853/14650082561_44ff45c654_q.jpg&quot; width=&quot;150&quot; alt=&quot;Hiking to Falls Creek Waterfall&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm6.staticflickr.com/5479/14651109894_1a5691e0d0_c.jpg&quot; title=&quot;Falls Creek Waterfall by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14651109894&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5479/14651109894_1a5691e0d0_q.jpg&quot; width=&quot;150&quot; alt=&quot;Falls Creek Waterfall&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;
    We left on Wednesday afternoon and drove to Taos, New
    Mexico. We had the best chilli relleno in the world, watched a bluegrass jam, visited &lt;a href=&quot;http://www.taosmesabrewing.com/&quot;&gt;Taos Mesa Brewing&lt;/a&gt;
    and hiked to &lt;a href=&quot;http://www.taostrails.com/williams_lake.html&quot;&gt;Williams Lake&lt;/a&gt;. &lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm6.staticflickr.com/5589/14732233144_b58bd533b0_c.jpg&quot; title=&quot;La Cueva Cafe: Best Mexican Food Around! by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14732233144&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5589/14732233144_b58bd533b0_s.jpg&quot; width=&quot;75&quot; alt=&quot;La Cueva Cafe: Best Mexican Food Around!&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;https://farm4.staticflickr.com/3866/14466724618_8d9613c535_c.jpg&quot; title=&quot;1000 year old buildings by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466724618&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3866/14466724618_8d9613c535_s.jpg&quot; width=&quot;75&quot; alt=&quot;1000 year old buildings&quot; style=&quot;border: 1px solid black; margin-left: 5px;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm6.staticflickr.com/5572/14466726348_3f8e7339dd_c.jpg&quot; title=&quot;Found good beer at The Bavarian Restaurant by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466726348&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5572/14466726348_3f8e7339dd_s.jpg&quot; width=&quot;75&quot; alt=&quot;Found good beer at The Bavarian Restaurant&quot; style=&quot;border: 1px solid black; margin-left: 5px;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3877/14547994229_caefa728e5_c.jpg&quot; title=&quot;Hiking to Williams Lake by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14547994229&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3877/14547994229_caefa728e5_s.jpg&quot; width=&quot;75&quot; alt=&quot;Hiking to Williams Lake&quot; style=&quot;border: 1px solid black; margin-left: 5px;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm6.staticflickr.com/5539/14673256063_74fa41633f_c.jpg&quot; title=&quot;Williams Lake by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14673256063&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5539/14673256063_74fa41633f_s.jpg&quot; width=&quot;75&quot; alt=&quot;Williams Lake&quot; style=&quot;border: 1px solid black; margin-left: 5px;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm3.staticflickr.com/2928/14466710019_e0f032fb62_c.jpg&quot; title=&quot;Happy Hikers by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14466710019&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2928/14466710019_e0f032fb62_s.jpg&quot; width=&quot;75&quot; alt=&quot;Happy Hikers&quot; style=&quot;border: 1px solid black; margin-left: 5px;&quot;&gt;&lt;/a&gt;


&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm4.staticflickr.com/3926/14548047399_6b20771668_c.jpg&quot; title=&quot;Williams Lake New Mexico by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14548047399&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3926/14548047399_6b20771668.jpg&quot; width=&quot;500&quot; alt=&quot;Williams Lake New Mexico&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://farm3.staticflickr.com/2902/14734423572_32fddf09b3_c.jpg&quot; title=&quot;Best Beer in Taos by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14734423572&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2902/14734423572_32fddf09b3.jpg&quot; width=&quot;500&quot; alt=&quot;Best Beer in Taos&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://farm4.staticflickr.com/3915/14548107659_2dfbe98ec1_c.jpg&quot; title=&quot;Taos Sunset Fence by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14548107659&quot;&gt;&lt;img src=&quot;https://farm4.staticflickr.com/3915/14548107659_2dfbe98ec1.jpg&quot; width=&quot;500&quot; alt=&quot;Taos Sunset Fence&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;On Friday, we left Taos and drove to Santa Fe, our ultimate destination. While arriving, I checked my email and was
    pleased to see an email from the folks working on my &apos;66 Bus. While flipping through the pictures referenced in the email, I
    realized there were several videos. I did my best to get us off the road and into a place where I could watch the
    videos on a proper screen. You can imagine my glee as I watched my bus drive under its own power for the first time. &lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;object type=&quot;application/x-shockwave-flash&quot; width=&quot;251&quot; height=&quot;141&quot; data=&quot;https://www.flickr.com/apps/video/stewart.swf&quot; classid=&quot;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&quot;&gt;
        &lt;param name=&quot;flashvars&quot; value=&quot;intl_lang=en-US&amp;amp;photo_secret=bcce816a9e&amp;amp;flickr_show_info_box=true&amp;amp;photo_id=14466716159&quot;&gt;
        &lt;param name=&quot;movie&quot; value=&quot;https://www.flickr.com/apps/video/stewart.swf&quot;&gt;
        &lt;param name=&quot;bgcolor&quot; value=&quot;#000000&quot;&gt;
        &lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;
        &lt;embed type=&quot;application/x-shockwave-flash&quot; src=&quot;https://www.flickr.com/apps/video/stewart.swf&quot; bgcolor=&quot;#000000&quot; allowfullscreen=&quot;true&quot; flashvars=&quot;intl_lang=en-US&amp;amp;photo_secret=bcce816a9e&amp;amp;flickr_show_info_box=true&amp;amp;photo_id=14466716159&quot; width=&quot;251&quot;&gt;
    &lt;/object&gt;
    &lt;object type=&quot;application/x-shockwave-flash&quot; width=&quot;251&quot; style=&quot;margin-left: 10px&quot; data=&quot;https://www.flickr.com/apps/video/stewart.swf&quot; classid=&quot;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&quot;&gt;
        &lt;param name=&quot;flashvars&quot; value=&quot;intl_lang=en-US&amp;amp;photo_secret=45f665577c&amp;amp;flickr_show_info_box=true&amp;amp;photo_id=14630372586&quot;&gt;
        &lt;param name=&quot;movie&quot; value=&quot;https://www.flickr.com/apps/video/stewart.swf&quot;&gt;
        &lt;param name=&quot;bgcolor&quot; value=&quot;#000000&quot;&gt;
        &lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;
        &lt;embed type=&quot;application/x-shockwave-flash&quot; src=&quot;https://www.flickr.com/apps/video/stewart.swf&quot; bgcolor=&quot;#000000&quot; allowfullscreen=&quot;true&quot; flashvars=&quot;intl_lang=en-US&amp;amp;photo_secret=45f665577c&amp;amp;flickr_show_info_box=true&amp;amp;photo_id=14630372586&quot; width=&quot;251&quot;&gt;
    &lt;/object&gt;
&lt;/p&gt;

&lt;p&gt;My &quot;achievement unlocked!&quot; moment was soon complimented by an excellent margarita and tasty New Mexican food. Wow!
    Those New Mexicans know the right level for the &quot;default&quot; hot sauce. Spicy and delicious!&lt;/p&gt;
&lt;p&gt;
    We spent the weekend with our friends Chris, Mary and Luna and had a great time. The
    Santa Fe summer weather was beautiful - in the mid-70s most of the time, with nice breezes and sunshine. Trish,
    Chris, Sagan, Jake and I took a hike on Saturday and thoroughly enjoyed their national forest. On Sunday, we marveled at the art on display at Santa Fe&apos;s &lt;a href=&quot;http://www.folkartalliance.org/&quot;&gt;11th Annual International Folk Art Market&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
    &lt;a href=&quot;https://farm6.staticflickr.com/5577/14652956982_50340e9089_c.jpg&quot; title=&quot;Old Friends by Matt Raible, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mraible/14652956982&quot;&gt;&lt;img src=&quot;https://farm6.staticflickr.com/5577/14652956982_50340e9089_q.jpg&quot; width=&quot;150&quot; alt=&quot;Old Friends&quot; style=&quot;border: 1px solid black;&quot;&gt;&lt;/a&gt;
    &lt;a href=&quot;https://farm3.staticflickr.com/2940/14548204898_627ac8fe2a_c.jpg&quot; title=&quot;Santa Fe&apos;s International Folk Art Market by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14548204898&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2940/14548204898_627ac8fe2a_q.jpg&quot; width=&quot;150&quot; alt=&quot;Santa Fe&apos;s International Folk Art Market&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;

    &lt;a href=&quot;https://farm3.staticflickr.com/2899/14734920435_3bbc938684_c.jpg&quot; title=&quot;The Alonsos by Trish McGinity, on Flickr&quot; rel=&quot;lightbox[santafe2014]&quot; data-href=&quot;https://www.flickr.com/photos/mcginityphoto/14734920435&quot;&gt;&lt;img src=&quot;https://farm3.staticflickr.com/2899/14734920435_3bbc938684_q.jpg&quot; width=&quot;150&quot; alt=&quot;The Alonsos&quot; style=&quot;border: 1px solid black; margin-left: 20px;&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;div style=&quot;text-align: right; color: #666; max-width: 500px; margin: -15px auto 0 auto&quot;&gt;
    &lt;a href=&quot;https://www.flickr.com/photos/mcginityphoto/sets/72157645941173903/&quot; title=&quot;Trish&apos;s 2014 Scenic Way to Santa Fe&quot;&gt;More&lt;/a&gt;
    &lt;a href=&quot;https://www.flickr.com/photos/mraible/sets/72157645273272880/&quot; title=&quot;Matt&apos;s The Scenic Way to Santa Fe&quot;&gt;photos&lt;/a&gt; on Flickr &amp;rightarrow;
&lt;/div&gt;
&lt;p&gt;
    The rest of the time, we hung out in their backyard. Trish played her banjo, we watched the firepit crackle and Dino
    (their new puppy) kept us entertained with his antics. It was one of the most relaxing weekends I&apos;ve had in quite
    some time. Thanks to Chris, Mary and Luna - you guys are awesome and we can&apos;t wait to visit again!&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/what_have_i_been_working</id>
        <title type="html">What have I been working on at Taleo?</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/what_have_i_been_working"/>
        <published>2011-12-09T12:57:36-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="javascript" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jquery" scheme="http://roller.apache.org/ns/tags/" />
        <category term="happiness" scheme="http://roller.apache.org/ns/tags/" />
        <category term="overstock" scheme="http://roller.apache.org/ns/tags/" />
        <category term="taleo" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">2011 has been a year of great clients for me. I started working with &lt;a href=&quot;http://overstock.com&quot;&gt;O.co&lt;/a&gt; and very much enjoyed my time there, especially on &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_greatest_snow_on_earth&quot;&gt;powder days in Utah&lt;/a&gt;. The people were great, the contract was great (no end date), but the work was not my forte. I was on a project to &lt;em&gt;modularize&lt;/em&gt; the main shopping site&apos;s codebase, which involved mostly refactoring. By refactoring, I mean creating new Maven projects, modifying lots of pom.xml files and literally moving files from one directory to another. IntelliJ made this easy, the hard part was refactoring tests, moving from EasyMock to Mockito and splitting classes into interfaces and implementations where appropriate. As a developer who likes developing UIs and visually seeing my accomplishments, the project wasn&apos;t that exciting. However, I knew that it was strategically important to O.co, so I didn&apos;t complain much.
&lt;/p&gt;
&lt;p&gt;In mid-May, I received a &lt;a href=&quot;http://www.linkedin.com&quot;&gt;LinkedIn&lt;/a&gt; message from the Director of Software Engineering at &lt;a href=&quot;http://www.taleo.com/&quot;&gt;Taleo&lt;/a&gt;. 
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
This is OB, I am the Director of Software Engineering at Taleo. We are the 2nd largest Software as a Service company. I am building a new specialist UI team that will take the product to the next level. I am looking for someone to lead this initiative. If you are interested to have a chat about it, please let me know.
&lt;/p&gt;
&lt;p&gt;At that time, I&apos;d never heard of Taleo and quickly recommended they not hire me.&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
This probably isn&apos;t the best position for me. While I am a good leader, I&apos;m not willing to relocate from Denver. I&apos;ve found that leaders usually do best when face-to-face with their developers.
&lt;/p&gt;
&lt;p&gt;This conversation continued back-and-forth where I explained how I wasn&apos;t willing to go full-time and I didn&apos;t want to leave Overstock. In the end, OB was persistent and explained how the position would entail lots of UI work and wouldn&apos;t require me to travel much. Our negotiations trailed off in June and resumed in July after I returned &lt;a href=&quot;http://raibledesigns.com/rd/entry/4th_of_july_adventures_in&quot;&gt;from vacation in Montana&lt;/a&gt;. Shortly after, we met each other&apos;s expectations, agreed on a start date and I started working at Taleo in early September. 
&lt;/p&gt;
&lt;p&gt;When I started, there were three features they wanted to add to to &lt;a href=&quot;http://www.taleo.com/solutions/taleo-business-edition&quot;&gt;Taleo Business Edition&lt;/a&gt;: Profile Pictures, Talent Cards and Org Charts. They knew the schedule was tight (8 weeks), but I was confident I could make it happen. At first, I groaned at the fact that they were using Ant to build the project. Then I smiled when I learned they&apos;d standardized on IntelliJ and set things up so you could do everything from the IDE. After using Maven for many years, this setup has actually become refreshing and I rarely have to restart or long for something like JRebel. Of course, a &lt;a href=&quot;http://raibledesigns.com/rd/entry/new_macbook_pro_and_imac&quot;&gt;new kick-ass laptop&lt;/a&gt; and &lt;a href=&quot;http://blogs.jetbrains.com/idea/2011/12/intellij-idea-11-is-out-get-ready-for-a-productivity-takeoff/&quot;&gt;awesome IDE&lt;/a&gt; make it so I rarely wait for anything to happen.
&lt;/p&gt;
&lt;p&gt;
To give you a taste of how I implemented each of these new features in 8 weeks, I&apos;ve broken them into sections below.
&lt;/p&gt;
&lt;p id=&quot;profile-pictures&quot;&gt;&lt;strong&gt;Profile Pictures&lt;/strong&gt;&lt;br/&gt;
Adding profile pictures was a pretty simple concept, one you see on my social networking sites today. I needed to give users the ability to upload a JPEG or PNG and crop it so it looked good. The uploading was a pretty straightforward process and I used a lot of internal APIs to grab the file from the request and save it to disk. The more difficult part was scaling the image to certain dimensions on upload (to save space) and allowing users to crop it after. 
&lt;/p&gt;
&lt;p&gt;Most of Taleo Business Edition (TBE) is written in good ol&apos; servlets and JSPs, with lots of scriptlets in their JSPs. When I saw the amount of HTML produced from Java, I laughed out loud and cringed. Soon after, I breathed a sigh of relief when I learned that any new features could be written using &lt;a href=&quot;http://freemarker.sourceforge.net/&quot;&gt;FreeMarker&lt;/a&gt; templates, which IntelliJ has excellent support for.
&lt;/p&gt;
&lt;p&gt;For image resizing on upload, I used Chris Campbell&apos;s &lt;a href=&quot;http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html&quot;&gt;Image.getScaledInstance() tutorial&lt;/a&gt;. For creating thumbnails, I used a combination of scaling, &lt;a href=&quot;http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferedImage.html#getSubimage(int, int, int, int)&quot;&gt;getSubimage()&lt;/a&gt; and the &lt;a href=&quot;http://docs.oracle.com/javase/6/docs/api/javax/imageio/package-summary.html&quot;&gt;Java Image I/O API&lt;/a&gt;. I made sure to &lt;a href=&quot;http://stackoverflow.com/questions/3204280/is-imageio-write-buffered&quot;&gt;write to BufferedOutputStream&lt;/a&gt; for scalability. For cropping images client-side, I used &lt;a href=&quot;http://jqueryui.com/demos/dialog/&quot;&gt;jQuery UI&apos;s Dialog&lt;/a&gt; and &lt;a href=&quot;http://deepliquid.com/content/Jcrop.html&quot;&gt;Jcrop&lt;/a&gt;, the jQuery image cropping plugin. Below is a screenshot of what the cropping UI looks like:
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm8.staticflickr.com/7142/6475456591_6831fd119e_b.jpg&quot; title=&quot;Taleo&apos;s TBE: Profile Picture&quot; rel=&quot;lightbox[taleo]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7142/6475456591_6831fd119e.jpg&quot; width=&quot;500&quot; height=&quot;176&quot; alt=&quot;Taleo&apos;s TBE: Profile Picture&quot;&gt;&lt;/a&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p id=&quot;talent-cards&quot;&gt;&lt;strong&gt;Talent Cards&lt;/strong&gt;&lt;br/&gt;
Talent Cards were a whole different beast. Not only did they need to display profile pictures, they also needed to contain contact information, work history and a number of other data points. Not just for employees, but for candidates as well. 
They also needed to be rendered with tabs at the bottom that allowed you to navigate between different data sections. 
&lt;/p&gt;
&lt;p&gt;

&lt;a href=&quot;http://farm8.staticflickr.com/7032/6475456677_ae342be56e_o.png&quot; title=&quot;Taleo&apos;s TBE: Talent Card&quot; rel=&quot;lightbox[taleo]&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7032/6475456677_a06514020d_m.jpg&quot; width=&quot;187&quot; height=&quot;240&quot; alt=&quot;Taleo&apos;s TBE: Talent Card&quot; class=&quot;picture&quot; style=&quot;border: 0&quot;&gt;&lt;/a&gt;

I&apos;ll admit, most of the hard work for this feature was done by the server-side developers (Harish and &lt;a href=&quot;http://www.linkedin.com/in/vladimirbazarsky&quot;&gt;Vlad&lt;/a&gt;) on my team. Vlad built the tabbed interface and Harish built the administrative section that allows you to add/remove/sort fields, as well as show and hide certain tabs. I performed most of my magic with jQuery, its &lt;a href=&quot;http://plugins.learningjquery.com/cluetip/&quot;&gt;clueTip plugin&lt;/a&gt; and good ol&apos; CSS. I was particularly thankful for CSS3 and its border-radius, box-shadow and Justin Maxwell&apos;s tutorial on &lt;a href=&quot;http://mattsnider.com/css/css-string-truncation-with-ellipsis/&quot;&gt;CSS String Truncation with Ellipsis&lt;/a&gt;. I used &lt;a href=&quot;http://directwebremoting.org/dwr/index.html&quot;&gt;DWR&lt;/a&gt; to fetch all the data from the server using Ajax. 
&lt;/p&gt;
&lt;p&gt;Talent Cards are a slick feature in TBE 11.5 and I think they&apos;re a great way to see a lot of information about someone very quickly. If you enable them for your company, you&apos;ll be able to mouse over any employee or candidate&apos;s names and see their information.
&lt;/p&gt;
&lt;p id=&quot;org-chart&quot;&gt;&lt;strong&gt;Org Chart&lt;/strong&gt;&lt;br/&gt;
The last feature I completed in this 8-week sprint was creating an organization chart. For this, I was given a rough prototype based on &lt;a href=&quot;http://www.capricasoftware.co.uk/corp/index.php&quot;&gt;Caprica Software&apos;s&lt;/a&gt; &lt;a href=&quot;http://www.capricasoftware.co.uk/jquery/orgchart/orgchart.html&quot;&gt;JQuery/CSS Organisation Chart&lt;/a&gt;. When I received it, it had all kinds of cool CSS 3 transformations (like &lt;a href=&quot;http://css3.bradshawenterprises.com/flip/&quot;&gt;this one&lt;/a&gt;), but they only worked in Safari and Chrome. I ended up removing the transformations and adding the ability to navigate up and down the org tree with Ajax (we currently only show three levels at a time). 
&lt;/p&gt;
&lt;p&gt;
The Org Chart feature also allows you to see how many direct/indirect reports an employee has, as well as access their Talent Card by hovering over their name. It&apos;s one of my favorite features because it&apos;s so visual and because it builds upon all the other features we&apos;ve built.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;http://farm8.staticflickr.com/7148/6483181659_619285347d_o.png&quot; rel=&quot;lightbox[taleo]&quot; title=&quot;Taleo&apos;s TBE: Org Chart&quot;&gt;&lt;img src=&quot;//farm8.staticflickr.com/7148/6483181659_7434afaeee.jpg&quot; width=&quot;487&quot; height=&quot;500&quot; alt=&quot;Taleo&apos;s TBE: Org Chart&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
As you might&apos;ve guessed by now, I&apos;ve been having a lot of fun doing UI development over the last few months. While I seem to have a knack for backend Java development, I enjoy developing UIs a lot more. The smile you see on people&apos;s faces during demos is priceless. I can&apos;t help but think this kind of thing contributes greatly to my developer happiness. All these features will be in next week&apos;s release of TBE and I couldn&apos;t be happier.
&lt;/p&gt;
&lt;p&gt;If you&apos;d like to work on my team at Taleo (or even take over my current role as UI Architect), please &lt;a href=&quot;http://raibledesigns.com/contact.jsp&quot;&gt;drop me a line&lt;/a&gt;. If you live near their headquarters (Dublin, CA), it&apos;d also be great to see you at the next Silicon Valley Spring User Group meetup. I&apos;ll be speaking about &lt;a href=&quot;http://www.meetup.com/SV-SUG/events/43376082/&quot;&gt;What&apos;s New in Spring 3.1 on February 1st&lt;/a&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_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/java_web_application_security_part1</id>
        <title type="html">Java Web Application Security - Part II: Spring Security 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_part1"/>
        <published>2011-05-13T09:20:51-06:00</published>
        <updated>2015-07-07T01:36:15-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="presentation" 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="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ujug" scheme="http://roller.apache.org/ns/tags/" />
        <category term="web" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last week, I wrote &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part&quot;&gt;a tutorial on how to implement Security in 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://static.springsource.org/spring-security/site/&quot;&gt;Spring Security&lt;/a&gt;. Before I begin, I&apos;d like to explain my reason for writing this article.
&lt;/p&gt;
&lt;p&gt;Last month, I presented a talk on Java Web Application Security at the &lt;a href=&quot;http://ujug.org&quot;&gt;Utah JUG&lt;/a&gt; (UJUG). As part of that presentation, I did a number of demos about how to implement security with Java EE 6, Spring Security and Apache Shiro. I told the audience that I would post the presentation and was planning on recording screencasts of the various demos so the online version of the presentation would make more sense. 
&lt;/p&gt;
&lt;p&gt;
Today, I&apos;ve finished the second screencast showing how to implement security with Spring Security. Below is the presentation (with the screencast embedded on slide 16) 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=K5Hf-2bKYu8&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;springsecurity-login-tutorial&quot;&gt;&lt;strong&gt;Spring Security 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;#remember-me&quot;&gt;Add Remember Me&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-springsecurity-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 Spring context file that contains Spring Security&apos;s configuration. Create &lt;em&gt;src/main/webapp/WEB-INF/security.xml&lt;/em&gt; and populate it with the contents 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;
               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&quot;&amp;gt;

      &amp;lt;!-- New in Spring Security 3.1 --&amp;gt;
      &amp;lt;!-- &amp;lt;http pattern=&quot;/css/**&quot; security=&quot;none&quot;/&amp;gt; --&amp;gt;

      &amp;lt;http auto-config=&quot;true&quot;&amp;gt;
          &amp;lt;intercept-url pattern=&quot;/app/users&quot; access=&quot;ROLE_USER,ROLE_ADMIN&quot;/&amp;gt;
          &amp;lt;http-basic/&amp;gt;
      &amp;lt;/http&amp;gt;

      &amp;lt;authentication-manager alias=&quot;authenticationManager&quot;&amp;gt;
          &amp;lt;authentication-provider&amp;gt;
              &amp;lt;password-encoder hash=&quot;sha&quot;/&amp;gt;
              &amp;lt;user-service&amp;gt;
                  &amp;lt;user name=&quot;user&quot; password=&quot;12dea96fec20593566ab75692c9949596833adc9&quot; authorities=&quot;ROLE_USER&quot;/&amp;gt;
                  &amp;lt;user name=&quot;admin&quot; password=&quot;d033e22ae348aeb5660fc2140aec35850c4da997&quot; authorities=&quot;ROLE_ADMIN&quot;/&amp;gt;
              &amp;lt;/user-service&amp;gt;
          &amp;lt;/authentication-provider&amp;gt;
      &amp;lt;/authentication-manager&amp;gt;

      &amp;lt;!-- Override userSecurityAdvice bean in appfuse-service to allow any role to update a user. --&amp;gt;
      &amp;lt;beans:bean id=&quot;userSecurityAdvice&quot; class=&quot;org.appfuse.examples.webapp.security.UserSecurityAdvice&quot;/&amp;gt;
  &amp;lt;/beans:beans&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
The last bean, userSecurityAdvice, is an aspect that&apos;s needed to override some behavior in &lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt;. You won&apos;t need this normally when implementing Spring Security. 
&lt;/p&gt;
&lt;p&gt;Next, open &lt;em&gt;src/main/webapp/WEB-INF/web.xml&lt;/em&gt; and add Spring&apos;s DelegatingFilterProxy:&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.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;
&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;
You don&apos;t need to add any dependencies in your pom.xml is because this project depends on AppFuse, which already contains these dependencies.
&lt;/p&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. Spring Security is a bit easier to configure than Java EE 6 out-of-the-box, mostly because it doesn&apos;t require you to configure your container.
&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: Spring Security has a way to configure &quot;logout&quot; to match a URL and get rid of a class like LogoutController. Since it was already in the project, I don&apos;t cover that in this tutorial.&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 Spring Security.
&lt;/p&gt;
&lt;p id=&quot;ssl&quot;&gt;&lt;strong&gt;Force SSL&lt;/strong&gt;&lt;br/&gt;
Spring Security allows you to switch between secure (https) and non-secure (http) protocols using a simple &lt;em&gt;requires-channel&lt;/em&gt; attribute on the &amp;lt;intercept-url&amp;gt; element. Possible values are &quot;http&quot;, &quot;https&quot; and &quot;any&quot;. Add &lt;em&gt;requires-channel=&quot;https&quot;&lt;/em&gt; to your security.xml file:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;intercept-url pattern=&quot;/app/users&quot; access=&quot;ROLE_USER,ROLE_ADMIN&quot; requires-channel=&quot;https&quot;/&amp;gt;
&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. This is an 
  improvement on Java EE&apos;s user-data-constraint for two reasons:
  &lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;You can switch between http and https protocols. With Java EE, you can only force https. You have to write a custom filter to switch back to http.&lt;/li&gt;
    &lt;li&gt;Redirecting to https actually works. With Java EE (on Jetty at least), a 403 is returned instead of redirecting the request.&lt;/li&gt;
  &lt;/ul&gt;
&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 &amp;lt;form-login&amp;gt; element in security.xml&apos;s &amp;lt;http&amp;gt; element:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;http auto-config=&quot;true&quot;&amp;gt;
    &amp;lt;intercept-url pattern=&quot;/app/users&quot; access=&quot;ROLE_USER,ROLE_ADMIN&quot; requires-channel=&quot;https&quot;/&amp;gt;
    &amp;lt;form-login login-page=&quot;/login&quot; authentication-failure-url=&quot;/login?error=true&quot;
                login-processing-url=&quot;/j_security_check&quot;/&amp;gt;
    &amp;lt;http-basic/&amp;gt;
&amp;lt;/http&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
  You can leave the &amp;lt;http-basic&amp;gt; element since Spring Security is smart enough to serve up the form for browsers and use Basic Authentication for clients such as web services.
  
  The login.jsp page (that /login forwards to) already exists in the project, in the &lt;em&gt;src/main/webapp&lt;/em&gt; directory. The forwarding is done by the &lt;a href=&quot;http://www.tuckey.org/urlrewrite/&quot;&gt;UrlRewriteFilter&lt;/a&gt; with the following configuration in &lt;em&gt;src/main/webapp/WEB-INF/urlrewrite.xml&lt;/em&gt;. 
  
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;rule&amp;gt;
    &amp;lt;from&amp;gt;/login&amp;lt;/from&amp;gt;
    &amp;lt;to&amp;gt;/login.jsp&amp;lt;/to&amp;gt;
&amp;lt;/rule&amp;gt;
&lt;/pre&gt;  
&lt;p&gt;
  This JSP has 3 important elements: 1) a form that submits to &quot;/j_security_check&quot;, 2) an input element named &quot;j_username&quot; and 3) an input element named &quot;j_password&quot;. If you restart Jetty, you&apos;ll now be prompted to login with this JSP instead of the basic authentication dialog.
&lt;/p&gt;
&lt;p id=&quot;remember-me&quot;&gt;&lt;strong&gt;Add Remember Me&lt;/strong&gt;&lt;br/&gt;
Remember Me is a feature you see in many web applications today. It&apos;s usually a checkbox on the login form that allows you to auto-login the next time you visit a site. This feature doesn&apos;t exist in Java EE security, but it does exist in Spring Security. To enable it, add the following just below &amp;lt;form-login&amp;gt; in security.xml:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;remember-me user-service-ref=&quot;userDao&quot; key=&quot;e37f4b31-0c45-11dd-bd0b-0800200c9a66&quot;/&gt;
&lt;/pre&gt;
&lt;p&gt;Next, open &lt;em&gt;src/main/webapp/login.jsp&lt;/em&gt; and change the name of the &quot;remember me&quot; checkbox to be &lt;strong&gt;_spring_security_remember_me&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;input type=&quot;checkbox&quot; name=&quot;_spring_security_remember_me&quot; id=&quot;rememberMe&quot;/&gt;
&lt;/pre&gt;
&lt;p&gt;After making these changes, you should be able to restart Jetty, go to &lt;a href=&quot;http://localhost:8080/users&quot;&gt;http://localhost:8080/users&lt;/a&gt;, enter admin/adminjdbc, check the Remember Me checkbox and login. Then close your browser, and repeat the process. This time, you won&apos;t be prompted to login. For more information on this feature, see &lt;a href=&quot;http://static.springsource.org/spring-security/site/docs/3.0.x/reference/remember-me.html&quot;&gt;Spring Security&apos;s Remember Me documentation&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
While storing usernames and passwords in a file is convenient for demos, it&apos;s not very real-world-ish. The next section shows you how to configure Spring Security to use a database for its user store.
&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 &lt;em&gt;user-service-ref&lt;/em&gt; attribute to the &amp;lt;authentication-provider&amp;gt; element. You can also delete the &amp;lt;user-service&amp;gt; element. 
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;authentication-manager alias=&quot;authenticationManager&quot;&amp;gt;
    &amp;lt;authentication-provider user-service-ref=&quot;userDao&quot;&amp;gt;
        &amp;lt;password-encoder hash=&quot;sha&quot;/&amp;gt;
    &amp;lt;/authentication-provider&amp;gt;
&amp;lt;/authentication-manager&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The &quot;userDao&quot; bean is provided by AppFuse and its &lt;a href=&quot;http://static.appfuse.org/appfuse-data/appfuse-hibernate/xref/org/appfuse/dao/hibernate/UserDaoHibernate.html&quot;&gt;UserDaoHibernate.java&lt;/a&gt; class. This 
  class implements Spring Security&apos;s &lt;a href=&quot;http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/core/userdetails/UserDetailsService.html&quot;&gt;UserDetailsService&lt;/a&gt; interface.
  With Java EE, I had to configure a database connection and make sure the JDBC Driver was in my container&apos;s classpath. With Spring Security, you can talk to the database you already have configured in your application.
&lt;/p&gt;
&lt;div class=&quot;quote&quot; style=&quot;margin-left: 0; color: #666&quot;&gt;Of course, you could do this with Java EE too. One thing I neglected to show in my last tutorial was that 1) the app uses H2 and 2) I had to configure Java EE&apos;s database to be MySQL. This was because when I tried to access my H2 instance, I got an error about two threads trying to access it at once.
&lt;pre style=&quot;margin-top: 10px; margin-bottom: 0&quot;&gt;
2011-05-13 08:47:29.081:WARN::UserRealm Java EE Login could not connect to database; will try later
org.h2.jdbc.JdbcSQLException: Database may be already in use: &quot;Locked by another process&quot;. 
        Possible solutions: close all other connection(s); use the server mode [90020-154]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
	at org.h2.message.DbException.get(DbException.java:167)
	at org.h2.message.DbException.get(DbException.java:144)
	at org.h2.store.FileLock.getExceptionAlreadyInUse(FileLock.java:443)
	at org.h2.store.FileLock.lockFile(FileLock.java:338)
	at org.h2.store.FileLock.lock(FileLock.java:134)
	at org.h2.engine.Database.open(Database.java:535)
	at org.h2.engine.Database.openDatabase(Database.java:218)
&lt;/pre&gt;
&lt;/div&gt;
&lt;/p&gt;
&lt;!-- Figure out exact error from H2 --&gt;
&lt;p&gt;The password for the &quot;admin&quot; user is configured in &lt;em&gt;src/test/resources/sample-data.xml&lt;/em&gt; and it&apos;s loaded by &lt;a href=&quot;http://dbunit.sourceforge.net/&quot;&gt;DbUnit&lt;/a&gt; before the application starts. 
  You can view your pom.xml and the dbunit-maven-plugin&apos;s configuration if you&apos;re interested in learning how this is done. The password is currently configured to &quot;adminjdbc&quot;, but you can reset it by
  &lt;a href=&quot;http://darrenfauth.com/generators/sha1&quot;&gt;generating a new password&lt;/a&gt; and modifying sample-data.xml.
&lt;/p&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 Spring Security 3.0.5. In addition to the basic XML configuration, Spring Security also provides a AOP support and annotations you can use to secure methods. It also has many more features than standard Java EE Security. In my opinion, it&apos;s the most mature security framework we have in Java today. Currently, I think its &lt;a href=&quot;http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity.html&quot;&gt;reference documentation&lt;/a&gt; is the best place to learn more.
&lt;/p&gt;
There are a few limitations I found with Spring Security:
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;The authentication mechanism (file, database, ldap, etc.) is contained in the WAR&lt;/li&gt;
&lt;li&gt;Securing methods only works on Spring beans&lt;/li&gt;
&lt;li&gt;Remember Me doesn&apos;t work in my screencast (because I forgot to rename the checkbox in login.jsp)&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;&lt;p&gt;Of course, you can configure Spring to load its configuration from outside the WAR (e.g. a file or JNDI), but it&apos;s not as easy as including the configuration in your app.
  &lt;/p&gt;
  &lt;p&gt;In the next couple weeks, I&apos;ll post &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part2&quot;&gt;Part III&lt;/a&gt; of this series, where I&apos;ll show you how to implement this same set of features using Apache Shiro. In the meantime, please let me know if you have any questions.
&lt;/p&gt;
&lt;p style=&quot;border-top: 1px dotted silver; padding-top: 5px; color: #666&quot;&gt;
I created the screencasts with &lt;a href=&quot;http://www.techsmith.com/camtasia/&quot; style=&quot;color: #666&quot;&gt;Camtasia&lt;/a&gt;. For small screens, and embedding in the presentation, I created it at 50% and used the SmartFocus feature to zoom in and out during the demo. For larger screens, I published &lt;a href=&quot;http://www.youtube.com/watch?v=poc5dyImbig&quot; style=&quot;color: #666&quot;&gt;another screencast at 100%, in HD&lt;/a&gt;. If you have a preference for which screencast is better, I&apos;d love to hear about it.&lt;/p&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/java_web_application_security_part</id>
        <title type="html">Java Web Application Security - Part I: Java EE 6 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_part"/>
        <published>2011-05-05T16:58:00-06:00</published>
        <updated>2022-08-22T14:56:40-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="ujug" scheme="http://roller.apache.org/ns/tags/" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javaee" scheme="http://roller.apache.org/ns/tags/" />
        <category term="web" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="presentation" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;p&gt;Back in February, I &lt;a href=&quot;http://raibledesigns.com/rd/entry/upcoming_conferences_tssjs_in_las&quot;&gt;wrote about my upcoming conferences&lt;/a&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #666; border-top: 1px dotted silver; padding-top: 10px; margin-top: -5px&quot;&gt;
In addition to Vegas and Poland, there&apos;s a couple other events I might speak at in the next few months: the &lt;a href=&quot;http://www.ujug.org/&quot;&gt;Utah Java Users Group&lt;/a&gt; (possibly in April), &lt;a href=&quot;http://jazoon.com/&quot;&gt;Jazoon&lt;/a&gt; and &lt;a href=&quot;http://uberconf.com/conference/denver/2011/07/home&quot;&gt;&#220;berConf&lt;/a&gt; (if my proposals are accepted). For these events, I&apos;m hoping to present the following talk:
&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;Fast forward a couple months and I&apos;m happy to say that I&apos;ve completed my talk at the Utah JUG and it&apos;s been accepted at Jazoon and &#220;ber Conf. For this talk, I created a presentation that primarily consists of demos implementing basic, form and Ajax authentication using &lt;a href=&quot;http://download.oracle.com/javaee/6/tutorial/doc/gkbaa.html&quot;&gt;Java EE 6&lt;/a&gt;, &lt;a href=&quot;http://static.springsource.org/spring-security/site/&quot;&gt;Spring Security&lt;/a&gt; and &lt;a href=&quot;http://shiro.apache.org/&quot;&gt;Apache Shiro&lt;/a&gt;. In the process of creating the demos, I learned (or re-educated myself) how to do a number of things in all 3 frameworks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement Basic Authentication&lt;/li&gt;
&lt;li&gt;Implement Form-based Authentication&lt;/li&gt;
&lt;li&gt;Implement Ajax HTTP -&gt; HTTPS Authentication (with programmatic APIs)&lt;/li&gt;
&lt;li&gt;Force SSL for certain URLs&lt;/li&gt;
&lt;li&gt;Implement a file-based store of users and passwords (in Jetty/Maven and Tomcat standalone)&lt;/li&gt;
&lt;li&gt;Implement a database store of users and passwords (in Jetty/Maven and Tomcat standalone)&lt;/li&gt;
&lt;li&gt;Encrypt Passwords&lt;/li&gt;
&lt;li&gt;Secure methods with annotations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the demos, I showed the audience how to do almost all of these, but skipped Tomcat standalone and securing methods in the interest of time. In July, when I do this talk at &#220;berConf, I plan on adding 1) hacking the app (to show security holes) and 2) fixing it to protect it against vulnerabilities. 
&lt;/p&gt;
&lt;p&gt;I told the audience at UJUG that I would post the presentation and was planning on recording screencasts of the various demos so the online version of the presentation would make more sense. Today, I&apos;ve finished the first screencast showing how to implement security with Java EE 6. Below is the presentation (with the screencast embedded on slide 10) as well as a step-by-step tutorial.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object id=&quot;__sse7850034&quot; width=&quot;510&quot; height=&quot;426&quot;&gt; &lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=javawebapplicationsecurityujug2011-110505121131-phpapp02&amp;stripped_title=java-web-application-security-utah-jug-2011&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;__sse7850034&quot; src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=javawebapplicationsecurityujug2011-110505121131-phpapp02&amp;stripped_title=java-web-application-security-utah-jug-2011&amp;userName=mraible&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;510&quot; height=&quot;426&quot;&gt;&lt;/embed&gt; &lt;/object&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=4LD4mF5ex2U&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;javaee6-login-tutorial&quot;&gt;&lt;strong&gt;Java EE 6 Login Tutorial&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://raibledesigns.com/rd/entry/java_web_application_security_part#download-run&quot;&gt;Download and Run the Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raibledesigns.com/rd/entry/java_web_application_security_part#secure-basic&quot;&gt;Implement Basic Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raibledesigns.com/rd/entry/java_web_application_security_part#form-authentication&quot;&gt;Implement Form-based Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raibledesigns.com/rd/entry/java_web_application_security_part#ssl&quot;&gt;Force SSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raibledesigns.com/rd/entry/java_web_application_security_part#jdbc&quot;&gt;Store Users in a Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raibledesigns.com/rd/entry/java_web_application_security_part#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-javaee-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, add the following to the bottom of &lt;em&gt;src/main/webapp/WEB-INF/web.xml&lt;/em&gt;:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;security-constraint&amp;gt;
    &amp;lt;web-resource-collection&amp;gt;
        &amp;lt;web-resource-name&amp;gt;users&amp;lt;/web-resource-name&amp;gt;
        &amp;lt;url-pattern&amp;gt;/users&amp;lt;/url-pattern&amp;gt;
        &amp;lt;http-method&amp;gt;GET&amp;lt;/http-method&amp;gt;
        &amp;lt;http-method&amp;gt;POST&amp;lt;/http-method&amp;gt;
    &amp;lt;/web-resource-collection&amp;gt;
    &amp;lt;auth-constraint&amp;gt;
        &amp;lt;role-name&amp;gt;ROLE_ADMIN&amp;lt;/role-name&amp;gt;
    &amp;lt;/auth-constraint&amp;gt;
&amp;lt;/security-constraint&amp;gt;

&amp;lt;login-config&amp;gt;
    &amp;lt;auth-method&amp;gt;BASIC&amp;lt;/auth-method&amp;gt;
    &amp;lt;realm-name&amp;gt;Java EE Login&amp;lt;/realm-name&amp;gt;
&amp;lt;/login-config&amp;gt;

&amp;lt;security-role&amp;gt;
    &amp;lt;role-name&amp;gt;ROLE_ADMIN&amp;lt;/role-name&amp;gt;
&amp;lt;/security-role&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
At this point, if you restart Jetty (Ctrl+C and jetty:run again), you&apos;ll get an error about a missing LoginService. This happens because Jetty doesn&apos;t know where the &quot;Java EE Login&quot; realm is located. Add the following to &lt;em&gt;pom.xml&lt;/em&gt;, just after &amp;lt;/webAppConfig&gt; in the Jetty plugin&apos;s configuration.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;loginServices&amp;gt;
    &amp;lt;loginService implementation=&quot;org.eclipse.jetty.security.HashLoginService&quot;&amp;gt;
        &amp;lt;name&amp;gt;Java EE Login&amp;lt;/name&amp;gt;
        &amp;lt;config&amp;gt;${basedir}/src/test/resources/realm.properties&amp;lt;/config&amp;gt;
    &amp;lt;/loginService&amp;gt;
&amp;lt;/loginServices&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The realm.properties file already exists in the project and contains user names and passwords. Start the app again using &lt;strong&gt;mvn jetty:run&lt;/strong&gt; and you should be prompted to login when you click on the &quot;Users&quot; tab. Enter admin/admin to login.
&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&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.
&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 replace the &amp;lt;login-config&amp;gt; in your web.xml with the following:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;login-config&amp;gt;
    &amp;lt;auth-method&amp;gt;FORM&amp;lt;/auth-method&amp;gt;
    &amp;lt;form-login-config&amp;gt;
        &amp;lt;form-login-page&amp;gt;/login.jsp&amp;lt;/form-login-page&amp;gt;
        &amp;lt;form-error-page&amp;gt;/login.jsp?error=true&amp;lt;/form-error-page&amp;gt;
    &amp;lt;/form-login-config&amp;gt;
&amp;lt;/login-config&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The login.jsp page already exists in the project, in the &lt;em&gt;src/main/webapp&lt;/em&gt; directory. This JSP has 3 important elements: 1) a form that submits to &quot;${contextPath}/j_security_check&quot;, 2) an input element named &quot;j_username&quot; and 3) an input element named &quot;j_password&quot;. If you restart Jetty, you&apos;ll now be prompted to login with this JSP instead of the basic authentication dialog.
&lt;/p&gt;
&lt;p id=&quot;ssl&quot;&gt;&lt;strong&gt;Force SSL&lt;/strong&gt;&lt;br/&gt;
Another thing you might want to implement to secure your application is forcing SSL for certain URLs. To do this on the same &amp;lt;security-constraint&amp;gt; you already have in web.xml, add the following after &amp;lt;/auth-constraint&gt;:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;user-data-constraint&amp;gt;
    &amp;lt;transport-guarantee&amp;gt;CONFIDENTIAL&amp;lt;/transport-guarantee&amp;gt;
&amp;lt;/user-data-constraint&amp;gt;
&lt;/pre&gt;
&lt;p&gt;To configure Jetty to listen on an SSL port, add the following just after &amp;lt;/loginServices&amp;gt; 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 http://localhost:8080 and click on the &quot;Users&quot; tab, you&apos;ll get a 403. What the heck?! When this first happened to me, it took me a while to figure out. It turns out that Jetty doesn&apos;t redirect to HTTPS when using Java EE authentication, so you have to manually type in &lt;a href=&quot;https://localhost:8443/&quot;&gt;https://localhost:8443/&lt;/a&gt; (or add a filter to redirect for you). If you deployed this same application on Tomcat (after &lt;a href=&quot;http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html&quot;&gt;enabling SSL&lt;/a&gt;), it would redirect for you.
&lt;/p&gt;
&lt;p id=&quot;jdbc&quot;&gt;&lt;strong&gt;Store Users in a Database&lt;/strong&gt;&lt;br/&gt;
Finally, to store your users in a database instead of file, you&apos;ll need to change the &amp;lt;loginService&amp;gt; in the Jetty plugin&apos;s configuration. Replace the existing &amp;lt;loginService&amp;gt; element with the following:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;loginServices&amp;gt;
    &amp;lt;loginService implementation=&quot;org.eclipse.jetty.security.JDBCLoginService&quot;&amp;gt;
        &amp;lt;name&amp;gt;Java EE Login&amp;lt;/name&amp;gt;
        &amp;lt;config&amp;gt;${basedir}/src/test/resources/jdbc-realm.properties&amp;lt;/config&amp;gt;
    &amp;lt;/loginService&amp;gt;
&amp;lt;/loginServices&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The jdbc-realm.properties file already exists in the project and contains the database settings and table/column names for the user and role information.
&lt;/p&gt;
&lt;pre&gt;
jdbcdriver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost/appfuse
username = root
password =
usertable = app_user
usertablekey = id
usertableuserfield = username
usertablepasswordfield = password
roletable = role
roletablekey = id
roletablerolefield = name
userroletable = user_role
userroletableuserkey = user_id
userroletablerolekey = role_id
cachetime = 300
&lt;/pre&gt;
&lt;p&gt;Of course, 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 and populate it using the following commands:
&lt;/p&gt;
&lt;pre&gt;
mysql -u root -p -e &apos;create database appfuse&apos;
curl https://gist.github.com/raw/958091/ceecb4a6ae31c31429d5639d0d1e6bfd93e2ea42/create-appfuse.sql &gt; create-appfuse.sql
mysql -u root -p appfuse &amp;lt; create-appfuse.sql
&lt;/pre&gt;
&lt;p&gt;Next you&apos;ll need to configure Jetty so it has MySQL&apos;s JDBC Driver in its classpath. To do this, add the following dependency just after the &amp;lt;configuration&amp;gt; element (before &amp;lt;executions&amp;gt;) in pom.xml:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependencies&amp;gt;
    &amp;lt;!-- MySQL for JDBC Realm --&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;mysql&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;mysql-connector-java&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;5.1.14&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Now run the &lt;em&gt;jetty-password.sh&lt;/em&gt; file in the root directory of the project to generate a password of your choosing. For example:&lt;/p&gt;
&lt;pre&gt;
$ sh jetty-password.sh javaeelogin
javaeelogin
OBF:1vuj1t2v1wum1u9d1ugo1t331uh21ua51wts1t3b1vur
MD5:53b176e6ce1b5183bc970ef1ebaffd44
&lt;/pre&gt;&lt;p&gt;The last two lines are obfuscated and MD5 versions of the password. Update the &lt;strong&gt;admin&lt;/strong&gt; user&apos;s password to this new value. You can do this with the following SQL statement.
&lt;/p&gt;
&lt;pre&gt;
UPDATE app_user SET password=&apos;MD5:53b176e6ce1b5183bc970ef1ebaffd44&apos; WHERE username = &apos;admin&apos;;
&lt;/pre&gt;
&lt;p&gt;Now if you restart Jetty, you should be able to login with admin/javaeelogin 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 standard Java EE 6. In addition to the basic XML configuration, there&apos;s also some new methods in HttpServletRequest for Java EE 6 and Servlet 3.0:
&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;This tutorial doesn&apos;t show you how to use them, but I did play with them a bit as part of my UJUG demo when implementing Ajax authentication. I found that login() did work, but it didn&apos;t persist the authentication for the users session. I also found that after calling logout(), I still needed to invalidate the session to completely logout the user. There are some additional limitations I found with Java EE authentication, namely:
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;No error messages for failed logins&lt;/li&gt;
&lt;li&gt;No Remember Me&lt;/li&gt;
&lt;li&gt;No auto-redirect from HTTP to HTTPS&lt;/li&gt;
&lt;li&gt;Container has to be configured&lt;/li&gt;
&lt;li&gt;Doesn&#8217;t support regular expressions for URLs&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Of course, no error messages indicating why login failed is probably a good thing (you don&apos;t want to tell users why their credentials failed). However, when you&apos;re trying to figure out if your container is configured properly, the lack of container logging can be a pain.
  &lt;/p&gt;
  &lt;p&gt;In the next couple weeks, I&apos;ll post &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_application_security_part1&quot;&gt;Part II&lt;/a&gt; of this series, where I&apos;ll show you how to implement this same set of features using Spring Security. In the meantime, please let me know if you have any questions.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/livin_it_up_in_vegas</id>
        <title type="html">Livin&apos; it up in Vegas at TSSJS 2011</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/livin_it_up_in_vegas"/>
        <published>2011-03-22T09:04:17-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="vegas" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tssjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="perfbench" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="vaadin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="liftweb" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="video" scheme="http://roller.apache.org/ns/tags/" />
        <category term="playframework" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rubyonrails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="onlinevideo" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last Wednesday, Trish and I traveled to Las Vegas for &lt;a href=&quot;http://javasymposium.techtarget.com/&quot;&gt;TheServerSide Java Symposium 2011 conference&lt;/a&gt;. We had a free room from TechTarget, but opted to upgrade to a suite with a view over the Bellagio Fountains. Trish won a trip to Vegas as a sales award earlier in the year and cleverly exchanged it for cash, so our upgrade was sort of free. 
&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[tssjs2011]&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[tssjs2011]&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;
My first talk was on Online Video and my experience at Time Warner Cable. With my former team&apos;s &lt;a href=&quot;http://justanotheripadblog.com/ipad-app-reviews/quick-look-twcable-tv-for-ipad-time-warner-cables-new-live-streaming-app-looks-good&quot;&gt;iPad app releasing the day before&lt;/a&gt;, it was a fun session. The attendance was kind of sparse, but I had some good competition so wasn&apos;t surprised.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;object id=&quot;__sse7299514&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=everythingonlinevideotssjs2011-110317161814-phpapp02&amp;rel=0&amp;stripped_title=everything-you-ever-wanted-to-know-about-online-video-tssjs-2011&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;__sse7299514&quot; src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=everythingonlinevideotssjs2011-110317161814-phpapp02&amp;rel=0&amp;stripped_title=everything-you-ever-wanted-to-know-about-online-video-tssjs-2011&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;After I finished speaking, we headed to happy hour and met up with some friends that happened to be in town. We had dinner at the &lt;a href=&quot;http://www.toddenglishpub.com/&quot;&gt;Todd English Pub&lt;/a&gt; and headed to the &lt;a href=&quot;http://www.pennandteller.com/&quot;&gt;Penn &amp;amp; Teller&lt;/a&gt; show at the Rio. We closed the night after Trish had a 45-minute roll at the craps table at &lt;a href=&quot;http://www.harrahs.com/osheas/&quot;&gt;O&apos;Sheas&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;We slept in on Thursday and I gave my Comparing JVM Web Frameworks talk that afternoon. I made sure to mention some other methods to choosing web frameworks: doing &lt;a href=&quot;http://code.google.com/p/perfbench/&quot;&gt;performance comparisons&lt;/a&gt; like Peter Thomas has done or &lt;a href=&quot;http://lift.la/my-take-on-matt-raibles-spreadsheet&quot;&gt;choosing Lift&lt;/a&gt; because one of its developers says it&apos;s the best. While Vaadin did sneak into the #5 spot, I made sure and mentioned that Wicket and Tapestry seem to belong there moreso (based on stats, mailing list traffic, etc.).
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;object id=&quot;__sse7299545&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=comparingjvmwebframeworkstssjs2011-110317162242-phpapp02&amp;rel=0&amp;stripped_title=comparing-jvm-web-frameworks-tssjs-2011&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;__sse7299545&quot; src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=comparingjvmwebframeworkstssjs2011-110317162242-phpapp02&amp;rel=0&amp;stripped_title=comparing-jvm-web-frameworks-tssjs-2011&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;&lt;a href=&quot;http://www.mcginityphoto.com/&quot;&gt;Trish&lt;/a&gt; took a bunch of pictures during my talk, which had a great turnout and lots of participation.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm6.static.flickr.com/5131/5550024506_e90c77ff59.jpg&quot; title=&quot;Getting Intro&apos;d&quot; rel=&quot;lightbox[tssjs2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5131/5550024506_e90c77ff59_t.jpg&quot; width=&quot;100&quot; height=&quot;66&quot; alt=&quot;Getting Intro&apos;d&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5266/5549441719_057d56a957.jpg&quot; title=&quot;My Intro&quot; rel=&quot;lightbox[tssjs2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5266/5549441719_057d56a957_t.jpg&quot; width=&quot;100&quot; height=&quot;66&quot; alt=&quot;My Intro&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5149/5550024786_52a3f6aaea.jpg&quot; title=&quot;My Dream Bus on Display&quot; rel=&quot;lightbox[tssjs2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5149/5550024786_52a3f6aaea_t.jpg&quot; width=&quot;100&quot; height=&quot;66&quot; alt=&quot;My Dream on Display&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://farm6.static.flickr.com/5051/5549442047_5defbb12d0.jpg&quot; title=&quot;The Problem&quot; rel=&quot;lightbox[tssjs2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5051/5549442047_5defbb12d0_t.jpg&quot; width=&quot;100&quot; height=&quot;66&quot; alt=&quot;The Problem&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5173/5550025074_d8af7137ba.jpg&quot; title=&quot;How do you choose?&quot; rel=&quot;lightbox[tssjs2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5173/5550025074_d8af7137ba_t.jpg&quot; width=&quot;100&quot; height=&quot;66&quot; alt=&quot;How do you choose?&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm6.static.flickr.com/5140/5550025200_a32831f218.jpg&quot; title=&quot;Choosing a Framework&quot; rel=&quot;lightbox[tssjs2011]&quot;&gt;&lt;img src=&quot;//farm6.static.flickr.com/5140/5550025200_a32831f218_t.jpg&quot; width=&quot;100&quot; height=&quot;66&quot; alt=&quot;Choosing a Framework&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; /&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;That evening, we celebrated St. Patty&apos;s Day with some college buddies of mine, ate great sushi at &lt;a href=&quot;http://www.mandalaybay.com/dining/casual-restaurants/mizuya.aspx&quot;&gt;Mizuya&lt;/a&gt; and experienced the joys of three card poker. Thanks to TechTarget for inviting me to TSSJS 2011; we had an awesome time. You can find all the pictures we took &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157626325120502/&quot;&gt;on Flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;border-top: 1px dotted silver; color: #666; padding-top: 5px&quot;&gt;
P.S. If you can&apos;t see the presentations in this post (a.k.a. you don&apos;t have Flash), you can &lt;a href=&quot;http://www.slideshare.net/mraible&quot; style=&quot;color: #666&quot;&gt;view them on on Slideshare&lt;/a&gt; or &lt;a href=&quot;http://raibledesigns.com/rd/page/publications&quot; style=&quot;color: #666&quot;&gt;download the PDFs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/upgrading_to_jsf_2</id>
        <title type="html">Upgrading to JSF 2</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/upgrading_to_jsf_2"/>
        <published>2011-03-07T13:24:53-07:00</published>
        <updated>2011-03-07T19:30:33-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="urlrewritefilter" scheme="http://roller.apache.org/ns/tags/" />
        <category term="myfaces" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="richfaces" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springsecurity" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomahawk" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="facelets" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last week, I spent a few hours upgrading &lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt; from JSF 1.2 to JSF 2.0. In reality, I upgraded from &lt;a href=&quot;http://myfaces.apache.org&quot;&gt;MyFaces&lt;/a&gt; 1.2.7 to 2.0.4, but all JSF implementations should be the same, right? All in all, it was a pretty easy upgrade with a few minor AppFuse-specific things. My goal in upgrading was to do the bare minimum to get things working and to leave integration of JSF 2 features for a later date.&lt;/p&gt;

&lt;p&gt;In addition to upgrading MyFaces, I had to upgrade Tomahawk by changing the dependency&apos;s artifactId to &lt;strong&gt;tomahawk20&lt;/strong&gt;. I was also able to remove the following listener from my web.xml:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;listener&gt;
    &amp;lt;listener-class&gt;org.apache.myfaces.webapp.StartupServletContextListener&amp;lt;/listener-class&gt;
&amp;lt;listener&gt;
&lt;/pre&gt;
&lt;p&gt;After that, I discovered that MyFaces uses a new URI (/javax.faces.resource/) for serving up some of its resource files. I kindly asked Spring Security to ignore these requests by adding the following to my security.xml file.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;intercept-url pattern=&quot;/javax.faces.resource/**&quot; filters=&quot;none&quot;/&gt;
&lt;/pre&gt;
&lt;p&gt;Since JSF 2 includes Facelets by default, I tried removing Facelets as a dependency. After doing this, I received the following error:
&lt;/p&gt;
&lt;pre&gt;
ERROR [308855416@qtp-120902214-7] ViewHandlerWrapper.fillChain(158) | Error instantiation parent Faces ViewHandler
java.lang.ClassNotFoundException: com.sun.facelets.FaceletViewHandler
        at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:50)
        at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:244)
        at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:230)
        at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:401)
        at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:363)
        at org.ajax4jsf.framework.ViewHandlerWrapper.fillChain(ViewHandlerWrapper.java:144)
        at org.ajax4jsf.framework.ViewHandlerWrapper.calculateRenderKitId(ViewHandlerWrapper.java:68)
        at org.apache.myfaces.lifecycle.DefaultRestoreViewSupport.isPostback(DefaultRestoreViewSupport.java:179)
        at org.apache.myfaces.lifecycle.RestoreViewExecutor.execute(RestoreViewExecutor.java:113)
        at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:171)
        at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189)
&lt;/pre&gt;
&lt;p&gt;Figuring this was caused by the following element in my web.xml ...
&lt;/p&gt;
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;context-param&amp;gt;
    &amp;lt;param-name&amp;gt;org.ajax4jsf.VIEW_HANDLERS&amp;lt;/param-name&amp;gt;
    &amp;lt;param-value&amp;gt;com.sun.facelets.FaceletViewHandler&amp;lt;/param-value&amp;gt;
&amp;lt;/context-param&amp;gt;
&lt;/pre&gt;
&lt;p&gt;... I removed it and tried again. This time I received a NoClassDefFoundError:&lt;/p&gt;
&lt;pre&gt;
java.lang.NoClassDefFoundError: com/sun/facelets/tag/TagHandler
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:392)
        at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:363)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:247)
        at org.apache.myfaces.shared_impl.util.ClassUtils.classForName(ClassUtils.java:184)
        at org.apache.myfaces.view.facelets.util.ReflectionUtil.forName(ReflectionUtil.java:67)
&lt;/pre&gt;
&lt;p&gt;Since everything seemed to work with Facelets in the classpath, I decided to save this headache for a later date. I entered two issues in AppFuse&apos;s JIRA, one for &lt;a href=&quot;http://issues.appfuse.org/browse/APF-1234&quot;&gt;removing Facelets&lt;/a&gt; and one for &lt;a href=&quot;http://issues.appfuse.org/browse/APF-1233&quot;&gt;replacing Ajax4JSF with RichFaces&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;The next issue I encountered was redirecting from AppFuse&apos;s password hint page. The navigation-rule for this page is as follows:&lt;/p&gt;
&lt;pre class=&quot;brush: xml; toolbar: false&quot;&gt;
&amp;lt;navigation-rule&amp;gt;
    &amp;lt;from-view-id&amp;gt;/passwordHint.xhtml&amp;lt;/from-view-id&amp;gt;
    &amp;lt;navigation-case&amp;gt;
        &amp;lt;from-outcome&amp;gt;success&amp;lt;/from-outcome&amp;gt;
        &amp;lt;to-view-id&amp;gt;/login&amp;lt;/to-view-id&amp;gt;
        &amp;lt;redirect/&amp;gt;
    &amp;lt;/navigation-case&amp;gt;
&amp;lt;/navigation-rule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;With JSF 2.0, the rule changes the URL to /login.xhtml when redirecting (where it was left as /login with 1.2) and it was caught by the security setting in my web.xml that prevents users from viewing raw templates.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;security-constraint&amp;gt;
    &amp;lt;web-resource-collection&amp;gt;
        &amp;lt;web-resource-name&amp;gt;Protect XHTML Templates&amp;lt;/web-resource-name&amp;gt;
        &amp;lt;url-pattern&amp;gt;*.xhtml&amp;lt;/url-pattern&amp;gt;
    &amp;lt;/web-resource-collection&amp;gt;
    &amp;lt;auth-constraint/&amp;gt;
&amp;lt;/security-constraint&amp;gt;
&lt;/pre&gt;
&lt;p&gt;To solve this issue, I had to make a couple of changes:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comment out the security-constraint in web.xml and move it to Spring Security&apos;s security.xml file.
&lt;pre class=&quot;brush: xml; toolbar: false&quot; style=&quot;margin: 5px 0 0 0&quot;&gt;
&amp;lt;intercept-url pattern=&quot;/**/*.xhtml&quot; access=&quot;ROLE_NOBODY&quot;/&gt;
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Add a rule to urlrewrite.xml that redirects back to login (since login.xhtml doesn&apos;t exist and I&apos;m using extensionless URLs).
&lt;pre class=&quot;brush: xml&quot; style=&quot;margin: 5px 0 0 0&quot;&gt;
&amp;lt;rule match-type=&quot;regex&quot;&amp;gt;
    &amp;lt;from&amp;gt;^/login.xhtml$&amp;lt;/from&amp;gt;
    &amp;lt;to type=&quot;redirect&quot;&amp;gt;%{context-path}/login&amp;lt;/to&amp;gt;
&amp;lt;/rule&amp;gt;
&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After getting the Password Hint feature passing in the browser, I tried running the integration tests (powered by &lt;a href=&quot;http://webtest.canoo.com&quot;&gt;Canoo WebTest&lt;/a&gt;). The Password Hint test kept failing with the following error:
&lt;/p&gt;
&lt;pre&gt;
[ERROR] /Users/mraible/dev/appfuse/web/jsf/src/test/resources/web-tests.xml:51: JavaScript error loading
page http://localhost:9876/appfuse-jsf-2.1.0-SNAPSHOT/passwordHint?username=admin: syntax error (http://
localhost:9876/appfuse-jsf-2.1.0-SNAPSHOT/javax.faces.resource/oamSubmit.js.jsf?ln=org.apache.myfaces#122)
&lt;/pre&gt;
&lt;p&gt;Figuring this was caused by my hack to &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/jsf/src/main/webapp/passwordHint.xhtml?r=2866&quot;&gt;submit the form when the page was loaded&lt;/a&gt;, I turned to &lt;a href=&quot;http://ocpsoft.com/prettyfaces/&quot;&gt;Pretty Faces&lt;/a&gt;, which allows you to call a method directly from a URL. After adding the Pretty Faces dependencies to my pom.xml, I created a src/main/webapp/WEB-INF/pretty-config.xml file with the following XML:&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;url-mapping&amp;gt;
    &amp;lt;pattern value=&quot;/editProfile&quot;/&amp;gt;
    &amp;lt;view-id value=&quot;/userForm.jsf&quot;/&amp;gt;
    &amp;lt;action&amp;gt;#{userForm.edit}&amp;lt;/action&amp;gt;
&amp;lt;/url-mapping&amp;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;This allowed me to remove both editProfile.xhtml and passwordHint.xhtml, both of which simply auto-submitted forms.&lt;/p&gt;
&lt;p&gt;At this point, I figured I&apos;d be good to go and ran my integration tests again. The first thing I discovered was that &quot;.jsf&quot; was being tacked onto my pretty URL, most likely by the UrlRewriteFilter. Adding the following to my PasswordHint.java class solved this.
&lt;/p&gt;
&lt;pre class=&quot;brush: java; toolbar: false&quot;&gt;
if (username.endsWith(&quot;.jsf&quot;)) {
    username = username.substring(0, username.indexOf(&quot;.jsf&quot;));
}
&lt;/pre&gt;
&lt;p&gt;The next thing was a cryptic error that took me a while to figure out.&lt;/p&gt;
&lt;pre&gt;
DEBUG [1152467051@qtp-144702232-0] PasswordHint.execute(38) | Processing Password Hint...
2011-03-05 05:48:52.471:WARN::/passwordHint/admin
com.ocpsoft.pretty.PrettyException: Exception occurred while processing &amp;lt;:#{passwordHint.execute}&gt; null
        at com.ocpsoft.pretty.faces.beans.ActionExecutor.executeActions(ActionExecutor.java:71)
        at com.ocpsoft.pretty.faces.event.PrettyPhaseListener.processEvent(PrettyPhaseListener.java:214)
        at com.ocpsoft.pretty.faces.event.PrettyPhaseListener.afterPhase(PrettyPhaseListener.java:108)
        at org.apache.myfaces.lifecycle.PhaseListenerManager.informPhaseListenersAfter(PhaseListenerManager.java:111)
        at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:185)
        at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189)
&lt;/pre&gt;
&lt;p&gt;Digging into the bowels of MyFaces, I discovered a class was looking for a viewId with an extension and no view-id was being set. Adding the following to the top of my execute() method solved this.
&lt;/p&gt;
&lt;pre class=&quot;brush: java; toolbar: false&quot;&gt;
getFacesContext().getViewRoot().setViewId(&quot;/passwordHint.xhtml&quot;);
&lt;/pre&gt;
&lt;p&gt;After making this change, all AppFuse&apos;s integration tests are passing and the upgrade seems complete. The only other issues I encountered were logging-related. The first is an error about Tomahawk that doesn&apos;t seem to affect anything.
&lt;/p&gt;
&lt;pre&gt;
Mar 5, 2011 6:44:01 AM com.sun.facelets.compiler.TagLibraryConfig loadImplicit
SEVERE: Error Loading Library: jar:file:/Users/mraible/.m2/repository/org/apache/myfaces/tomahawk/tomahawk20/1.1.10/tomahawk20-1.1.10.jar!/META-INF/tomahawk.taglib.xml
java.io.IOException: Error parsing [jar:file:/Users/mraible/.m2/repository/org/apache/myfaces/tomahawk/tomahawk20/1.1.10/tomahawk20-1.1.10.jar!/META-INF/tomahawk.taglib.xml]: 
        at com.sun.facelets.compiler.TagLibraryConfig.create(TagLibraryConfig.java:410)
        at com.sun.facelets.compiler.TagLibraryConfig.loadImplicit(TagLibraryConfig.java:431)
        at com.sun.facelets.compiler.Compiler.initialize(Compiler.java:87)
        at com.sun.facelets.compiler.Compiler.compile(Compiler.java:104)
&lt;/pre&gt;
&lt;p&gt;The second is excessive logging from MyFaces. As far as I can tell, this is because MyFaces switched to java.util.logging instead of commons logging. With all the frameworks that AppFuse leverages, I think it has all the logging frameworks in its classpath now. I was hoping to fix this by &lt;a href=&quot;http://old.nabble.com/Turn-down-logging-in-2.0.4--td31068698.html&quot;&gt;posting a message to the mailing list&lt;/a&gt;, but haven&apos;t received a reply yet.
&lt;/p&gt;
&lt;pre&gt;
[WARNING] [talledLocalContainer] Mar 5, 2011 6:50:25 AM org.apache.myfaces.config.annotation.TomcatAnnotationLifecycleProvider newInstance
[WARNING] [talledLocalContainer] INFO: Creating instance of org.appfuse.webapp.action.BasePage
[WARNING] [talledLocalContainer] Mar 5, 2011 6:50:25 AM org.apache.myfaces.config.annotation.TomcatAnnotationLifecycleProvider destroyInstance
[WARNING] [talledLocalContainer] INFO: Destroy instance of org.appfuse.webapp.action.BasePage
&lt;/pre&gt;
&lt;p&gt;After successfully upgrading AppFuse, I turned to AppFuse Light, where things were &lt;a href=&quot;http://source.appfuse.org/changelog/appfuse-light/?cs=243&quot;&gt;much easier&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
Now that AppFuse uses JSF 2, I hope to start leveraging some of its &lt;a href=&quot;http://www.ibm.com/developerworks/java/library/j-jsf2fu1/index.html&quot;&gt;new features&lt;/a&gt;. If you&apos;re yearning to get started with them today, I invite you to &lt;a href=&quot;http://appfuse.org/display/APF/Source+Repository&quot;&gt;grab the source&lt;/a&gt; and start integrating them yourself.</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/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/jess_and_lili_s_legendary</id>
        <title type="html">Jess and Lili&apos;s Legendary Wedding on The Lost Coast</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/jess_and_lili_s_legendary"/>
        <published>2010-07-29T23:54:00-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/General" label="General" />
        <category term="vacation" scheme="http://roller.apache.org/ns/tags/" />
        <category term="friends" scheme="http://roller.apache.org/ns/tags/" />
        <category term="lostcoast" scheme="http://roller.apache.org/ns/tags/" />
        <category term="travel" scheme="http://roller.apache.org/ns/tags/" />
        <category term="wedding" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">If you&apos;re a long-time reader of this blog, you&apos;ll know I&apos;ve been to &lt;a href=&quot;http://raibledesigns.com/rd/entry/jason_and_holly_s_wedding&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;http://raibledesigns.com/rd/entry/ryan_and_breanne_s_wedding&quot;&gt;great&lt;/a&gt; &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_sister_s_fabulous_wedding&quot;&gt;weddings&lt;/a&gt; in the last couple years. This past weekend, I had the pleasure of experiencing yet another fantastic celebration with two old and close friends, Clint and Jess. You might remember Clint from his &lt;a href=&quot;http://raibledesigns.com/rd/entry/costa_rica_was_awesome&quot;&gt;wedding in Costa Rica&lt;/a&gt; or when we &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_almost_slept_in_a&quot;&gt;almost slept in a snow cave&lt;/a&gt;. I&apos;m happy to report we didn&apos;t get in any trouble and everyone survived the weekend without a scratch.
&lt;/p&gt;
&lt;p&gt;My trip to Jess&apos;s wedding (on the &lt;a href=&quot;http://en.wikipedia.org/wiki/Lost_Coast&quot;&gt;Lost Coast&lt;/a&gt; of Northern California) started with a flight to Portland, Oregon. After arriving, I drove to Clint and Autumn&apos;s house in Eugene where we enjoyed some sweet Oregon micros and reminisced about Costa Rica. The next morning, we headed for the wedding; an 8-hour drive. Our road trip was awesome, especially when we started driving through the Redwood Groves on 101.&lt;/p&gt;
&lt;p&gt;We stayed in a &lt;a href=&quot;http://www.vrbo.com/30279&quot;&gt;sweet beach house&lt;/a&gt; for the weekend. While it was foggy most of the time, the sun did come out on Saturday. We quickly became surrounded by beautiful views and headed to the beach to relax with Jess.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4152/4837105756_a8c04f820b.jpg&quot; title=&quot;Whoo hoo! Sunshine!&quot; rel=&quot;lightbox[jessandliliwedding]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4152/4837105756_a8c04f820b_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Whoo hoo! Sunshine!&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4147/4837106698_506429dc8c.jpg&quot; title=&quot;Taking it all in&quot; rel=&quot;lightbox[jessandliliwedding]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4147/4837106698_506429dc8c_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Taking it all in&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4152/4836495851_95ef11cf5d.jpg&quot; title=&quot;Fog Lifting&quot; rel=&quot;lightbox[jessandliliwedding]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4152/4836495851_95ef11cf5d_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Fog Lifting&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4089/4836496609_5d5349fe0b.jpg&quot; title=&quot;Clint and Jess&quot; rel=&quot;lightbox[jessandliliwedding]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4089/4836496609_5d5349fe0b_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Clint and Jess&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The wedding was on Sunday, a mere block from where we were staying. The ceremony was one of the most heartfelt I&apos;ve ever heard, especially since the Wedding Official was a friend of the bride&apos;s since she was born.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4127/4837109660_1bf82702c6.jpg&quot; title=&quot;Jess and Kai&quot; rel=&quot;lightbox[jessandliliwedding]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4127/4837109660_1bf82702c6_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Jess and Kai&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4112/4836499239_9fc18dec2f.jpg&quot; title=&quot;Smiles all around&quot; rel=&quot;lightbox[jessandliliwedding]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4112/4836499239_9fc18dec2f_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Smiles all around&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4147/4837113014_b5f0a698f3.jpg&quot; title=&quot;Vows&quot; rel=&quot;lightbox[jessandliliwedding]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4147/4837113014_b5f0a698f3_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Vows&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4148/4837113676_f742506fbc.jpg&quot; title=&quot;Aawwwwww&quot; rel=&quot;lightbox[jessandliliwedding]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4148/4837113676_f742506fbc_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Aawwwwww&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The reception afterwards was a truly spectacular party that lasted well into the evening. Clint and I vowed to go to bed early, but we ended up having so much fun we closed the place down. Jess and Lili were an instrumental part in creating a spectacular night, especially with their &lt;a href=&quot;http://www.youtube.com/watch?v=zVNYDwQXggI&quot;&gt;wedding dance&lt;/a&gt; and infectious happiness.
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4128/4836504101_199c9821ba.jpg&quot; title=&quot;Lili and Jess&quot; rel=&quot;lightbox[jessandliliwedding]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4128/4836504101_199c9821ba_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Lili and Jess&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The next day, we woke up on time, embarked on the 10-hour road trip back to Oregon and enjoyed a quick detour through the &lt;a href=&quot;http://avenueofthegiants.net/&quot;&gt;Avenue of the Giants&lt;/a&gt;. I did end up missing my flight home, but it was worth it. Thanks to Lili and Jess (and their families) for showing us such a great time. It was truly spectacular.&lt;p&gt;
&lt;p&gt;
For more pictures, see albums on &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157624599819640/&quot;&gt;Flickr&lt;/a&gt;, &lt;a href=&quot;http://www.facebook.com/album.php?id=571296711&amp;amp;aid=194884&quot;&gt;Facebook&lt;/a&gt; or the slideshow below.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object width=&quot;400&quot; height=&quot;300&quot;&gt; &lt;param name=&quot;flashvars&quot; value=&quot;offsite=true&amp;lang=en-us&amp;page_show_url=%2Fphotos%2Fmraible%2Fsets%2F72157624599819640%2Fshow%2F&amp;page_show_back_url=%2Fphotos%2Fmraible%2Fsets%2F72157624599819640%2F&amp;set_id=72157624599819640&amp;jump_to=&quot;&gt;&lt;/param&gt; &lt;param name=&quot;movie&quot; value=&quot;http://www.flickr.com/apps/slideshow/show.swf?v=71649&quot;&gt;&lt;/param&gt; &lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;embed type=&quot;application/x-shockwave-flash&quot; src=&quot;//www.flickr.com/apps/slideshow/show.swf?v=71649&quot; allowFullScreen=&quot;true&quot; flashvars=&quot;offsite=true&amp;lang=en-us&amp;page_show_url=%2Fphotos%2Fmraible%2Fsets%2F72157624599819640%2Fshow%2F&amp;page_show_back_url=%2Fphotos%2Fmraible%2Fsets%2F72157624599819640%2F&amp;set_id=72157624599819640&amp;jump_to=&quot; width=&quot;400&quot; height=&quot;300&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/my_summer_vacation_in_montana1</id>
        <title type="html">My Summer Vacation in Montana</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/my_summer_vacation_in_montana1"/>
        <published>2010-07-13T08:12:02-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/General" label="General" />
        <category term="thecabin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="montana" scheme="http://roller.apache.org/ns/tags/" />
        <category term="abbie" scheme="http://roller.apache.org/ns/tags/" />
        <category term="mom" scheme="http://roller.apache.org/ns/tags/" />
        <category term="dad" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jack" scheme="http://roller.apache.org/ns/tags/" />
        <category term="summer" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">My favorite time of year is summertime. My favorite place to spend it is in Montana, often called &quot;&lt;a href=&quot;http://www.nytimes.com/2008/08/18/us/18trademark.html&quot;&gt;The Last Best Place&lt;/a&gt;&quot; by natives. This year was no different and I spent the last two weeks at my family&apos;s cabin celebrating the 4th of July. Shortly after returning from our &lt;a href=&quot;http://raibledesigns.com/rd/entry/another_fun_father_s_day&quot;&gt;Father&apos;s Day Camping Trip&lt;/a&gt;, my parents packed up Abbie and Jack and headed on a 3-day road trip through Wyoming and Montana, camping and sight-seeing along the way. I followed them a few days later and made the &lt;a href=&quot;http://twitter.com/mraible/status/17135468902&quot; title=&quot;Made it to The Cabin - woo hoo! 950 miles in 14.25 hours.&quot;&gt;950-mile drive in just over 14 hours&lt;/a&gt;. With scenes like the one below, the trip was very enjoyable, despite it being so long.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4096/4788758981_ea7346ab25.jpg&quot; rel=&quot;lightbox[montanavacation2010]&quot; title=&quot;Big Sky Country&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4096/4788758981_ea7346ab25_m.jpg&quot; width=&quot;240&quot; height=&quot;179&quot; alt=&quot;Big Sky Country&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt; 
&lt;p&gt;The first week I was there, I worked remotely. It&apos;s always fun to tell people &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_cabin&quot;&gt;The Cabin&lt;/a&gt; has no electricity or running water, but it does have DSL. To be fair, it &lt;em&gt;does&lt;/em&gt; have electricity, but it&apos;s not &quot;on the grid&quot; electricity - it&apos;s my Dad&apos;s concoction of generators, batteries and inverters. While I worked most of the week, I did manage to get a nice mountain bike ride in along the Foothills Trail to Holland Lake.&lt;/p&gt;
&lt;p&gt;My real vacation began on the 4th of July weekend and we did it up right with the Swan Valley Parade and lots of big fireworks I picked up in Wyoming. The kids dressed up as Woody and Jesse (from &lt;a href=&quot;http://disney.go.com/toystory/&quot;&gt;Toy Story&lt;/a&gt;) and walked in the parade all by themselves (first time w/o me). They were especially excited when their &lt;a href=&quot;http://farm5.static.flickr.com/4073/4788770319_62ac31485b.jpg&quot; rel=&quot;lightbox[montanavacation2010]&quot; title=&quot;Abbie and Jack are famous!&quot;&gt;pictures appeared in the local paper&lt;/a&gt; the following week.

&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4077/4788762471_187425438b.jpg&quot; title=&quot;Ready for the Parade&quot; rel=&quot;lightbox[montanavacation2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4077/4788762471_187425438b_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Ready for the Parade&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4114/4788762677_2a9bccec92.jpg&quot; title=&quot;Tossing Candy in the Parade&quot; rel=&quot;lightbox[montanavacation2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4114/4788762677_2a9bccec92_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Tossing Candy in the Parade&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4096/4789393410_52aa8aa457.jpg&quot; title=&quot;Woddy and Jesse in the 4th of July Parade&quot; rel=&quot;lightbox[montanavacation2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4096/4789393410_52aa8aa457_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Woddy and Jesse in the 4th of July Parade&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Last week was spent hiking to Glacier Lake in the rain, golfing in Seeley Lake and Columbia Falls and hanging out with my good friend &lt;a href=&quot;http://www.facebook.com/oconley1&quot;&gt;Owen Conley&lt;/a&gt; and his family.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4096/4789395818_8eefb50d1e.jpg&quot; title=&quot;Made it to Glacier Lake&quot; rel=&quot;lightbox[montanavacation2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4096/4789395818_8eefb50d1e_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Made it to Glacier Lake&quot; style=&quot;border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4098/4788767939_d273d4ddf5.jpg&quot; title=&quot;Chris Auchenbach&quot; rel=&quot;lightbox[montanavacation2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4098/4788767939_d273d4ddf5_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Chris Auchenbach&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4143/4789398916_a70dd2077e.jpg&quot; title=&quot;Meadow Lake Golf Course in Columbia Falls&quot; rel=&quot;lightbox[montanavacation2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4143/4789398916_a70dd2077e_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Meadow Lake Golf Course in Columbia Falls&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4074/4788771667_a5bab64f22.jpg&quot; title=&quot;Sunset from The Conley&apos;s&quot; rel=&quot;lightbox[montanavacation2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4074/4788771667_a5bab64f22_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Sunset from The Conley&apos;s&quot; style=&quot;margin-left: 10px; border: 1px solid black&quot;&gt;&lt;/a&gt;
&lt;/p&gt; 
&lt;p&gt;
The kids and I drove home last Sunday and it only took us 15 minutes longer than it did for me solo. I think they&apos;re quickly becoming road-tripping professionals. &lt;img src=&quot;https://raibledesigns.com/images/smileys/smile.gif&quot; class=&quot;smiley&quot; alt=&quot;:-)&quot; title=&quot;:-)&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;My favorite part of this year&apos;s trip to The Cabin was seeing it as a home again. My &lt;a href=&quot;http://raibledesigns.com/rd/entry/celebrating_my_mom_s_retirement&quot;&gt;Mom retired in April&lt;/a&gt; and my parents moved back to Montana shortly after. Seeing how happy they are there is truly magical. I especially enjoy the thought of visiting them and all the wonderful folks in the Swan Valley many, many times in the future. 
&lt;/p&gt;
&lt;p&gt;
To see all the pictures I took on this trip, check out the slideshow below. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object width=&quot;400&quot; height=&quot;300&quot;&gt; &lt;param name=&quot;flashvars&quot; value=&quot;offsite=true&amp;lang=en-us&amp;page_show_url=%2Fphotos%2Fmraible%2Fsets%2F72157624358584447%2Fshow%2F&amp;page_show_back_url=%2Fphotos%2Fmraible%2Fsets%2F72157624358584447%2F&amp;set_id=72157624358584447&amp;jump_to=&quot;&gt;&lt;/param&gt; &lt;param name=&quot;movie&quot; value=&quot;http://www.flickr.com/apps/slideshow/show.swf?v=71649&quot;&gt;&lt;/param&gt; &lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;embed type=&quot;application/x-shockwave-flash&quot; src=&quot;//www.flickr.com/apps/slideshow/show.swf?v=71649&quot; allowFullScreen=&quot;true&quot; flashvars=&quot;offsite=true&amp;lang=en-us&amp;page_show_url=%2Fphotos%2Fmraible%2Fsets%2F72157624358584447%2Fshow%2F&amp;page_show_back_url=%2Fphotos%2Fmraible%2Fsets%2F72157624358584447%2F&amp;set_id=72157624358584447&amp;jump_to=&quot; width=&quot;400&quot; height=&quot;300&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;&lt;p style=&quot;border-top: 1px dotted silver; padding-top: 5px; color: #666&quot;&gt;P.S. An interesting note about &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157624358584447/&quot; style=&quot;color: #666&quot;&gt;all the pictures I took&lt;/a&gt; - they&apos;re all from my iPhone 4. I forgot my camera&apos;s battery at home and it seemed like a good experiment.&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/abbie_and_jack_s_field</id>
        <title type="html">Abbie and Jack&apos;s Field Days</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/abbie_and_jack_s_field"/>
        <published>2010-05-26T06:49:39-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/General" label="General" />
        <category term="fieldday" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jack" scheme="http://roller.apache.org/ns/tags/" />
        <category term="abbie" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last week, I had the pleasure of attending my kids&apos; field days. For those who aren&apos;t familiar with field days, it&apos;s basically a &lt;a href=&quot;http://en.wikipedia.org/wiki/Sports_day&quot;&gt;sports day&lt;/a&gt; for elementary schools. The best part of this year&apos;s field days was seeing my kids have so much fun with their classmates. Of course, it didn&apos;t hurt that their teachers were also smitten with the thought of the school year coming to a close. 
&lt;/p&gt;
&lt;p&gt;
I took a few pictures and shot a bunch of video to remember how much fun they had. I know most readers won&apos;t enjoy these as much as I do, but I always like posting fond memories on this blog. Below are a couple videos I compiled and enhanced with appropriate music. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/iPVbMwkkmyY&amp;amp;hl=en_US&amp;amp;fs=1&amp;amp;rel=0&amp;amp;color1=0x3a3a3a&amp;amp;color2=0x999999&amp;amp;hd=1&amp;amp;border=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/iPVbMwkkmyY&amp;amp;hl=en_US&amp;amp;fs=1&amp;amp;rel=0&amp;amp;color1=0x3a3a3a&amp;amp;color2=0x999999&amp;amp;hd=1&amp;amp;border=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;I especially like Jack&apos;s friend&apos;s dance moves at the end of the video below. &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 style=&quot;text-align: center&quot;&gt;
&lt;object width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/NgPQjzNIeiE&amp;amp;hl=en_US&amp;amp;fs=1&amp;amp;rel=0&amp;amp;color1=0x3a3a3a&amp;amp;color2=0x999999&amp;amp;hd=1&amp;amp;border=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/NgPQjzNIeiE&amp;amp;hl=en_US&amp;amp;fs=1&amp;amp;rel=0&amp;amp;color1=0x3a3a3a&amp;amp;color2=0x999999&amp;amp;hd=1&amp;amp;border=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;&lt;p&gt;If you have trouble viewing either video here, &lt;a href=&quot;http://www.youtube.com/mraible&quot;&gt;check them out on my YouTube channel&lt;/a&gt;.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/tssjs_2010_presentations_and_summary</id>
        <title type="html">My TSSJS 2010 Presentations and Summary</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/tssjs_2010_presentations_and_summary"/>
        <published>2010-03-19T17:29:08-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="future" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="vegas" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tssjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwt" 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="flex" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This afternoon, I delivered my last talk at &lt;a href=&quot;http://javasymposium.techtarget.com/&quot;&gt;TSSJS 2010&lt;/a&gt; on &lt;a href=&quot;http://javasymposium.techtarget.com/html/frameworks.html#MRaibleFrameworks&quot;&gt;The Future of Web Frameworks&lt;/a&gt;. It&apos;s true that I made some &lt;a href=&quot;http://twitter.com/xgerman/status/10741037460&quot; title=&quot;JSF and Wicket are dead! Bold statement but GWT is a better alternative to begin with anyway #tssjs&quot;&gt;bold statements&lt;/a&gt;, but please remember that this is my personal opinion, based on my experience. For the most part, I&apos;ve been involved in super high-traffic websites for the last few years and this has influenced my opinion on web frameworks. Just because I don&apos;t recommend your favorite framework doesn&apos;t mean it won&apos;t work for you. In fact, many of the best web applications today were built without an open source (or commercial) web framework. In the end, it&apos;s not as much about the web framework you&apos;re using as it is about hiring smart people. Below is my slide deck from this talk.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;object 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;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 src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=thefutureofwebframeworks-100225012146-phpapp02&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;Yesterday, I did a &lt;a href=&quot;http://javasymposium.techtarget.com/html/theclientside.html#MRaibleSmack&quot;&gt;GWT vs. Flex Smackdown&lt;/a&gt; with &lt;a href=&quot;http://jamesward.com&quot;&gt;James Ward&lt;/a&gt;. While there wasn&apos;t as much trash talking as I&apos;d hoped, I enjoyed delivering it and disputing the greatness of Flex. Below is the presentation that James and I delivered.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object 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=flexvsgwtsmackdown-100311234937-phpapp01&amp;stripped_title=flex-vs-gwt-smackdown&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 src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=flexvsgwtsmackdown-100311234937-phpapp01&amp;stripped_title=flex-vs-gwt-smackdown&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 show itself was great this year. It had more attendees than I&apos;ve seen in a long time. There were a lot of really interesting sessions and and an often humorous &lt;a href=&quot;http://twitter.com/search?q=%23tssjs&quot;&gt;Twitter back-channel&lt;/a&gt;. I attended quite a few talks and jotted down my notes from several of them. Please see the links below if you&apos;re interested in the sessions I attended. You can view all of the presentations from TSSJS 2010 on &lt;a href=&quot;http://slideshare.net/javasymposium&quot;&gt;SlideShare&lt;/a&gt;.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/what_s_happening_in_the&quot;&gt;What&apos;s Happening in the Java World?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/software_quality_the_quest_for&quot;&gt;Software Quality: The Quest for the Holy Grail?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/the_cloud_computing_continuum_with&quot;&gt;The Cloud Computing Continuum with Bob McWhirter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/highly_interactive_software_with_java&quot;&gt;Highly Interactive Software with Java and Flex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/c_java_and_net_lessons&quot;&gt;C++, Java and .NET: Lessons Learned from the Internet Age&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_rich_web_service_apis&quot;&gt;Developing Rich Web Service APIs with Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://raibledesigns.com/rd/entry/what_s_new_in_spring&quot;&gt;What&apos;s New in Spring 3.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks to everyone who came to Vegas and to &lt;a href=&quot;http://theserverside.com&quot;&gt;TheServerSide&lt;/a&gt; for an excellent conference.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/fantastic_fun_in_jackson_hole</id>
        <title type="html">Fantastic Fun in Jackson Hole</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/fantastic_fun_in_jackson_hole"/>
        <published>2010-03-12T07:04:57-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/General" label="General" />
        <category term="skiing" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jacksonhole" scheme="http://roller.apache.org/ns/tags/" />
        <category term="wyoming" scheme="http://roller.apache.org/ns/tags/" />
        <category term="vacation" scheme="http://roller.apache.org/ns/tags/" />
        <category term="friends" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;a href=&quot;http://farm5.static.flickr.com/4053/4414626185_d4bccb0ff1.jpg&quot; rel=&quot;lightbox[jacksonhole2010]&quot; title=&quot;Jackson Hole Tram by mraible, on Flickr&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4053/4414626185_d4bccb0ff1_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Jackson Hole Tram&quot; class=&quot;picture&quot; /&gt;&lt;/a&gt;
For the last couple of years, I&apos;ve done a ski trip with college buddies to an out-of-state destination. Two years ago, we went to &lt;a href=&quot;http://raibledesigns.com/rd/entry/awesome_weekend_in_tahoe&quot;&gt;Tahoe&lt;/a&gt; and had a great time. Last year, we did it again and I (amazingly) &lt;a href=&quot;http://raibledesigns.com/rd/entry/traveling_to_tahoe_without_a&quot;&gt;flew and rented a car without a driver&apos;s license&lt;/a&gt;. This year, we decided to switch things up a bit and head for &lt;a href=&quot;http://www.jacksonhole.com/&quot;&gt;Jackson Hole&lt;/a&gt;. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4020/4414598647_a3fc722aed.jpg&quot; rel=&quot;lightbox[jacksonhole2010]&quot; title=&quot;Run under the Gondola&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4020/4414598647_a3fc722aed_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Run under the Gondola&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm3.static.flickr.com/2804/4414605103_60aca6093c.jpg&quot; rel=&quot;lightbox[jacksonhole2010]&quot; title=&quot;Murphy, Morse and Matt Good&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2804/4414605103_60aca6093c_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Murphy, Morse and Matt Good&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/4034/4414720761_ba90505bc0.jpg&quot; rel=&quot;lightbox[jacksonhole2010]&quot; title=&quot;Murphy, Ben and Chris by mraible, on Flickr&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4034/4414720761_ba90505bc0_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Murphy, Ben and Chris&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4015/4424378450_c6cd0f88b7.jpg&quot; rel=&quot;lightbox[jacksonhole2010]&quot; title=&quot;Paragliding&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4015/4424378450_c6cd0f88b7_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Paragliding&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
In previous years, only a couple of us went, but this year was organized by my good friend from Boston, Chris Morse. He managed to take it up a notch and invited a great group of guys, 9 of us in all. I knew about half the group, and met everyone else upon arrival. 
&lt;/p&gt;
&lt;p&gt;
The only unfortunate part about the trip was that no new snow fell. However, the Spring Skiing was warm and beautiful, somewhat making up for the lack of snow. The thing I enjoyed the most about this trip was how well the group &lt;em&gt;jelled&lt;/em&gt;. Kudos to Chris for assembling such an awesome group and putting such a spectacular trip together. Can&apos;t wait for next year.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm5.static.flickr.com/4037/4415396480_18103421f4.jpg&quot; title=&quot;Top of Tram&quot; rel=&quot;lightbox[jacksonhole2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4037/4415396480_18103421f4_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Top of Tram&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4015/4414627855_f2b8c7c794.jpg&quot; title=&quot;Top o&apos; Jackson Hole&quot; rel=&quot;lightbox[jacksonhole2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4015/4414627855_f2b8c7c794_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Top o&apos; Jackson Hole&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm3.static.flickr.com/2738/4415487338_b59fd0600b.jpg&quot; title=&quot;Murphy and I&quot; rel=&quot;lightbox[jacksonhole2010]&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2738/4415487338_b59fd0600b_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Murphy and I&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm3.static.flickr.com/2788/4414630091_6ba638752c.jpg&quot; title=&quot;Paintbrush&quot; rel=&quot;lightbox[jacksonhole2010]&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2788/4414630091_6ba638752c_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Paintbrush&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://farm3.static.flickr.com/2705/4415399408_fe1fa51546.jpg&quot; title=&quot;Apres Ski&quot; rel=&quot;lightbox[jacksonhole2010]&quot;&gt;&lt;img src=&quot;//farm3.static.flickr.com/2705/4415399408_fe1fa51546_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Apres Ski&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4035/4414635575_1ffaa235c5.jpg&quot; title=&quot;Corbet&apos;s Couloir&quot; rel=&quot;lightbox[jacksonhole2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4035/4414635575_1ffaa235c5_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Corbet&apos;s  Couloir&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4060/4414635217_7643509779.jpg&quot; title=&quot;Morse and I&quot; rel=&quot;lightbox[jacksonhole2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4060/4414635217_7643509779_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Morse and I&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm5.static.flickr.com/4003/4424375736_2866dc227e.jpg&quot; title=&quot;Ben, Jed, Tom and Christian&quot; rel=&quot;lightbox[jacksonhole2010]&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4003/4424375736_2866dc227e_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Ben, Jed, Tom and Christian&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;For further action of what the conditions where like, checkout the YouTube video I made. If only I&apos;d recorded it for another 5 seconds to catch the digger that Corey takes at the end. &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;div style=&quot;text-align: center; margin-bottom: 10px&quot;&gt;
&lt;object width=&quot;480&quot; height=&quot;295&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/Q4BluD740N0&amp;hl=en_US&amp;fs=1&amp;rel=0&amp;color1=0x3a3a3a&amp;color2=0x999999&amp;hd=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/Q4BluD740N0&amp;hl=en_US&amp;fs=1&amp;rel=0&amp;color1=0x3a3a3a&amp;color2=0x999999&amp;hd=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;480&quot; height=&quot;295&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/div&gt;
&lt;p&gt;To see all the pictures we took on this adventure, checkout my &lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157623574871328/&quot;&gt;Jackson Hole Set on Flickr&lt;/a&gt;.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/my_future_of_web_frameworks</id>
        <title type="html">My Future of Web Frameworks Presentation</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/my_future_of_web_frameworks"/>
        <published>2010-02-26T08:55:39-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="vegas" scheme="http://roller.apache.org/ns/tags/" />
        <category term="theserverside" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jvm" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tssjs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="future" scheme="http://roller.apache.org/ns/tags/" />
        <category term="presentation" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Earlier this week, I &lt;a href=&quot;http://twitter.com/mraible/status/9467279089&quot;&gt;tweeted about a history of web frameworks timeline&lt;/a&gt; I created for my upcoming &lt;a href=&quot;http://javasymposium.techtarget.com/html/frameworks.html#MRaibleFrameworks&quot;&gt;Future of Web Frameworks talk&lt;/a&gt; at &lt;a href=&quot;http://javasymposium.techtarget.com/&quot;&gt;TSSJS Vegas 2010&lt;/a&gt;. I immediately received a lot of feedback and requests for adding new frameworks and releases. The image below is the result of that Twitter conversation. Thanks to everyone who contributed.
&lt;/p&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&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4067/4378559350_13f0755403.jpg&quot; width=&quot;500&quot; height=&quot;239&quot; alt=&quot;History of Web Frameworks&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Back in &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_future_of_web_frameworks&quot;&gt;November&lt;/a&gt;, I wrote about my proposals for TSSJS. I&apos;ve been thinking a lot about web frameworks lately and I can&apos;t help but think we live in a very exciting time. As a Java developer, I&apos;ve been exposed to one of the most vibrant language ecosystems on the planet. As &lt;a href=&quot;http://www.javaworld.com/podcasts/jtech/2009/020909jtech-bray.html&quot;&gt;Tim Bray talks about&lt;/a&gt;, the Java Platform has 3 legs: the language, the virtual machine and a huge, immense library of APIs (both in the JDK and in open source libraries). The diagram below is something I created based on Tim&apos;s podcast.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://www.flickr.com/photos/mraible/4388528613/&quot; title=&quot;Java has 3 Legs&quot;&gt;&lt;img src=&quot;//farm5.static.flickr.com/4003/4388528613_18df5e164f_o.png&quot; width=&quot;418&quot; height=&quot;290&quot; alt=&quot;Java has 3 Legs&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Tim says, &quot;One of those legs is replaceable and that&apos;s the language.&quot; And he&apos;s right, there&apos;s many &lt;a href=&quot;http://blog.thinkrelevance.com/2008/9/24/java-next-overview&quot;&gt;Java.next&lt;/a&gt; languages that run efficiently on the JVM. This is one of the most exciting parts of being a Java web developer today. There&apos;s many proven web frameworks and languages that you can pick to build your next web application. 
&lt;/p&gt;
&lt;p&gt;
The best part is many of the best web frameworks run on the JVM. Not only that, but the best code editors are the IDEs that you&apos;re familiar with and have grown to love. Furthermore, much of the literature for Java.next languages is written &lt;em&gt;for&lt;/em&gt; Java developers. As someone who knows Java, you have wealth of web frameworks and languages just waiting for you to learn them. &lt;!--I think the biggest mistake you can make as developer is to stop learning. Just because you know one language/framework well doesn&apos;t mean you shouldn&apos;t learn about it&apos;s competition. Java vs. Scala, Maven vs. Ant, Rails vs. Grails, GWT vs. Flex, Tomcat vs. Jetty, Spring vs. Guice, Hibernate vs. iBATIS - your knowledge about more than one language/framework can be very rewarding.--&gt;
&lt;/p&gt;
&lt;p&gt;
To create my presentation on the future of web frameworks, I followed the outline I &lt;a href=&quot;http://raibledesigns.com/rd/entry/the_future_of_web_frameworks&quot;&gt;posted previously&lt;/a&gt;. I plan on explaining the evolution and history of web frameworks and how we got to where we are today. From there, I&apos;ll be speculating on what web applications we&apos;ll be developing in the future. Finally, I&apos;ll touch on the necessary features of web frameworks that will allow us to develop these applications. 
&lt;/p&gt;
&lt;p&gt;
Of course, I haven&apos;t actually presented this talk yet, so it&apos;s likely to change in the coming weeks before the conference. The good news is this gives you the opportunity to provide constructive criticism on this presentation and help make it better. I realize that a presentation rarely represents the conversation that takes place during a conference. However, I believe it can portray the jist of my thinking and lead to a meaningful conversation in the comments of this post.
Below is the presentation I created - thanks in advance for any feedback. 
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;&lt;object 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;rel=0&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 src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=thefutureofwebframeworks-100225012146-phpapp02&amp;rel=0&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;
For those who will be joining me at TSSJS ... it&apos;s gonna be a great show. St. Patrick&apos;s Day in Vegas, what more could you ask for? &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;&lt;strong&gt;Update:&lt;/strong&gt; This article has been &lt;a href=&quot;http://java.dzone.com/articles/my-future-web-frameworks&quot;&gt;re-posted on Javalobby&lt;/a&gt; and contains additional community feedback in the comments.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/upside_down_man_saves_the</id>
        <title type="html">Upside Down Man Saves the Day</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/upside_down_man_saves_the"/>
        <published>2010-01-31T16:54:31-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/General" label="General" />
        <category term="abbie" scheme="http://roller.apache.org/ns/tags/" />
        <category term="youtube" scheme="http://roller.apache.org/ns/tags/" />
        <category term="upsidedownman" scheme="http://roller.apache.org/ns/tags/" />
        <category term="video" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jack" scheme="http://roller.apache.org/ns/tags/" />
        <category term="superhero" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Yesterday, Abbie and Jack &lt;a href=&quot;http://raibledesigns.com/rd/entry/how_to_be_a_super&quot;&gt;showed you how to be a superhero&lt;/a&gt;. Today they&apos;re back with an action-packed video titled Upside Down Man Saves the Day. Watch it if you&apos;d like to see how to take out a tiger, wrestle an alligator and diffuse a bomb. This short film was written, directed and filmed by Abbie, the only thing I did was add the music. &lt;em&gt;Enjoy!&lt;/em&gt; &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 style=&quot;text-align: center&quot;&gt;
&lt;object width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/g1ZjqHX2q7E&amp;hl=en_US&amp;fs=1&amp;color1=0x3a3a3a&amp;color2=0x999999&amp;hd=1&amp;border=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/g1ZjqHX2q7E&amp;hl=en_US&amp;fs=1&amp;color1=0x3a3a3a&amp;color2=0x999999&amp;hd=1&amp;border=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;If you have trouble viewing it here, &lt;a href=&quot;http://www.youtube.com/watch?v=g1ZjqHX2q7E&quot;&gt;check it out on YouTube&lt;/a&gt;.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/how_to_be_a_super</id>
        <title type="html">How to be a Super Hero by Abbie and Jack</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/how_to_be_a_super"/>
        <published>2010-01-30T16:42:29-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/General" label="General" />
        <category term="youtube" scheme="http://roller.apache.org/ns/tags/" />
        <category term="abbie" scheme="http://roller.apache.org/ns/tags/" />
        <category term="video" scheme="http://roller.apache.org/ns/tags/" />
        <category term="superhero" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jack" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">For some reason, my kids are very interested in Super Heros lately. In fact, they know so much about them that they&apos;ve decided to start teaching others how to become one. Checkout the videos we shot earlier today with their step-by-step instructions.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/sg0ggFFUtQk&amp;hl=en_US&amp;fs=1&amp;color1=0x3a3a3a&amp;color2=0x999999&amp;hd=1&amp;border=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/sg0ggFFUtQk&amp;hl=en_US&amp;fs=1&amp;color1=0x3a3a3a&amp;color2=0x999999&amp;hd=1&amp;border=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/PK4Jrtk7e40&amp;hl=en_US&amp;fs=1&amp;color1=0x3a3a3a&amp;color2=0x999999&amp;hd=1&amp;border=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/PK4Jrtk7e40&amp;hl=en_US&amp;fs=1&amp;color1=0x3a3a3a&amp;color2=0x999999&amp;hd=1&amp;border=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;500&quot; height=&quot;315&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;I hope Abbie and Jack&apos;s tips help you become a super hero! &lt;img src=&quot;https://raibledesigns.com/images/smileys/smile.gif&quot; class=&quot;smiley&quot; alt=&quot;:-)&quot; title=&quot;:-)&quot; /&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/comparing_kick_ass_web_frameworks</id>
        <title type="html">Comparing Kick-Ass Web Frameworks at The Rich Web Experience</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/comparing_kick_ass_web_frameworks"/>
        <published>2009-12-04T08:16:48-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="jobs" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwt" 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="trends" scheme="http://roller.apache.org/ns/tags/" />
        <category term="flex" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Yesterday, I delivered my &lt;a href=&quot;http://www.therichwebexperience.com/conference/orlando/2009/12/session?id=15951&quot;&gt;Comparing Kick-Ass Web Frameworks&lt;/a&gt; talk at the Rich Web Experience in Orlando, Florida. Below are the slides I used:&lt;/p&gt;
&lt;div style=&quot;text-align:center; margin-bottom: 10px&quot; id=&quot;__ss_2644393&quot;&gt;
&lt;object style=&quot;margin:0px&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 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;/div&gt;
&lt;p&gt;Although it&apos;s difficult to convey a presentation in a slide deck, I can offer you my conclusion: &lt;a href=&quot;http://java.dzone.com/news/there-no-best-web-framework&quot;&gt;there is no &quot;best&quot; web framework&lt;/a&gt;. I believe web frameworks are like &lt;a href=&quot;http://www.ted.com/talks/malcolm_gladwell_on_spaghetti_sauce.html&quot;&gt;spaghetti sauce&lt;/a&gt; in that everyone has different tastes and having so many choices is necessary to satisfy everyone. You can read more about the &lt;em&gt;plural nature of perfection&lt;/em&gt; in Malcolm Gladwell&apos;s &lt;a href=&quot;http://www.gladwell.com/2004/2004_09_06_a_ketchup.html&quot;&gt;The Ketchup Conundrum&lt;/a&gt; (a written version of &lt;a href=&quot;http://www.ted.com/talks/malcolm_gladwell_on_spaghetti_sauce.html&quot;&gt;What we can learn from spaghetti sauce&lt;/a&gt;). Even though there is no &quot;best&quot; web framework, I believe GWT, Flex, Rails and Grails are frameworks that every web developer should try. They really do make it fun to develop web applications.
&lt;/p&gt;
&lt;p&gt;You can find the slides for my other RWE talk at &lt;a href=&quot;http://raibledesigns.com/rd/entry/building_sofea_applications_with_gwt&quot;&gt;Building SOFEA Applications with GWT and Grails&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
Kudos to &lt;a href=&quot;http://www.nofluffjuststuff.com&quot;&gt;Jay Zimmerman&lt;/a&gt; for putting on a great show in Orlando this year. I had a great time talking with folks and learning in the sessions I attended. I particularly enjoyed bringing my parents and kids and staying at such a nice resort. Disney World (Magic Kingdom) and Universal Studios was very enjoyable due to the short lines. Also, the weather was perfect - especially considering the freezing cold in Denver this week. &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/adding_expires_headers_with_oscache</id>
        <title type="html">Adding Expires Headers with OSCache&apos;s CacheFilter</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/adding_expires_headers_with_oscache"/>
        <published>2009-11-23T11:17:05-07:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Roller" label="Roller" />
        <category term="oscache" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appfuse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="roller" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ehcache" scheme="http://roller.apache.org/ns/tags/" />
        <category term="highperformance" scheme="http://roller.apache.org/ns/tags/" />
        <category term="expiresheaders" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">A couple of weeks ago, I wrote about how I improved this site&apos;s YSlow grade by &lt;a href=&quot;http://raibledesigns.com/rd/entry/javascript_and_css_concatenation&quot;&gt;concatenating JavaScript and CSS with wro4j&lt;/a&gt;. Even though I loved the improvements, there was still work to do:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
I&apos;m now sitting at a YSlow (V2) score of 75; 90 if I use the &quot;Small Site or Blog&quot; ruleset. I believe I can improve this by adding expires headers to my images, js and css.
&lt;/p&gt;
&lt;p&gt;Last Monday, &lt;a href=&quot;http://groups.google.com/group/wro4j/browse_thread/thread/364dc86a194d712a&quot;&gt;wro4j 1.1.0 was released&lt;/a&gt; and I thought it would solve my last remaining issue. Unfortunately, it only adds expires headers (and ETags) to images referenced in included CSS. Of course, this makes sense, but I thought they&apos;d add a filter to explicitly add expires headers.&lt;/p&gt;
&lt;p&gt;Since I still wanted this feature, I did some searching around and found what I was looking for: &lt;a href=&quot;http://www.opensymphony.com/oscache/wiki/CacheFilter.html&quot;&gt;OSCache&apos;s CacheFilter&lt;/a&gt;. It was surprisingly easy to setup, I &lt;a href=&quot;https://oscache.dev.java.net/files/documents/629/61424/oscache-2.4.1.jar&quot;&gt;downloaded OSCache 2.4.1&lt;/a&gt;, added it to my WEB-INF/lib directory, and added the following to my web.xml.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;filter&amp;gt;
    &amp;lt;filter-name&amp;gt;CacheFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;filter-class&amp;gt;com.opensymphony.oscache.web.filter.CacheFilter&amp;lt;/filter-class&amp;gt;
    &amp;lt;init-param&amp;gt;
        &amp;lt;param-name&amp;gt;expires&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;time&amp;lt;/param-value&amp;gt;
    &amp;lt;/init-param&amp;gt;
    &amp;lt;init-param&amp;gt;
        &amp;lt;param-name&amp;gt;time&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;2592000&amp;lt;/param-value&amp;gt; &amp;lt;!-- one month --&amp;gt;
    &amp;lt;/init-param&amp;gt;
    &amp;lt;init-param&amp;gt;
        &amp;lt;param-name&amp;gt;scope&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;session&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;CacheFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;*.gif&amp;lt;/url-pattern&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;CacheFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;*.jpg&amp;lt;/url-pattern&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;CacheFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;*.png&amp;lt;/url-pattern&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&lt;/pre&gt;
&lt;p&gt;After restarting Tomcat and clearing out my Firefox cache, I was in business. 
&lt;/p&gt;
&lt;p&gt;
I did experience one issue along the way when I tried to remove the oscache.jar from my WEB-INF/lib directory. I&apos;m using the &lt;a href=&quot;http://wiki.java.net/bin/view/Javanet/JSPWikiPlugin&quot;&gt;JSPWiki Plugin&lt;/a&gt; and it seems to rely on a class in oscache.jar. I&apos;m not sure which version oscache.jar is, but the packages got moved around somewhere along the way. The good news is it seems OK to have both oscache.jar and oscache-2.4.1.jar in Roller&apos;s classpath.
&lt;/p&gt;
&lt;p&gt;After discovering the duplicate JARs issue, I got to thinkin&apos; that EhCache would probably have a solution. Sure enough, it has a &lt;a href=&quot;http://ehcache.org/documentation/web_caching.html&quot;&gt;SimpleCachingHeadersPageCachingFilter&lt;/a&gt;. Since I already had a working solution, I didn&apos;t bother trying EhCache (especially since my Roller install uses EhCache 1.1 and the filter is only available in a later version). However, when I implement expires headers in &lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt;, I&apos;ll definitely try EhCache&apos;s solution.&lt;/p&gt;
&lt;p&gt;As for my YSlow score, it didn&apos;t improve as much as I&apos;d hoped (low 80s instead of mid 80s). Some of this is due to my &lt;a href=&quot;http://raibledesigns.com/rd/entry/building_sofea_applications_with_gwt&quot;&gt;embedded presentation from Slideshare&lt;/a&gt;. There&apos;s also some external images I&apos;m using in my &lt;a href=&quot;http://raibledesigns.com/rd/entry/lightbox_js&quot;&gt;Lightbox JS&lt;/a&gt; implementation. So if I can find a better Lightbox implementation (supports rel=&quot;lightbox&quot; syntax), there&apos;s a good chance I&apos;ll switch. In the meantime, I&apos;m lovin&apos; how much faster this site loads.
&lt;/p&gt;
&lt;p&gt;In case you&apos;re wondering, I do plan on adding css/js concatenation and expires headers to both AppFuse 2.1 and &lt;a href=&quot;http://roller.apache.org&quot;&gt;Roller&lt;/a&gt; 5.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; FWIW, I did try to configure expires headers in Apache, but the AJP 1.3 Connector doesn&apos;t seem to allow this to work. To quote Keith from &lt;a href=&quot;http://kgbinternet.com/&quot;&gt;KGB Internet&lt;/a&gt;:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
I added an expires directive and it didn&apos;t touch the header for anything served from Tomcat, but does for content served directly by Apache.  This might have to be set up in Tomcat.
&lt;/p&gt;&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/building_sofea_applications_with_gwt</id>
        <title type="html">Building SOFEA Applications with GWT and Grails</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/building_sofea_applications_with_gwt"/>
        <published>2009-11-12T09:30:09-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="evite" scheme="http://roller.apache.org/ns/tags/" />
        <category term="sofea" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last night, I spoke at the &lt;a href=&quot;http://denverjug.org&quot;&gt;Denver Java User Group&lt;/a&gt; meeting. The consulting panel with &lt;a href=&quot;http://www.ambientideas.com/blog/&quot;&gt;Matthew&lt;/a&gt;, &lt;a href=&quot;http://www.augusttechgroup.com/tim/blog/&quot;&gt;Tim&lt;/a&gt; and &lt;a href=&quot;http://www.jroller.com/JamesGoodwill/&quot;&gt;Jim&lt;/a&gt; 
a lot of fun and I enjoyed delivering my &lt;a href=&quot;http://raibledesigns.com/rd/entry/consulting_sofea_grails_and_gwt&quot;&gt;Building SOFEA Applications with GWT and Grails&lt;/a&gt; presentation for the first time. The talk was mostly a story about how we &lt;a href=&quot;http://raibledesigns.com/rd/entry/enhancing_evite_com_with_gwt&quot;&gt;enhanced Evite.com with GWT and Grails&lt;/a&gt; and what we did to make both frameworks scale. I don&apos;t believe the presentation reflects the story format that well, but it&apos;s not about the presentation, it&apos;s about the delivery of it. &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 style=&quot;text-align:center&quot; id=&quot;__ss_2484656&quot;&gt;&lt;object style=&quot;margin:0px&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=sofeawithgwtandgrails-091112101640-phpapp01&amp;rel=0&amp;stripped_title=building-sofea-applications-with-gwt-and-grails&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 src=&quot;//static.slidesharecdn.com/swf/ssplayer2.swf?doc=sofeawithgwtandgrails-091112101640-phpapp01&amp;rel=0&amp;stripped_title=building-sofea-applications-with-gwt-and-grails&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;If you&apos;d like to hear the story about this successful SOFEA implementation at a high-volume site, I&apos;d recommend attending the &lt;a href=&quot;http://www.therichwebexperience.com&quot;&gt;Rich Web Experience&lt;/a&gt; next month. If you attended last night&apos;s meeting and have any feedback on how this talk can be improved, I&apos;d love to hear it.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/developing_and_testing_gwt_client</id>
        <title type="html">Developing and Testing GWT Client Services</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/developing_and_testing_gwt_client"/>
        <published>2009-10-21T06:55:17-06:00</published>
        <updated>2010-02-22T22:47:19-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="requestbuilder" scheme="http://roller.apache.org/ns/tags/" />
        <category term="junit" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwtinpractice" scheme="http://roller.apache.org/ns/tags/" />
        <category term="testing" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwttestcase" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rest" scheme="http://roller.apache.org/ns/tags/" />
        <category term="restygwt" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Earlier this week, Hiram Chirino released &lt;a href=&quot;http://github.com/chirino/resty-gwt&quot;&gt;RestyGWT&lt;/a&gt;, a GWT generator for REST services and JSON encoded data transfer objects. You can read more about it in Hiram&apos;s post &lt;a href=&quot;http://hiramchirino.com/blog/2009/10/restygwt-a-better-gwt-rpc/&quot;&gt;RestyGWT, a Better GWT RPC??&lt;/a&gt;. First of all, I&apos;m impressed with RestyGWT because provides something I&apos;ve always wanted with GWT: the ability to call RESTful services and get a populated POJO in your callback, much like &lt;a href=&quot;http://google-web-toolkit.googlecode.com/svn/javadoc/1.6/com/google/gwt/user/client/rpc/AsyncCallback.html&quot;&gt;AsyncCallback&lt;/a&gt; provides for RPC services. &lt;/p&gt;
&lt;p&gt;RestyGWT also allows you to easily create services using only interfaces and JAX-RS annotations. For example:
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
import javax.ws.rs.POST;
...
public interface PizzaService extends RestService {
    @POST
    public void order(PizzaOrder request, MethodCallback&amp;lt;OrderConfirmation&amp;gt; callback);
}
&lt;/pre&gt;
&lt;p&gt;
After taking a brief look at RestyGWT, I thought it&apos;d be interesting to share how I develop and test GWT client services.
&lt;/p&gt;
&lt;p id=&quot;developing&quot;&gt;&lt;strong&gt;Developing GWT Client Services&lt;/strong&gt;&lt;br/&gt;
Writing services in a GWT application can be helpful when you&apos;re using MVP, especially since you can &lt;a href=&quot;http://googletesting.blogspot.com/2009/08/tott-testing-gwt-without-gwttest.html&quot;&gt;EasyMock them in a test&lt;/a&gt;. On my GWT projects, I&apos;ve often used &lt;a href=&quot;http://raibledesigns.com/rd/entry/json_parsing_with_javascript_overlay&quot;&gt;overlay types&lt;/a&gt; because they allow me to write less code and they make parsing JSON super simple. 
I&apos;ve &lt;a href=&quot;http://raibledesigns.com/rd/entry/building_gwt_applications_with_mvp&quot;&gt;had issues&lt;/a&gt; testing my presenters when using overlay types. The good news is I think I&apos;ve figured out a reasonable solution, but it does require using GWTTestCase. If RestyGWT supported overlay types, there&apos;s a good chance I&apos;d use it, especially since its  &lt;a href=&quot;http://github.com/chirino/resty-gwt/tree/master/src/it/resty-gwt-example/src/test/java/com/hiramchirino/restygwt/examples/client/&quot;&gt;integration tests&lt;/a&gt; seem to require GWTTestCase too.
&lt;/p&gt;
&lt;p&gt;Rather than using callbacks in my presenters, I try to only use them in my service implementations. That way, my presenters don&apos;t have to worry about overlay types and can be tested in a JUnit-only fashion. The callbacks in my services handle JSON parsing/object population and fire events with the populated objects. 
&lt;/p&gt;
&lt;p&gt;
GWT&apos;s &lt;a href=&quot;http://google-web-toolkit.googlecode.com/svn/javadoc/1.6/com/google/gwt/http/client/RequestBuilder.html&quot;&gt;RequestBuilder&lt;/a&gt; is one option for communicating with RESTful services. The &lt;a href=&quot;http://code.google.com/p/google-web-toolkit-doc-1-5/wiki/DevGuideHttpRequests&quot;&gt;Development Guide for HTTP Requests&lt;/a&gt; explains how to use this class. To simplify REST requests and allow multiple callbacks, I&apos;m using a &lt;strong&gt;RestRequest&lt;/strong&gt; class, and a number of other utility classes that make up a small GWT REST framework (created by a former colleague). &lt;!--good friend of mine, Dan Mesh. Unfortunately, Dan doesn&apos;t have a blog to link to; you&apos;ll have to trust me that he&apos;s a smart guy and a lot of fun to work with.--&gt; RestRequest wraps RequestBuilder and provides a &lt;a href=&quot;http://martinfowler.com/bliki/FluentInterface.html&quot;&gt;Fluent API&lt;/a&gt; for executing HTTP requests. Another class, &lt;strong&gt;Deferred&lt;/strong&gt;, is a GWT implementation of &lt;a href=&quot;http://twistedmatrix.com/projects/core/documentation/howto/defer.html&quot;&gt;Twisted&apos;s Deferred&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;As part of my service implementation, I inject an EventBus (with &lt;a href=&quot;http://code.google.com/p/google-gin/&quot;&gt;GIN&lt;/a&gt;) into the constructor and then proceed to implement callbacks that fire Events to indicate loading, saving and deleting has succeeded. Here&apos;s an example service:
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class ConversationServiceImpl implements ConversationService {
    private EventBus eventBus;

    @Inject
    public ConversationServiceImpl(EventBus eventBus) {
        this.eventBus = eventBus;
    }

    public void getConversation(String name) {
        Deferred&amp;lt;Representation&amp;gt; d =
                RestRequest.get(URLs.CONVERSATION + &quot;/&quot; + URL.encode(name)).build();

        d.addCallback(new Callback&amp;lt;Representation&amp;gt;() {
            public void onSuccess(Representation result) {
                Conversation conversation = convertResultToConversation(result);
                eventBus.fireEvent(new ResourceLoadedEvent&amp;lt;Conversation&amp;gt;(conversation));
            }
        });

        d.run();
    }

    public void saveConversation(Conversation conversation) {
        Deferred&amp;lt;Representation&amp;gt; d = RestRequest.post(URLs.CONVERSATION)
                .setRequestData(conversation.toJson()).build();
        
        d.addCallback(new Callback&amp;lt;Representation&amp;gt;() {
            public void onSuccess(Representation result) {
                Conversation conversation = convertResultToConversation(result);
                eventBus.fireEvent(new ResourceSavedEvent&amp;lt;Conversation&amp;gt;(conversation));
            }
        });

        d.run();
    }

    public void deleteConversation(Long id) {
        Deferred&amp;lt;Representation&amp;gt; d =
                RestRequest.post(URLs.CONVERSATION + &quot;/&quot; + id).build();

        d.addCallback(new Callback&amp;lt;Representation&amp;gt;() {
            public void onSuccess(Representation result) {
                eventBus.fireEvent(new ResourceDeletedEvent());
            }
        });

        d.run();
    }

    /**
     * Convenience method to populate object in one location
     *
     * @param result the result of a resource request.
     * @return the populated object.
     */
    private Conversation convertResultToConversation(Representation result) {
        JSOModel model = JSOModel.fromJson(result.getData());
        return new Conversation(model);
    }
}
&lt;/pre&gt;
&lt;p&gt;In the &lt;em&gt;saveConversation()&lt;/em&gt; method you&apos;ll notice the &lt;em&gt;conversation.toJson()&lt;/em&gt; method call. This method uses a JSON class that loops through an objects properties and constructs a JSON String.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public JSON toJson() {
    return new JSON(getMap());
}
&lt;/pre&gt;
&lt;p id=&quot;testing&quot;&gt;&lt;strong&gt;Testing Services&lt;/strong&gt;&lt;br/&gt;
In my experience, the hardest part about using overlay types is writing your objects so they get populated correctly. I&apos;ve found that writing tests which read JSON from a file can be a great productivity boost. However, because of overlay types, you have to write a test that extends GWTTestCase. When using GWTTestCase, you can&apos;t simply read from the filesystem. The good news is there is a workaround where you can subclass GWTShellServlet and overwrite GWT&apos;s web.xml to have your own servlet that &lt;em&gt;can&lt;/em&gt; read from the filesystem. A detailed explanation of how to do this was written by Alex Moffat in &lt;a href=&quot;http://development.lombardi.com/?p=15&quot;&gt;Implementing a -noserver flag for GWTTestCase&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;Once this class is in place, I&apos;ve found you can easily write services using TDD and the server doesn&apos;t even have to exist. When constructing services, I&apos;ve found the following workflow to be the most productive:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a file with the expected JSON in src/test/resources/&lt;em&gt;resource&lt;/em&gt;.json where &lt;em&gt;resource&lt;/em&gt; matches the last part of the URL for your service.&lt;/li&gt;
&lt;li&gt;Create a *ServiceGwtTest.java and write tests.&lt;/li&gt;
&lt;li&gt;Run tests to make sure they fail.&lt;/li&gt;
&lt;li&gt;Implement the service and run tests to ensure JSON is getting consumed/produced properly to/from model objects.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Below is the code for my JsonReaderServlet.java:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class JsonReaderServlet extends GWTShellServlet {

    public void service(ServletRequest servletRequest, ServletResponse servletResponse)
            throws ServletException, IOException {

        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        String uri = req.getRequestURI();
        if (req.getQueryString() != null) {
            uri += &quot;?&quot; + req.getQueryString();
        }

        if (uri.contains(&quot;/services&quot;)) {
            String method = req.getMethod();
            String output;

            if (method.equalsIgnoreCase(&quot;get&quot;)) {
                // use the part after the last slash as the filename
                String filename = uri.substring(uri.lastIndexOf(&quot;/&quot;) + 1, uri.length()) + &quot;.json&quot;;
                System.out.println(&quot;loading: &quot; + filename);
                String json = readFileAsString(&quot;/&quot; + filename);
                System.out.println(&quot;loaded json: &quot; + json);
                output = json;
            } else {
                // for posts, return the same body content
                output = getBody(req);
            }

            PrintWriter out = resp.getWriter();
            out.write(output);
            out.close();

            resp.setStatus(HttpServletResponse.SC_OK);
        } else {
            super.service(servletRequest, servletResponse);
        }
    }

    private String readFileAsString(String filePath) throws IOException {
        filePath = getClass().getResource(filePath).getFile();
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        return getStringFromReader(reader);
    }

    private String getBody(ServletRequest request) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        return getStringFromReader(reader);
    }

    private String getStringFromReader(Reader reader) throws IOException {
        StringBuilder sb = new StringBuilder();
        char[] buf = new char[1024];
        int numRead;
        while ((numRead = reader.read(buf)) != -1) {
            sb.append(buf, 0, numRead);
        }
        reader.close();
        return sb.toString();
    }
}
&lt;/pre&gt;
&lt;p&gt;This servlet is mapped to &lt;code&gt;&amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;/code&gt; in a web.xml file in src/test/resources/com/google/gwt/dev/etc/tomcat/webapps/ROOT/WEB-INF.&lt;/p&gt;
&lt;p&gt;My Service Test starts by getting an EventBus from GIN and registering itself to handle the fired events.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class ConversationServiceGwtTest extends AbstractGwtTestCase
        implements ResourceLoadedEvent.Handler, ResourceSavedEvent.Handler, ResourceDeletedEvent.Handler {
    ConversationService service;
    ResourceLoadedEvent&amp;lt;Conversation&amp;gt; loadedEvent;
    ResourceSavedEvent&amp;lt;Conversation&amp;gt; savedEvent;
    ResourceDeletedEvent deletedEvent;

    @Override
    public void gwtSetUp() throws Exception {
        super.gwtSetUp();
        DesigntimeGinjector injector = GWT.create(MyGinjector.class);
        EventBus eventBus = injector.getEventBus();
        service = new ConversationServiceImpl(eventBus);
        eventBus.addHandler(ResourceLoadedEvent.ENGINE, this);
        eventBus.addHandler(ResourceSavedEvent.ENGINE, this);
        eventBus.addHandler(ResourceDeletedEvent.ENGINE, this);
    }

    @SuppressWarnings(&quot;unchecked&quot;)
    public void onLoad(ResourceLoadedEvent event) {
        this.loadedEvent = event;
    }

    @SuppressWarnings(&quot;unchecked&quot;)
    public void onSave(ResourceSavedEvent event) {
        this.savedEvent = event;
    }

    public void onDelete(ResourceDeletedEvent event) {
        this.deletedEvent = event;
    }
}
&lt;/pre&gt;
&lt;p&gt;After this groundwork has been done, a test can be written that loads up the JSON file and verifies the objects are populated correctly.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public void testGetConversation() {

    service.getConversation(&quot;test-conversation&quot;);

    Timer t = new Timer() {
        public void run() {
            assertNotNull(&quot;ResourceLoadedEvent not received&quot;, loadedEvent);
            Conversation conversation = loadedEvent.getResource();
            assertEquals(&quot;Conversation name is incorrect&quot;,&quot;Test Conversation&quot;, conversation.getName());

            assertNotNull(&quot;Conversation has no channel&quot;, conversation.getChannel());
            assertEquals(&quot;Conversation has incorrect task size&quot;, 3, conversation.getTasks().size());

            convertToAndFromJson(conversation);
            finishTest();
        }
    };

    delayTestFinish(3000);
    t.schedule(100);
}

private void convertToAndFromJson(Conversation fromJsonModel) {
    Representation json = fromJsonModel.toJson();
    assertNotNull(&quot;Cannot convert empty JSON&quot;, json.getData());

    // change back into model
    JSOModel data = JSOModel.fromJson(json.getData());
    Conversation toJsonModel = new Conversation(data);
    verifyModelBuiltCorrectly(toJsonModel);
}

private void verifyModelBuiltCorrectly(Conversation model) {
    assertEquals(&quot;Conversation name is incorrect&quot;, &quot;Test Conversation&quot;, model.getString(&quot;name&quot;));
    assertEquals(&quot;Conversation has incorrect task size&quot;, 3, model.getTasks().size());
    assertEquals(&quot;Conversation channel is incorrect&quot;, &quot;Web&quot;, model.getChannel().getString(&quot;type&quot;));
}
&lt;/pre&gt;
&lt;p&gt;For more information on the usage of the Timer, &lt;em&gt;finishTest()&lt;/em&gt; and &lt;em&gt;delayTestFinish()&lt;/em&gt;, see &lt;a href=&quot;http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/junit/client/GWTTestCase.html#delayTestFinish%28int%29&quot;&gt;GWTTestCase&apos;s javadoc&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
The tests for saving and deleting a resource look as follows:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public void testSaveConversation() {
    Conversation conversation = new Conversation().setName(&quot;Test&quot;).setId(&quot;1&quot;);

    List&amp;lt;Task&amp;gt; tasks = new ArrayList&amp;lt;Task&amp;gt;();
    for (int i = 1; i &amp;lt; 4; i++) {
        tasks.add(new Task().setName(&quot;Task &quot; + i));
    }
    conversation.setTasks(tasks);

    System.out.println(&quot;conversation.toJson(): &quot; + conversation.toJson());

    assertTrue(conversation.toJson().toString().contains(&quot;Task 1&quot;));

    service.saveConversation(conversation);

    Timer t = new Timer() {
        public void run() {
            assertNotNull(&quot;ResourceSavedEvent not received&quot;, savedEvent);
            finishTest();
        }
    };

    delayTestFinish(3000);
    t.schedule(100);
}
  
public void testDeleteConversation() {
    service.deleteConversation(1L);

    Timer t = new Timer() {
        public void run() {
            assertNotNull(&quot;ResourceDeletedEvent not received&quot;, deletedEvent);
            finishTest();
        }
    };

    delayTestFinish(3000);
    t.schedule(100);
}
&lt;/pre&gt;
&lt;p id=&quot;summary&quot;&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;This article has shown you how I develop and test GWT Client Services. If RestyGWT supported overlay types, there&apos;s a good chance I could change my service implementation to use it and I wouldn&apos;t have to change my test. &lt;a href=&quot;http://www.screaming-penguin.com/&quot;&gt;Robert Cooper&lt;/a&gt;, author of &lt;a href=&quot;http://www.manning.com/cooper/&quot;&gt;GWT in Practice&lt;/a&gt;, claims he &lt;a href=&quot;http://twitter.com/kebernet/status/4997144279&quot;&gt;has a framework that does this&lt;/a&gt;. Here&apos;s to hoping this article stimulates the GWT ecosystem and we get a GWT REST framework that&apos;s as easy to use as GWT RPC.
&lt;/p&gt;
&lt;p id=&quot;update&quot;&gt;&lt;strong&gt;Update:&lt;/strong&gt; Today I enhanced this code to use Generics-based classes (inspired by &lt;a href=&quot;http://www.ibm.com/developerworks/java/library/j-genericdao.html&quot;&gt;Don&apos;t repeat the DAO!&lt;/a&gt;) for the boiler-plate CRUD code in a service. In a nutshell, a service interface can now be written as:
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public interface FooService extends GenericService&amp;lt;Foo, String&amp;gt; {
 
}
&lt;/pre&gt;
&lt;p&gt;The implementation class is responsible for the URL and converting the JSON result to an object:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class FooServiceImpl extends GenericServiceImpl&amp;lt;Foo, String&amp;gt; implements FooService {

    @Inject
    public FooServiceImpl(EventBus eventBus) {
        super(eventBus, &quot;/services/foo&quot;);
    }

    @Override
    protected Foo convertResultToModel(Representation result) {
        return new Foo(JSOModel.fromJson(result.getData()));
    }
}
&lt;/pre&gt;
&lt;p&gt;I&apos;m sure this can be further enhanced to get rid of the need to create classes altogether, possibly leveraging &lt;a href=&quot;http://code.google.com/p/google-gin/&quot;&gt;GIN&lt;/a&gt; or some sort of factory. The parent classes referenced in this code can be viewed at the following URLs:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://gist.github.com/216495&quot;&gt;GenericService.java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gist.github.com/216496&quot;&gt;GenericServiceImpl.java&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&apos;s also a &lt;a href=&quot;http://gist.github.com/216497&quot;&gt;GenericServiceGwtTest.java&lt;/a&gt; that proves it all works as expected.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/integrating_gwt_with_spring_security</id>
        <title type="html">Integrating GWT with Spring Security</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/integrating_gwt_with_spring_security"/>
        <published>2009-08-06T08:50:15-06:00</published>
        <updated>2012-10-17T17:35:41-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="authentication" scheme="http://roller.apache.org/ns/tags/" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springsecurity" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Yesterday, I wrote about &lt;a href=&quot;http://raibledesigns.com/rd/entry/how_to_do_cross_domain&quot;&gt;How to do cross-domain GWT RPC with a ProxyServlet&lt;/a&gt;. Today I&apos;ll be discussing
    how to modify the ProxyServlet to authenticate with Spring Security. For the application I&apos;m working on, the ProxyServlet
    is only used in development (when running GWT&apos;s hosted mode) and isn&apos;t necessary when deploying the client and
    server on the same server. Using the ProxyServlet allows cross-domain requests so you can run GWT in hosted mode and
    talk to your backend running on another server. This setup can be especially handy in that you
    can easily point your hosted client at different backends (for example, if you have testing and staging environments).
&lt;/p&gt;
&lt;p&gt;
    In this example, the backend application is a JSF/Spring application that has Spring Security wired in to protect
    services with both Basic and Form-based authentication. Basic authentication will kick in if a &quot;Authorization&quot; header
    is sent, otherwise Form-based authentication is used. Here&apos;s the Spring Security context file that makes this happen:
&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;beans:beans xmlns=&quot;http://www.springframework.org/schema/security&quot;
             xmlns:beans=&quot;http://www.springframework.org/schema/beans&quot;
             xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
             xsi:schemaLocation=&quot;...&quot;&amp;gt;

    &amp;lt;http auto-config=&quot;true&quot; realm=&quot;My Web Application&quot;&amp;gt;
        &amp;lt;intercept-url pattern=&quot;/faces/welcome.jspx&quot; access=&quot;ROLE_USER&quot;/&amp;gt;
        &amp;lt;intercept-url pattern=&quot;/*.rpc&quot; access=&quot;ROLE_USER&quot;/&amp;gt;
        &amp;lt;http-basic/&amp;gt;
        &amp;lt;form-login login-page=&quot;/faces/login.jspx&quot; authentication-failure-url=&quot;/faces/accessDenied.jspx&quot;
                    login-processing-url=&quot;/j_spring_security_check&quot; default-target-url=&quot;/redirect.jsp&quot;
                    always-use-default-target=&quot;true&quot;/&amp;gt;
    &amp;lt;/http&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&quot;/&amp;gt;
        &amp;lt;/user-service&amp;gt;
    &amp;lt;/authentication-provider&amp;gt;
&amp;lt;/beans:beans&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
The easiest way to configure your GWT application to talk to a Spring Security protected resource is to
&lt;a href=&quot;http://www.dotnetguru2.org/bmarchesson/index.php?p=678&amp;amp;more=1&amp;amp;c=1&amp;amp;tb=1&amp;amp;pb=1&quot;&gt;protect your HTML page that GWT is embedded in&lt;/a&gt;. This is the documented way to integrate GWT with Spring Security (ref: 
&lt;a href=&quot;http://code.google.com/p/google-web-toolkit-incubator/wiki/LoginSecurityFAQ&quot;&gt;GWT&apos;s LoginSecurityFAQ&lt;/a&gt;, search for &quot;Acegi&quot;).
This works well for production, but not for hosted-mode development.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Basic Authentication&lt;/strong&gt;&lt;br/&gt;
To authenticate with Basic Authentication, you can use GWT&apos;s RequestBuilder and set an &quot;Authentication&quot; header that
contains the user&apos;s (base64-encoded) credentials.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
private class LoginRequest {
    public LoginRequest(RequestCallback callback) {
        String url = &quot;/services/faces/welcome.jspx&quot;;

        RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, url);
        rb.setHeader(&quot;Authorization&quot;, createBasicAuthToken());
        rb.setCallback(callback);
        try {
            rb.send();
        } catch (RequestException e) {
            Window.alert(e.getMessage());
        }
    }
}

protected String createBasicAuthToken() {
    byte[] bytes = stringToBytes(username.getValue() + &quot;:&quot; + password.getValue());
    String token = Base64.encode(bytes);
    return &quot;Basic &quot; + token;
}

protected byte[] stringToBytes(String msg) {
    int len = msg.length();
    byte[] bytes = new byte[len];
    for (int i = 0; i &amp;lt; len; i++)
        bytes[i] = (byte) (msg.charAt(i) &amp;amp; 0xff);
    return bytes;
}
&lt;/pre&gt;
&lt;p&gt;
To use this LoginRequest class, create it with a callback and look for a 401 response code to determine if
authentication failed.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
new LoginRequest(new RequestCallback() {
    public void onResponseReceived(Request request, Response response) {
        if (response.getStatusCode() != Response.SC_UNAUTHORIZED &amp;amp;&amp;amp;
                response.getStatusCode() != Response.SC_OK) {
            onError(request, new RequestException(response.getStatusText() + &quot;:\n&quot; + response.getText()));
            return;
        }

        if (response.getStatusCode() == Response.SC_UNAUTHORIZED) {
            Window.alert(&quot;You have entered an incorrect username or password. Please try again.&quot;);
        } else {
            // authentication worked, show a fancy dashboard screen
        }
    }

    public void onError(Request request, Throwable throwable) {
        Window.alert(throwable.getMessage());
    }
});
&lt;/pre&gt;
&lt;p&gt;If your GWT application is included in the &quot;services&quot; war, everything should work at this point. However, if you try to login
with invalid credentials, your browser&apos;s login dialog will appear. To suppress this in the aforementioned
ProxyServlet, you&apos;ll need to make a change in its &lt;em&gt;executeProxyRequest()&lt;/em&gt; method so the &quot;WWW-Authenticate&quot; header
is not copied.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
// Pass the response code back to the client
httpServletResponse.setStatus(intProxyResponseCode);

// Pass response headers back to the client
Header[] headerArrayResponse = httpMethodProxyRequest.getResponseHeaders();
for (Header header : headerArrayResponse) {
    if (header.getName().equals(&quot;Transfer-Encoding&quot;) &amp;amp;&amp;amp; header.getValue().equals(&quot;chunked&quot;) ||
            header.getName().equals(&quot;Content-Encoding&quot;) &amp;amp;&amp;amp; header.getValue().equals(&quot;gzip&quot;) ||
            header.getName().equals(&quot;WWW-Authenticate&quot;)) { // don&apos;t copy WWW-Authenticate header
    } else {
        httpServletResponse.setHeader(header.getName(), header.getValue());
    }
}
&lt;/pre&gt;
&lt;p&gt;I&apos;m not sure how to suppress the browser prompt when not using the ProxyServlet. If you have a solution, please
&lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_gwt_with_spring_security#comments&quot;&gt;let me know&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Basic Authentication works well for GWT applications because you don&apos;t need additional logic to retain the
authenticated state after the initial login. While Basic Authentication over SSL might offer a decent solution,
the downside is you can&apos;t logout. Form-based Authentication allows you to logout.&lt;/p&gt;
&lt;strong&gt;Form-based Authentication&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;Before I show you how to implement form-based authentication, you should be aware that Google does not recommend this.
Below is a warning from their LoginSecurityFAQ.&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
Do &lt;i&gt;NOT&lt;/i&gt; attempt to use the &lt;code&gt;Cookie&lt;/code&gt; header to transfer the sessionID from GWT to the server; it is
fraught with security issues that will become clear in the rest of this article. You &lt;strong&gt;MUST&lt;/strong&gt; transfer
the sessionID in the payload of the request. For an example of why this can fail, see CrossSiteRequestForgery.
&lt;/p&gt;
&lt;p&gt;In my experiment, I didn&apos;t want to change the server-side Spring Security configuration, so I ignored this
warning. If you know how to configure Spring Security so it looks for the sessionID in the payload of the request
(rather than in a cookie), I&apos;d love to hear about it. The upside of the example below is it should work with 
container-managed authentication as well.&lt;/p&gt;
&lt;p&gt;
The LoginRequest class for form-based authentication is similar to the previous one, except it has a different URL and
sends the user&apos;s credentials in the request body.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
private class LoginRequest {
    public LoginRequest(RequestCallback callback) {
        String url = &quot;/services/j_spring_security_check&quot;;

        RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, url);
        rb.setHeader(&quot;Content-Type&quot;, &quot;application/x-www-form-urlencoded&quot;);
        rb.setRequestData(&quot;j_username=&quot; + URL.encode(username.getValue()) +
                    &quot;&amp;amp;j_password=&quot; + URL.encode(password.getValue()));

        rb.setCallback(callback);
        try {
            rb.send();
        } catch (RequestException e) {
            Window.alert(e.getMessage());
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;If you deploy your GWT application in the same WAR your services are hosted in, this is all you&apos;ll need to do. If
you&apos;re using the ProxyServlet, there&apos;s a couple of changes you&apos;ll need to make in order to set/send cookies when
running in hosted mode.
&lt;/p&gt;
&lt;p&gt;
First of all, you&apos;ll need to make sure you&apos;ve configured the servlet to follow redirects (by subclassing or simply modifying its default).
After that, add the following logic on line 358 (or just look for &quot;&lt;code&gt;if (followRedirects)&lt;/code&gt;&quot;) to expose the sessionID to the client. The most important part is setting the cookie&apos;s path to &quot;/&quot; so the client (running at localhost:8888) can see it.&lt;/p&gt;
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
if (followRedirects) {
    // happens on first login attempt
    if (stringLocation.contains(&quot;jsessionid&quot;)) { 
        Cookie cookie = new Cookie(&quot;JSESSIONID&quot;,
                stringLocation.substring(stringLocation.indexOf(&quot;jsessionid=&quot;) + 11));
        cookie.setPath(&quot;/&quot;);
        httpServletResponse.addCookie(cookie);
    // the following happens if you refresh your GWT app after already logging in once
    } else if (httpMethodProxyRequest.getResponseHeader(&quot;Set-Cookie&quot;) != null) {
        Header header = httpMethodProxyRequest.getResponseHeader(&quot;Set-Cookie&quot;);
        String[] cookieDetails = header.getValue().split(&quot;;&quot;);
        String[] nameValue = cookieDetails[0].split(&quot;=&quot;);

        Cookie cookie = new Cookie(nameValue[0], nameValue[1]);
        cookie.setPath(&quot;/&quot;);
        httpServletResponse.addCookie(cookie);
    }
    httpServletResponse.sendRedirect(stringLocation.replace(getProxyHostAndPort() +
            this.getProxyPath(), stringMyHostName));
    return;
}
&lt;/pre&gt;
&lt;p style=&quot;font-style: italic&quot;&gt;Click &lt;a href=&quot;http://www.flickr.com/photos/mraible/3794558459/sizes/l/&quot;&gt;here&lt;/a&gt; to see a screenshot of the diff of the ProxyServlet after this code has been added.&lt;/p&gt;
&lt;p&gt;Figuring out that headers needed to be parsed &lt;strong&gt;after&lt;/strong&gt; authenticating successfully and &lt;strong&gt;before&lt;/strong&gt; redirecting was the hardest part for me. If you grab the JSESSIONID from
the &quot;Set-Cookie&quot; header anywhere else, the JSESSIONID is one that hasn&apos;t been authenticated. While the login will work,
subsequent calls to services will fail.&lt;/p&gt;
&lt;p&gt;To make subsequent calls with the cookie in the header, you&apos;ll need to make an additional modification to ProxyServlet to 
send cookies as headers. First of all, add a &lt;em&gt;setProxyRequestCookies()&lt;/em&gt; method:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
/**
 * Retrieves all of the cookies from the servlet request and sets them on
 * the proxy request
 *
 * @param httpServletRequest The request object representing the client&apos;s
 *                            request to the servlet engine
 * @param httpMethodProxyRequest The request that we are about to send to
 *                                the proxy host
 */
@SuppressWarnings(&quot;unchecked&quot;)
private void setProxyRequestCookies(HttpServletRequest httpServletRequest, 
                                    HttpMethod httpMethodProxyRequest) {
    // Get an array of all of all the cookies sent by the client
    Cookie[] cookies = httpServletRequest.getCookies();
    if (cookies == null) {
        return;
    }
    
    for (Cookie cookie : cookies) {
        cookie.setDomain(stringProxyHost);
        cookie.setPath(httpServletRequest.getServletPath());
        httpMethodProxyRequest.setRequestHeader(&quot;Cookie&quot;, cookie.getName() +  
                &quot;=&quot; + cookie.getValue() + &quot;; Path=&quot; + cookie.getPath());
    }
}
&lt;/pre&gt;
&lt;p&gt;Next, in the &lt;em&gt;doGet()&lt;/em&gt; and &lt;em&gt;doPost()&lt;/em&gt; methods, add the following line just after the call to &lt;em&gt;setProxyRequestHeaders()&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
setProxyRequestCookies(httpServletRequest, getMethodProxyRequest);
&amp;nbsp;
&lt;/pre&gt;
&lt;p&gt;After making these modifications to ProxyServlet, you can create LoginRequest and attempt to authenticate. To detect a failed attempt, I&apos;m looking for text in Spring Security&apos;s &quot;authentication-failure-url&quot; page.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
new LoginRequest(new RequestCallback() {

    public void onResponseReceived(Request request, Response response) {
        if (response.getStatusCode() != Response.SC_OK) {
            onError(request, new RequestException(response.getStatusText() + &quot;:\n&quot; + response.getText()));
            return;
        }
        
        if (response.getText().contains(&quot;Access Denied&quot;)) {
            Window.alert(&quot;You have entered an incorrect username or password. Please try again.&quot;);
        } else {
            // authentication worked, show a fancy dashboard screen
        }
    }

    public void onError(Request request, Throwable throwable) {
        Window.alert(throwable.getMessage());
    }
});
&lt;/pre&gt;
&lt;p&gt;After making these changes, you should be able to authenticate with Spring Security&apos;s form-based configuration. While this example doesn&apos;t show how to logout, it should be easy enough to do by 1) deleting the JSESSIONID cookie or 2) calling the Logout URL you have configured in your services WAR.&lt;/p&gt;
&lt;p&gt;Hopefully this howto gives you enough information to configure your GWT application to talk to Spring Security
without modifying your existing backend application. It&apos;s entirely possible that Spring Security offers a more GWT-friendly
authentication mechanism. If you know of a better way to integrate GWT with Spring Security, I&apos;d love to hear about it.&lt;/p&gt;
&lt;p id=&quot;update&quot;&gt;&lt;strong&gt;Update on October 7, 2009&lt;/strong&gt;: I did some additional work on this and got Remember Me working when using form-based authentication. I found I didn&apos;t need as much fancy logic in my ProxyServlet and was able to reduce the &quot;followRequests&quot; logic to the following:
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
if (followRedirects) {
    if (httpMethodProxyRequest.getResponseHeader(&quot;Set-Cookie&quot;) != null) {
        Header[] headers = httpMethodProxyRequest.getResponseHeaders(&quot;Set-Cookie&quot;);
        if (headers.length == 1) {
            extractCookieFromHeader(httpServletResponse, headers[0]);
        } else {
            // ignore the first header since there always seems two jsessionid headers
            // and the 2nd is the valid one
            for (int i = 1; i &lt; headers.length; i++) {
                extractCookieFromHeader(httpServletResponse, headers[i]);
            }
        }
    }
    httpServletResponse.sendRedirect(
            stringLocation.replace(getProxyHostAndPort() + getProxyPath(), stringMyHostName));
    return;
}
&lt;/pre&gt;
&lt;p&gt;I was also able to remove the &lt;em&gt;setProxyRequestCookies()&lt;/em&gt; method completely as it no longer seems necessary.&lt;/p&gt;
&lt;p&gt;Next, I&apos;d like to figure out how to make Spring Security more Ajax-friendly where it can read an authentication token in the request body or header (instead of from a cookie). Also, it&apos;d be sweet if I could convince it to return error codes instead of the login page (for example, when a certain header is present). </content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/how_to_do_cross_domain</id>
        <title type="html">How to do cross-domain GWT RPC with a ProxyServlet</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/how_to_do_cross_domain"/>
        <published>2009-08-05T16:06:12-06:00</published>
        <updated>2014-10-07T19:59:23-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="servlet" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rpc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last week, I started working on a new project using GWT. On my &lt;a href=&quot;http://raibledesigns.com/rd/entry/enhancing_evite_com_with_gwt&quot;&gt;last project&lt;/a&gt;, we used GWT &lt;a href=&quot;http://code.google.com/docreader/#p=google-web-toolkit-doc-1-5&amp;s=google-web-toolkit-doc-1-5&amp;t=DevGuideHttp&quot;&gt;HTTP Calls&lt;/a&gt; and my new project is using &lt;a href=&quot;http://code.google.com/docreader/#p=google-web-toolkit-doc-1-5&amp;s=google-web-toolkit-doc-1-5&amp;t=DevGuideRemoteProcedureCalls&quot;&gt;RPC&lt;/a&gt;. We&apos;ll likely migrate to a JSON backend eventually, but in the meantime, I wanted to be able to develop in hosted mode (localhost:8888) and call services on another host (localhost:8080), where the services are running in a JSF/Spring webapp.
&lt;/p&gt;
&lt;p&gt;At first, I thought it&apos;d be easy thanks to the handy-dandy ProxyServlet I mentioned in &lt;a href=&quot;http://raibledesigns.com/rd/entry/implementing_oauth_with_gwt&quot;&gt;Implementing OAuth with GWT&lt;/a&gt;. However, when I tried to hook it in and use it, I saw the following error in my server-side logs.&lt;/p&gt;
&lt;pre&gt;
java.lang.NullPointerException
        at javax.servlet.GenericServlet.getServletName(GenericServlet.java:322)
        at javax.servlet.GenericServlet.log(GenericServlet.java:277)
        at com.google.gwt.user.server.rpc.RemoteServiceServlet.doGetSerializationPolicy(RemoteServiceServlet.java:219)
        at com.google.gwt.user.server.rpc.RemoteServiceServlet.getSerializationPolicy(RemoteServiceServlet.java:117)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.prepareToRead(ServerSerializationStreamReader.java:429)
        at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:234)
&lt;/pre&gt;
&lt;p&gt;Looking at RemoteServiceServlet.java:219, there&apos;s a logging call that fails for some reason (at least in my application).
&lt;p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
/*
 * Check that the module path must be in the same web app as the servlet
 * itself. If you need to implement a scheme different than this, override
 * this method.
 */
if (modulePath == null || !modulePath.startsWith(contextPath)) {
  String message = &quot;ERROR: The module path requested, &quot;
      + modulePath
      + &quot;, is not in the same web application as this servlet, &quot;
      + contextPath
      + &quot;.  Your module may not be properly configured or your client and server code maybe out of date.&quot;;
  log(message, null);
}
&lt;/pre&gt;&lt;p&gt;In the above code, you might notice that GWT is checking to make sure the client is hosted in the same application as the server. After I figured this out, it was pretty easy to modify my ProxyServlet to trick GWT RPC into thinking the client was in the same web application. In the ProxyServlet&apos;s &lt;em&gt;handleContentPost&lt;/em&gt; method, I added the following code to replace &quot;localhost:8888/&quot; with &quot;localhost:8080/services/&quot; (in the content of the post to the server).
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
if (contentType.startsWith(&quot;text/x-gwt-rpc&quot;)) {
    String clientHost = httpServletRequest.getLocalName();
    if (clientHost.equals(&quot;127.0.0.1&quot;)) {
        clientHost = &quot;localhost&quot;;
    }

    int clientPort = httpServletRequest.getLocalPort();
    String clientUrl = clientHost + ((clientPort != 80) ? &quot;:&quot; + 
                       clientPort : &quot;&quot;);
    String serverUrl = stringProxyHost + ((intProxyPort != 80) ? &quot;:&quot; + 
                       intProxyPort : &quot;&quot;) + httpServletRequest.getServletPath();
    postContent = postContent.replace(clientUrl , serverUrl);
}
&lt;/pre&gt;&lt;p&gt;After manipulating the posted content, I was successfully able to use GWT RPC cross-domain. 
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;Woo hoo!&lt;/em&gt; 
&lt;/p&gt;
&lt;p&gt;
For your convenience, the full &lt;em&gt;handleContentPost()&lt;/em&gt; method is listed below.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
private void handleContentPost(PostMethod postMethodProxyRequest, 
                               HttpServletRequest httpServletRequest) 
            throws IOException, ServletException {
    StringBuilder content = new StringBuilder();
    BufferedReader reader = httpServletRequest.getReader();
    for (;;) {
        String line = reader.readLine();
        if (line == null) break;
        content.append(line);
    }

    String contentType = httpServletRequest.getContentType();
    String postContent = content.toString();

    if (contentType.startsWith(&quot;text/x-gwt-rpc&quot;)) {
        String clientHost = httpServletRequest.getLocalName();
        if (clientHost.equals(&quot;127.0.0.1&quot;)) {
            clientHost = &quot;localhost&quot;;
        }

        int clientPort = httpServletRequest.getLocalPort();
        String clientUrl = clientHost + ((clientPort != 80) ? &quot;:&quot; + 
                           clientPort : &quot;&quot;);
        String serverUrl = stringProxyHost + ((intProxyPort != 80) ? &quot;:&quot; + 
                           intProxyPort : &quot;&quot;) + httpServletRequest.getServletPath();
        postContent = postContent.replace(clientUrl , serverUrl);
    }

    String encoding = httpServletRequest.getCharacterEncoding();
    debug(&quot;POST Content Type: &quot; + contentType + &quot; Encoding: &quot; + encoding,
          &quot;Content: &quot; + postContent);
    StringRequestEntity entity;
    try {
        entity = new StringRequestEntity(postContent, contentType, encoding);
    } catch (UnsupportedEncodingException e) {
        throw new ServletException(e);
    }
    // Set the proxy request POST data
    postMethodProxyRequest.setRequestEntity(entity);
}
&lt;/pre&gt;
&lt;a name=&quot;proxyServlet&quot;&gt;&lt;/a&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; In the comments, Ganesh asked for more details, so I figured it&apos;d be a good idea to post the full source code. First of all, &lt;a href=&quot;http://raibledesigns.com/rd/entry/how_to_do_cross_domain#proxyServlet&quot; onclick=&quot;($(&apos;#proxyServletCode&apos;).is(&apos;:visible&apos;) ? $(&apos;#proxyServletCode&apos;).hide() : $(&apos;#proxyServletCode&apos;).show()); return false&quot;&gt;click here&lt;/a&gt; to see the code for the ProxyServlet:
&lt;/p&gt;
&lt;div style=&quot;display: none&quot; id=&quot;proxyServletCode&quot;&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;

/**
 * ProxyServlet from http://edwardstx.net/wiki/attach/HttpProxyServlet/ProxyServlet.java
 * (This seems to be a derivative of Noodle -- http://noodle.tigris.org/)
 * 
 * Patched to skip &quot;Transfer-Encoding: chunked&quot; headers, avoid double slashes
 * in proxied URLs, handle GZip and allow GWT RPC.
 */
public class ProxyServlet extends HttpServlet {

    private static final int FOUR_KB = 4196;

    /**
     * Serialization UID.
     */
    private static final long serialVersionUID = 1L;
    /**
     * Key for redirect location header.
     */
    private static final String STRING_LOCATION_HEADER = &quot;Location&quot;;
    /**
     * Key for content type header.
     */
    private static final String STRING_CONTENT_ENGINE_HEADER_NAME = &quot;Content-Type&quot;;
    /**
     * Key for content length header.
     */
    private static final String STRING_CONTENT_LENGTH_HEADER_NAME = &quot;Content-Length&quot;;
    /**
     * Key for host header
     */
    private static final String STRING_HOST_HEADER_NAME = &quot;Host&quot;;
    /**
     * The directory to use to temporarily store uploaded files
     */
    private static final File FILE_UPLOAD_TEMP_DIRECTORY = new File(System.getProperty(&quot;java.io.tmpdir&quot;));

    // Proxy host params
    /**
     * The host to which we are proxying requests. Default value is &quot;localhost&quot;.
     */
    private String stringProxyHost = &quot;localhost&quot;;
    /**
     * The port on the proxy host to wihch we are proxying requests. Default value is 80.
     */
    private int intProxyPort = 80;
    /**
     * The (optional) path on the proxy host to wihch we are proxying requests. Default value is &quot;&quot;.
     */
    private String stringProxyPath = &quot;&quot;;
    /**
     * Setting that allows removing the initial path from client. Allows specifying /twitter/* as synonym for twitter.com.
     */
    private boolean removePrefix;
    /**
     * The maximum size for uploaded files in bytes. Default value is 5MB.
     */
    private int intMaxFileUploadSize = 5 * 1024 * 1024;
    private boolean isSecure;
    private boolean followRedirects;

    /**
     * Initialize the &amp;lt;code&amp;gt;ProxyServlet&amp;lt;/code&amp;gt;
     * @param servletConfig The Servlet configuration passed in by the servlet container
     */
    public void init(ServletConfig servletConfig) {
        // Get the proxy host
        String stringProxyHostNew = servletConfig.getInitParameter(&quot;proxyHost&quot;);
        if (stringProxyHostNew == null || stringProxyHostNew.length() == 0) {
            throw new IllegalArgumentException(&quot;Proxy host not set, please set init-param &apos;proxyHost&apos; in web.xml&quot;);
        }
        this.setProxyHost(stringProxyHostNew);
        // Get the proxy port if specified
        String stringProxyPortNew = servletConfig.getInitParameter(&quot;proxyPort&quot;);
        if (stringProxyPortNew != null &amp;amp;&amp;amp; stringProxyPortNew.length() &amp;gt; 0) {
            this.setProxyPort(Integer.parseInt(stringProxyPortNew));
        }
        // Get the proxy path if specified
        String stringProxyPathNew = servletConfig.getInitParameter(&quot;proxyPath&quot;);
        if (stringProxyPathNew != null &amp;amp;&amp;amp; stringProxyPathNew.length() &amp;gt; 0) {
            this.setProxyPath(stringProxyPathNew);
        }
        // Get the maximum file upload size if specified
        String stringMaxFileUploadSize = servletConfig.getInitParameter(&quot;maxFileUploadSize&quot;);
        if (stringMaxFileUploadSize != null &amp;amp;&amp;amp; stringMaxFileUploadSize.length() &amp;gt; 0) {
            this.setMaxFileUploadSize(Integer.parseInt(stringMaxFileUploadSize));
        }
    }

    /**
     * Performs an HTTP GET request
     * @param httpServletRequest The {@link HttpServletRequest} object passed
     *                            in by the servlet engine representing the
     *                            client request to be proxied
     * @param httpServletResponse The {@link HttpServletResponse} object by which
     *                             we can send a proxied response to the client
     */
    public void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
            throws IOException, ServletException {
        // Create a GET request
        String destinationUrl = this.getProxyURL(httpServletRequest);
        debug(&quot;GET Request URL: &quot; + httpServletRequest.getRequestURL(),
              &quot;Destination URL: &quot; + destinationUrl);
        GetMethod getMethodProxyRequest = new GetMethod(destinationUrl);
        // Forward the request headers
        setProxyRequestHeaders(httpServletRequest, getMethodProxyRequest);
        setProxyRequestCookies(httpServletRequest, getMethodProxyRequest);
        // Execute the proxy request
        this.executeProxyRequest(getMethodProxyRequest, httpServletRequest, httpServletResponse);
    }

    /**
     * Performs an HTTP POST request
     * @param httpServletRequest The {@link HttpServletRequest} object passed
     *                            in by the servlet engine representing the
     *                            client request to be proxied
     * @param httpServletResponse The {@link HttpServletResponse} object by which
     *                             we can send a proxied response to the client
     */
    public void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
            throws IOException, ServletException {
        // Create a standard POST request
        String contentType = httpServletRequest.getContentType();
        String destinationUrl = this.getProxyURL(httpServletRequest);
        debug(&quot;POST Request URL: &quot; + httpServletRequest.getRequestURL(),
              &quot;    Content Type: &quot; + contentType,
              &quot; Destination URL: &quot; + destinationUrl);
        PostMethod postMethodProxyRequest = new PostMethod(destinationUrl);
        // Forward the request headers
        setProxyRequestHeaders(httpServletRequest, postMethodProxyRequest);
        setProxyRequestCookies(httpServletRequest, postMethodProxyRequest);
        // Check if this is a mulitpart (file upload) POST
        if (ServletFileUpload.isMultipartContent(httpServletRequest)) {
            this.handleMultipartPost(postMethodProxyRequest, httpServletRequest);
        } else {
            if (contentType == null || PostMethod.FORM_URL_ENCODED_CONTENT_ENGINE.equals(contentType)) {
                this.handleStandardPost(postMethodProxyRequest, httpServletRequest);
            } else {
                this.handleContentPost(postMethodProxyRequest, httpServletRequest);
            }
        }
        // Execute the proxy request
        this.executeProxyRequest(postMethodProxyRequest, httpServletRequest, httpServletResponse);
    }

    /**
     * Sets up the given {@link PostMethod} to send the same multipart POST
     * data as was sent in the given {@link HttpServletRequest}
     * @param postMethodProxyRequest The {@link PostMethod} that we are
     *                                configuring to send a multipart POST request
     * @param httpServletRequest The {@link HttpServletRequest} that contains
     *                            the mutlipart POST data to be sent via the {@link PostMethod}
     */
    @SuppressWarnings(&quot;unchecked&quot;)
    private void handleMultipartPost(PostMethod postMethodProxyRequest, HttpServletRequest httpServletRequest)
            throws ServletException {
        // Create a factory for disk-based file items
        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
        // Set factory constraints
        diskFileItemFactory.setSizeThreshold(this.getMaxFileUploadSize());
        diskFileItemFactory.setRepository(FILE_UPLOAD_TEMP_DIRECTORY);
        // Create a new file upload handler
        ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
        // Parse the request
        try {
            // Get the multipart items as a list
            List&amp;lt;FileItem&amp;gt; listFileItems = (List&amp;lt;FileItem&amp;gt;) servletFileUpload.parseRequest(httpServletRequest);
            // Create a list to hold all of the parts
            List&amp;lt;Part&amp;gt; listParts = new ArrayList&amp;lt;Part&amp;gt;();
            // Iterate the multipart items list
            for (FileItem fileItemCurrent : listFileItems) {
                // If the current item is a form field, then create a string part
                if (fileItemCurrent.isFormField()) {
                    StringPart stringPart = new StringPart(
                            fileItemCurrent.getFieldName(), // The field name
                            fileItemCurrent.getString() // The field value
                            );
                    // Add the part to the list
                    listParts.add(stringPart);
                } else {
                    // The item is a file upload, so we create a FilePart
                    FilePart filePart = new FilePart(
                            fileItemCurrent.getFieldName(), // The field name
                            new ByteArrayPartSource(
                            fileItemCurrent.getName(), // The uploaded file name
                            fileItemCurrent.get() // The uploaded file contents
                            ));
                    // Add the part to the list
                    listParts.add(filePart);
                }
            }
            MultipartRequestEntity multipartRequestEntity = new MultipartRequestEntity(
                    listParts.toArray(new Part&amp;#91;&amp;#93;{}),
                    postMethodProxyRequest.getParams());
            postMethodProxyRequest.setRequestEntity(multipartRequestEntity);
            // The current content-type header (received from the client) IS of
            // type &quot;multipart/form-data&quot;, but the content-type header also
            // contains the chunk boundary string of the chunks. Currently, this
            // header is using the boundary of the client request, since we
            // blindly copied all headers from the client request to the proxy
            // request. However, we are creating a new request with a new chunk
            // boundary string, so it is necessary that we re-set the
            // content-type string to reflect the new chunk boundary string
            postMethodProxyRequest.setRequestHeader(STRING_CONTENT_ENGINE_HEADER_NAME, multipartRequestEntity.getContentType());
        } catch (FileUploadException fileUploadException) {
            throw new ServletException(fileUploadException);
        }
    }

    /**
     * Sets up the given {@link PostMethod} to send the same standard POST
     * data as was sent in the given {@link HttpServletRequest}
     * @param postMethodProxyRequest The {@link PostMethod} that we are
     *                                configuring to send a standard POST request
     * @param httpServletRequest The {@link HttpServletRequest} that contains
     *                            the POST data to be sent via the {@link PostMethod}
     */
    @SuppressWarnings(&quot;unchecked&quot;)
    private void handleStandardPost(PostMethod postMethodProxyRequest, HttpServletRequest httpServletRequest) {
        // Get the client POST data as a Map
        Map&amp;lt;String, String&amp;#91;&amp;#93;&amp;gt; mapPostParameters = (Map&amp;lt;String, String&amp;#91;&amp;#93;&amp;gt;) httpServletRequest.getParameterMap();
        // Create a List to hold the NameValuePairs to be passed to the PostMethod
        List&amp;lt;NameValuePair&amp;gt; listNameValuePairs = new ArrayList&amp;lt;NameValuePair&amp;gt;();
        // Iterate the parameter names
        for (String stringParameterName : mapPostParameters.keySet()) {
            // Iterate the values for each parameter name
            String&amp;#91;&amp;#93; stringArrayParameterValues = mapPostParameters.get(stringParameterName);
            for (String stringParamterValue : stringArrayParameterValues) {
                // Create a NameValuePair and store in list
                NameValuePair nameValuePair = new NameValuePair(stringParameterName, stringParamterValue);
                listNameValuePairs.add(nameValuePair);
            }
        }
        // Set the proxy request POST data
        postMethodProxyRequest.setRequestBody(listNameValuePairs.toArray(new NameValuePair&amp;#91;&amp;#93;{}));
    }

    /**
     * Sets up the given {@link PostMethod} to send the same content POST
     * data (JSON, XML, etc.) as was sent in the given {@link HttpServletRequest}
     * @param postMethodProxyRequest The {@link PostMethod} that we are
     *                                configuring to send a standard POST request
     * @param httpServletRequest The {@link HttpServletRequest} that contains
     *                            the POST data to be sent via the {@link PostMethod}
     */
    private void handleContentPost(PostMethod postMethodProxyRequest, HttpServletRequest httpServletRequest) throws IOException, ServletException {
        StringBuilder content = new StringBuilder();
        BufferedReader reader = httpServletRequest.getReader();
        for (;;) {
            String line = reader.readLine();
            if (line == null) break;
            content.append(line);
        }

        String contentType = httpServletRequest.getContentType();
        String postContent = content.toString();

        if (contentType.startsWith(&quot;text/x-gwt-rpc&quot;)) {
            String clientHost = httpServletRequest.getLocalName();
            if (clientHost.equals(&quot;127.0.0.1&quot;)) {
                clientHost = &quot;localhost&quot;;
            }

            int clientPort = httpServletRequest.getLocalPort();
            String clientUrl = clientHost + ((clientPort != 80) ? &quot;:&quot; + clientPort : &quot;&quot;);
            String serverUrl = stringProxyHost + ((intProxyPort != 80) ? &quot;:&quot; + intProxyPort : &quot;&quot;) + httpServletRequest.getServletPath();
            //debug(&quot;Replacing client (&quot; + clientUrl + &quot;) with server (&quot; + serverUrl + &quot;)&quot;);
            postContent = postContent.replace(clientUrl , serverUrl);
        }

        String encoding = httpServletRequest.getCharacterEncoding();
        debug(&quot;POST Content Type: &quot; + contentType + &quot; Encoding: &quot; + encoding,
              &quot;Content: &quot; + postContent);
        StringRequestEntity entity;
        try {
            entity = new StringRequestEntity(postContent, contentType, encoding);
        } catch (UnsupportedEncodingException e) {
            throw new ServletException(e);
        }
        // Set the proxy request POST data
        postMethodProxyRequest.setRequestEntity(entity);
    }

    /**
     * Executes the {@link HttpMethod} passed in and sends the proxy response
     * back to the client via the given {@link HttpServletResponse}
     * @param httpMethodProxyRequest An object representing the proxy request to be made
     * @param httpServletResponse An object by which we can send the proxied
     *                             response back to the client
     * @throws IOException Can be thrown by the {@link HttpClient}.executeMethod
     * @throws ServletException Can be thrown to indicate that another error has occurred
     */
    private void executeProxyRequest(
            HttpMethod httpMethodProxyRequest,
            HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse)
            throws IOException, ServletException {
        // Create a default HttpClient
        HttpClient httpClient = new HttpClient();
        httpMethodProxyRequest.setFollowRedirects(false);
        // Execute the request
        int intProxyResponseCode = httpClient.executeMethod(httpMethodProxyRequest);
        String response = httpMethodProxyRequest.getResponseBodyAsString();

        // Check if the proxy response is a redirect
        // The following code is adapted from org.tigris.noodle.filters.CheckForRedirect
        // Hooray for open source software
        if (intProxyResponseCode &amp;gt;= HttpServletResponse.SC_MULTIPLE_CHOICES /* 300 */ &amp;amp;&amp;amp; intProxyResponseCode &amp;lt; HttpServletResponse.SC_NOT_MODIFIED /* 304 */) {
            String stringStatusCode = Integer.toString(intProxyResponseCode);
            String stringLocation = httpMethodProxyRequest.getResponseHeader(STRING_LOCATION_HEADER).getValue();
            if (stringLocation == null) {
                throw new ServletException(&quot;Received status code: &quot; + stringStatusCode + &quot; but no &quot; + STRING_LOCATION_HEADER + &quot; header was found in the response&quot;);
            }
            // Modify the redirect to go to this proxy servlet rather that the proxied host
            String stringMyHostName = httpServletRequest.getServerName();
            if (httpServletRequest.getServerPort() != 80) {
                stringMyHostName += &quot;:&quot; + httpServletRequest.getServerPort();
            }
            stringMyHostName += httpServletRequest.getContextPath();
            if (followRedirects) {
                if (stringLocation.contains(&quot;jsessionid&quot;)) {
                    Cookie cookie = new Cookie(&quot;JSESSIONID&quot;, stringLocation.substring(stringLocation.indexOf(&quot;jsessionid=&quot;) + 11));
                    cookie.setPath(&quot;/&quot;);
                    httpServletResponse.addCookie(cookie);
                    //debug(&quot;redirecting: set jessionid (&quot; + cookie.getValue() + &quot;) cookie from URL&quot;);
                } else if (httpMethodProxyRequest.getResponseHeader(&quot;Set-Cookie&quot;) != null) {
	                Header header = httpMethodProxyRequest.getResponseHeader(&quot;Set-Cookie&quot;);
                    String&amp;#91;&amp;#93; cookieDetails = header.getValue().split(&quot;;&quot;);
					String&amp;#91;&amp;#93; nameValue = cookieDetails&amp;#91;0&amp;#93;.split(&quot;=&quot;);

					Cookie cookie = new Cookie(nameValue&amp;#91;0&amp;#93;, nameValue&amp;#91;1&amp;#93;);
					cookie.setPath(&quot;/&quot;);
					//debug(&quot;redirecting: setting cookie: &quot; + cookie.getName() + &quot;:&quot; + cookie.getValue() + &quot; on &quot; + cookie.getPath());
					httpServletResponse.addCookie(cookie);
                }
                httpServletResponse.sendRedirect(stringLocation.replace(getProxyHostAndPort() + this.getProxyPath(), stringMyHostName));
                return;
            }
        } else if (intProxyResponseCode == HttpServletResponse.SC_NOT_MODIFIED) {
            // 304 needs special handling.  See:
            // http://www.ics.uci.edu/pub/ietf/http/rfc1945.html#Code304
            // We get a 304 whenever passed an &apos;If-Modified-Since&apos;
            // header and the data on disk has not changed; server
            // responds w/ a 304 saying I&apos;m not going to send the
            // body because the file has not changed.
            httpServletResponse.setIntHeader(STRING_CONTENT_LENGTH_HEADER_NAME, 0);
            httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }

        // Pass the response code back to the client
        httpServletResponse.setStatus(intProxyResponseCode);

        // Pass response headers back to the client
        Header&amp;#91;&amp;#93; headerArrayResponse = httpMethodProxyRequest.getResponseHeaders();
        for (Header header : headerArrayResponse) {
            if (header.getName().equals(&quot;Transfer-Encoding&quot;) &amp;amp;&amp;amp; header.getValue().equals(&quot;chunked&quot;) ||
                    header.getName().equals(&quot;Content-Encoding&quot;) &amp;amp;&amp;amp; header.getValue().equals(&quot;gzip&quot;) || // don&apos;t copy gzip header
                    header.getName().equals(&quot;WWW-Authenticate&quot;)) { // don&apos;t copy WWW-Authenticate header so browser doesn&apos;t prompt on failed basic auth
                // proxy servlet does not support chunked encoding
            } else {
                httpServletResponse.setHeader(header.getName(), header.getValue());
            }
        }

        List&amp;lt;Header&amp;gt; responseHeaders = Arrays.asList(headerArrayResponse);

        if (isBodyParameterGzipped(responseHeaders)) {
            debug(&quot;GZipped: true&quot;);
            if (!followRedirects &amp;amp;&amp;amp; intProxyResponseCode == HttpServletResponse.SC_MOVED_TEMPORARILY) {
                response = httpMethodProxyRequest.getResponseHeader(STRING_LOCATION_HEADER).getValue();
                httpServletResponse.setStatus(HttpServletResponse.SC_OK);
                intProxyResponseCode = HttpServletResponse.SC_OK;
                httpServletResponse.setHeader(STRING_LOCATION_HEADER, response);
            } else {
                response = new String(ungzip(httpMethodProxyRequest.getResponseBody()));
            }
            httpServletResponse.setContentLength(response.length());
        }

        // Send the content to the client
        debug(&quot;Received status code: &quot; + intProxyResponseCode,
              &quot;Response: &quot; + response);

        httpServletResponse.getWriter().write(response);
    }


    /**
     * The response body will be assumed to be gzipped if the GZIP header has been set.
     *
     * @param responseHeaders of response headers
     * @return true if the body is gzipped
     */
    private boolean isBodyParameterGzipped(List&amp;lt;Header&amp;gt; responseHeaders) {
        for (Header header : responseHeaders) {
            if (header.getValue().equals(&quot;gzip&quot;)) {
                return true;
            }
        }
        return false;
    }

    /**
     * A highly performant ungzip implementation. Do not refactor this without taking new timings.
     * See ElementTest in ehcache for timings
     *
     * @param gzipped the gzipped content
     * @return an ungzipped byte&amp;#91;&amp;#93;
     * @throws java.io.IOException when something bad happens
     */
    private byte&amp;#91;&amp;#93; ungzip(final byte&amp;#91;&amp;#93; gzipped) throws IOException {
        final GZIPInputStream inputStream = new GZIPInputStream(new ByteArrayInputStream(gzipped));
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(gzipped.length);
        final byte&amp;#91;&amp;#93; buffer = new byte&amp;#91;FOUR_KB&amp;#93;;
        int bytesRead = 0;
        while (bytesRead != -1) {
            bytesRead = inputStream.read(buffer, 0, FOUR_KB);
            if (bytesRead != -1) {
                byteArrayOutputStream.write(buffer, 0, bytesRead);
            }
        }
        byte&amp;#91;&amp;#93; ungzipped = byteArrayOutputStream.toByteArray();
        inputStream.close();
        byteArrayOutputStream.close();
        return ungzipped;
    }

    public String getServletInfo() {
        return &quot;GWT Proxy Servlet&quot;;
    }

    /**
     * Retrieves all of the headers from the servlet request and sets them on
     * the proxy request
     *
     * @param httpServletRequest The request object representing the client&apos;s
     *                            request to the servlet engine
     * @param httpMethodProxyRequest The request that we are about to send to
     *                                the proxy host
     */
    @SuppressWarnings(&quot;unchecked&quot;)
    private void setProxyRequestHeaders(HttpServletRequest httpServletRequest, HttpMethod httpMethodProxyRequest) {
        // Get an Enumeration of all of the header names sent by the client
        Enumeration enumerationOfHeaderNames = httpServletRequest.getHeaderNames();
        while (enumerationOfHeaderNames.hasMoreElements()) {
            String stringHeaderName = (String) enumerationOfHeaderNames.nextElement();
            if (stringHeaderName.equalsIgnoreCase(STRING_CONTENT_LENGTH_HEADER_NAME)) {
                continue;
            }
            // As per the Java Servlet API 2.5 documentation:
            //		Some headers, such as Accept-Language can be sent by clients
            //		as several headers each with a different value rather than
            //		sending the header as a comma separated list.
            // Thus, we get an Enumeration of the header values sent by the client
            Enumeration enumerationOfHeaderValues = httpServletRequest.getHeaders(stringHeaderName);
            while (enumerationOfHeaderValues.hasMoreElements()) {
                String stringHeaderValue = (String) enumerationOfHeaderValues.nextElement();
                // In case the proxy host is running multiple virtual servers,
                // rewrite the Host header to ensure that we get content from
                // the correct virtual server
                if (stringHeaderName.equalsIgnoreCase(STRING_HOST_HEADER_NAME)) {
                    stringHeaderValue = getProxyHostAndPort();
                }
                Header header = new Header(stringHeaderName, stringHeaderValue);
                // Set the same header on the proxy request
                httpMethodProxyRequest.setRequestHeader(header);
            }
        }
    }

    /**
     * Retrieves all of the cookies from the servlet request and sets them on
     * the proxy request
     *
     * @param httpServletRequest The request object representing the client&apos;s
     *                            request to the servlet engine
     * @param httpMethodProxyRequest The request that we are about to send to
     *                                the proxy host
     */
    @SuppressWarnings(&quot;unchecked&quot;)
    private void setProxyRequestCookies(HttpServletRequest httpServletRequest, HttpMethod httpMethodProxyRequest) {
        // Get an array of all of all the cookies sent by the client
        Cookie&amp;#91;&amp;#93; cookies = httpServletRequest.getCookies();
        if (cookies == null) {
            return;
        }

        for (Cookie cookie : cookies) {
            cookie.setDomain(stringProxyHost);
            cookie.setPath(httpServletRequest.getServletPath());
            httpMethodProxyRequest.setRequestHeader(&quot;Cookie&quot;, cookie.getName() + &quot;=&quot; + cookie.getValue() + &quot;; Path=&quot; + cookie.getPath());
        }
    }

    // Accessors
    private String getProxyURL(HttpServletRequest httpServletRequest) {
        // Set the protocol to HTTP
        String protocol = (isSecure) ? &quot;https://&quot; : &quot;http://&quot;;
        String stringProxyURL = protocol + this.getProxyHostAndPort();

        // simply use whatever servlet path that was part of the request as opposed to getting a preset/configurable proxy path
        if (!removePrefix) {
            stringProxyURL += httpServletRequest.getServletPath();
        }
        stringProxyURL += &quot;/&quot;;
        
        // Handle the path given to the servlet
        String pathInfo = httpServletRequest.getPathInfo();
        if (pathInfo != null &amp;amp;&amp;amp; pathInfo.startsWith(&quot;/&quot;)) {
            if (stringProxyURL != null &amp;amp;&amp;amp; stringProxyURL.endsWith(&quot;/&quot;)) {
                // avoid double &apos;/&apos;
                stringProxyURL += pathInfo.substring(1);
            }
        } else {
            stringProxyURL += httpServletRequest.getPathInfo();
        }
        // Handle the query string
        if (httpServletRequest.getQueryString() != null) {
            stringProxyURL += &quot;?&quot; + httpServletRequest.getQueryString();
        }
        
        return stringProxyURL;
    }

    private String getProxyHostAndPort() {
        if (this.getProxyPort() == 80) {
            return this.getProxyHost();
        } else {
            return this.getProxyHost() + &quot;:&quot; + this.getProxyPort();
        }
    }

    protected String getProxyHost() {
        return this.stringProxyHost;
    }

    protected void setProxyHost(String stringProxyHostNew) {
        this.stringProxyHost = stringProxyHostNew;
    }

    protected int getProxyPort() {
        return this.intProxyPort;
    }

    protected void setSecure(boolean secure) {
        this.isSecure = secure;
    }
    
    protected void setFollowRedirects(boolean followRedirects) {
        this.followRedirects = followRedirects;
    }

    protected void setProxyPort(int intProxyPortNew) {
        this.intProxyPort = intProxyPortNew;
    }

    protected String getProxyPath() {
        return this.stringProxyPath;
    }

    protected void setProxyPath(String stringProxyPathNew) {
        this.stringProxyPath = stringProxyPathNew;
    }

    protected void setRemovePrefix(boolean removePrefix) {
        this.removePrefix = removePrefix;
    }

    protected int getMaxFileUploadSize() {
        return this.intMaxFileUploadSize;
    }

    protected void setMaxFileUploadSize(int intMaxFileUploadSizeNew) {
        this.intMaxFileUploadSize = intMaxFileUploadSizeNew;
    }

    private void debug(String ... msg) {
        for (String m : msg) {
            System.out.println(&quot;&amp;#91;DEBUG&amp;#93; &quot; + m);
        }
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I generally subclass ProxyServlet to provide my own configuration:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class MyProxyServlet extends ProxyServlet {

    @Override
    public void init(ServletConfig servletConfig) {
        setFollowRedirects(true);
        setRemovePrefix(false);
        setProxyPort(8080);
    }
}
&lt;/pre&gt;
&lt;p&gt;Here&apos;s another example that reads configuration settings from web.xml and proxies to a different domain name:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class AlternateHostProxyServlet extends ProxyServlet {

    @Override
    public void init(ServletConfig servletConfig) {

        setProxyHost(servletConfig.getInitParameter(&quot;proxyHost&quot;));

        String secure = servletConfig.getInitParameter(&quot;secure&quot;);
        if (secure != null) {
            setSecure(Boolean.valueOf(secure));
        }

        setFollowRedirects(false);
        setRemovePrefix(true);
        setProxyPort(80);
    }
}
&lt;/pre&gt;
&lt;p&gt;After you&apos;ve added these to your project, simply map the servlet (and its path) in your *.gwt.xml file (if you&apos;re using GWT) and your web.xml.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/abbie_is_a_blue_skier</id>
        <title type="html">Abbie is a Blue Skier!</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/abbie_is_a_blue_skier"/>
        <published>2008-12-14T21:55:44-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/General" label="General" />
        <category term="winterpark" scheme="http://roller.apache.org/ns/tags/" />
        <category term="abbie" scheme="http://roller.apache.org/ns/tags/" />
        <category term="skiing" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">On Friday afternoon, the kids and I headed up to &lt;a href=&quot;http://www.skiwinterpark.com&quot;&gt;Winter Park&lt;/a&gt; for a night at &lt;a href=&quot;http://www.zephyrlodge.com/&quot;&gt;Zephyr Lodge&lt;/a&gt;. The drive up was great (no traffic) and it started snowing as soon as we got off I-70. 45 minutes later and the kids were on the slopes for the last few runs of the day. There was a few inches of snow that turned out to be great - it slowed them down enough that they didn&apos;t have to turn or worry about &quot;pizza&quot;.
&lt;/p&gt;
&lt;p&gt;On Saturday, we put Jack in Ski School and Abbie and I had a &quot;Daddy + Daughter&quot; day on the mountain. She didn&apos;t want to hit the &lt;em&gt;magic carpet&lt;/em&gt; and instead opted for the lift right away. We skied a couple greens and w/in an hour she was ready to try a blue. She did quite well on the blue and even skied a few bumps on the side. Yes, she did fall a few times, but she got up by herself and always had a smile on her face. I was extremely proud. Below are a few pictures and a video from our weekend. &lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm4.static.flickr.com/3063/3107648565_f3c033ce75_o.jpg&quot; rel=&quot;lightbox[blueskier]&quot; title=&quot;Riding the Magic Carpet&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3063/3107648565_fda79fa7ca_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Riding the Magic Carpet&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3154/3108482528_742632b4ea_o.jpg&quot; rel=&quot;lightbox[blueskier]&quot; title=&quot;Snowball Fight!&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3154/3108482528_7d7e2d4e25_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Snowball Fight!&quot; style=&quot;border: 1px solid black; margin-left: 20px&quot; /&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3128/3108482778_f52d712c1a_o.jpg&quot; rel=&quot;lightbox[blueskier]&quot; title=&quot;Pizza&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3128/3108482778_fbff80d47a_t.jpg&quot; width=&quot;100&quot; height=&quot;75&quot; alt=&quot;Pizza&quot; style=&quot;border: 1px solid black; margin-left: 20px&quot;/&gt;&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;object width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/Dw97Bf9xTLE&amp;hl=en&amp;fs=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/Dw97Bf9xTLE&amp;amp;hl=en&amp;amp;fs=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;/p&gt;
&lt;p&gt;I&apos;m glad I took the kids skiing yesterday. It&apos;s been dumping with cold temperatures ever since we left. It&apos;s currently -15&amp;deg;F in Denver (a &lt;a href=&quot;http://www.9news.com/news/article.aspx?storyid=105730&amp;amp;catid=339&quot;&gt;new record&lt;/a&gt;) and it&apos;s snowed 2 feet at some resorts. Now I just need to figure out a way to make it up a couple of times this week. &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/building_rich_applications_with_appcelerator</id>
        <title type="html">Building Rich Applications with Appcelerator</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/building_rich_applications_with_appcelerator"/>
        <published>2008-10-22T16:18:42-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appcelerator" scheme="http://roller.apache.org/ns/tags/" />
        <category term="softwaresummit" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ria" scheme="http://roller.apache.org/ns/tags/" />
        <category term="flex" scheme="http://roller.apache.org/ns/tags/" />
        <category term="presentation" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This afternoon, I delivered my &lt;a href=&quot;http://softwaresummit.com/2008/speakers/raible.htm&quot;&gt;Building Rich Applications with Appcelerator&lt;/a&gt; talk for the 3rd time at Colorado Software Summit. When I first proposed this topic, I hadn&apos;t used &lt;a href=&quot;http://appcelerator.org&quot;&gt;Appcelerator&lt;/a&gt; and saw this as a good opportunity to learn more about it. I&apos;m glad I did.
&lt;/p&gt;
&lt;p&gt;
IMO, Appcelerator is a lot like Dojo in how it parses pages and turns HTML with special attributes into JavaScript widgets. I can&apos;t help but think a pre-compilation step would be nice to speed things up. I like Appcelerator&apos;s extensive &lt;a href=&quot;http://doc.appcelerator.org/reference/widget_reference/index.html&quot;&gt;Widget Library&lt;/a&gt;, and I especially like that they re-use many widgets rather than re-creating their own. Finally, I really dig the &quot;SOA in a browser&quot; approach where everything is a message and you can easily publish and subscribe to events - on the client and server. Below is my presentation, please let me know if you have any questions.
&lt;/p&gt;
&lt;div style=&quot;text-align: center&quot;&gt;&lt;object style=&quot;margin:0px&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slideshare.net/swf/ssplayer2.swf?doc=building-rich-applications-with-appcelerator-12002&amp;stripped_title=building-rich-applications-with-appcelerator&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 src=&quot;//static.slideshare.net/swf/ssplayer2.swf?doc=building-rich-applications-with-appcelerator-12002&amp;stripped_title=building-rich-applications-with-appcelerator&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;div style=&quot;font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;&quot;&gt;&lt;a style=&quot;text-decoration:underline;&quot; href=&quot;http://www.slideshare.net/mraible/building-rich-applications-with-appcelerator?type=powerpoint&quot; title=&quot;View Building Rich Applications with Appcelerator on SlideShare&quot;&gt;View on Slideshare&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/what_s_coming_in_spring</id>
        <title type="html">What&apos;s Coming in Spring 3.0</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/what_s_coming_in_spring"/>
        <published>2008-10-22T11:51:12-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springframework" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rest" scheme="http://roller.apache.org/ns/tags/" />
        <category term="presentation" scheme="http://roller.apache.org/ns/tags/" />
        <category term="annotations" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <category term="softwaresummit" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springexpressionlanguage" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This morning, I delivered my &lt;a href=&quot;http://softwaresummit.com/2008/speakers/raible.htm&quot;&gt;What&apos;s Coming in Spring 3.0&lt;/a&gt; talk for the 2nd time at Colorado Software Summit. Since there is no Spring 3.0 source code to speak of, I was unable to do the &quot;Choose Your Own Adventure&quot; demo at the end. &lt;img src=&quot;https://raibledesigns.com/images/smileys/sad.gif&quot; class=&quot;smiley&quot; alt=&quot;:(&quot; title=&quot;:(&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;
The good news is I was able to easily upgrade the &lt;a href=&quot;http://spring-kickstart.googlecode.com&quot;&gt;Spring Kickstart&lt;/a&gt; application from Spring 2.0 to Spring 2.5.5 (using annotations). When 3.0 is released, I hope to update this project to use 3.0 as well as show what I needed to change. If I get ambitious, I might even change the UI to use Flex or Ext JS to show a RESTful client. Below is my presentation - hope you enjoy.
&lt;/p&gt;
&lt;div style=&quot;text-align:center&quot;&gt;&lt;object style=&quot;margin:0px&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slideshare.net/swf/ssplayer2.swf?doc=whats-coming-in-spring-30-18636&amp;stripped_title=whats-coming-in-spring-30&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 src=&quot;//static.slideshare.net/swf/ssplayer2.swf?doc=whats-coming-in-spring-30-18636&amp;stripped_title=whats-coming-in-spring-30&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;div style=&quot;font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;&quot;&gt;&lt;a style=&quot;text-decoration:underline;&quot; href=&quot;http://www.slideshare.net/mraible/whats-coming-in-spring-30?type=powerpoint&quot; title=&quot;View What&amp;#39;s Coming in Spring 3.0 on SlideShare&quot;&gt;View on Slideshare&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/oktoberfest_best_vacation_ever</id>
        <title type="html">Oktoberfest: Best. Vacation. Ever.</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/oktoberfest_best_vacation_ever"/>
        <published>2008-10-01T22:37:49-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/General" label="General" />
        <category term="munich" scheme="http://roller.apache.org/ns/tags/" />
        <category term="travel" scheme="http://roller.apache.org/ns/tags/" />
        <category term="germany" scheme="http://roller.apache.org/ns/tags/" />
        <category term="friends" scheme="http://roller.apache.org/ns/tags/" />
        <category term="oktoberfest" scheme="http://roller.apache.org/ns/tags/" />
        <category term="vacation" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">As &lt;a href=&quot;http://raibledesigns.com/rd/entry/my_oktoberfest_adventure_begins&quot;&gt;mentioned earlier&lt;/a&gt;, a good friend (Miller) and I took a vacation to &lt;a href=&quot;http://en.wikipedia.org/wiki/Oktoberfest&quot;&gt;Oktoberfest&lt;/a&gt; last week. The flight over was brutal: Denver -&gt; Newark (4 hour layover) -&gt; Paris (2 hour layover) -&gt; Munich. I was pretty disappointed to see &quot;No Service&quot; on my iPhone when we landed in France. This continued in Munich and I quickly decided connectivity wasn&apos;t necessary. After a 80 &amp;euro; cab ride from the airport, we arrived at our hotel around 1PM on Monday. We both woke up at 4AM on Sunday to start the journey, so we were pretty beat.&lt;br/&gt;&lt;br/&gt;
It didn&apos;t take us long to decide we had to suck it up and head to &quot;The Tents&quot; at Oktoberfest. We walked the 4 blocks in the rain and quickly ended up in the Armbrustschutzenzelt tent. The crowd was small and we found a table and enjoyed our first Liter.&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;a href=&quot;http://farm4.static.flickr.com/3270/2904119692_db0bf800be_o.jpg&quot; title=&quot;Weather on Arrival in Munich&quot; rel=&quot;lightbox[oktoberfest]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3270/2904119692_7523926831_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Weather on Arrival in Munich&quot; style=&quot;border: 1px solid black&quot;/&gt;&lt;/a&gt;

&lt;a href=&quot;http://farm4.static.flickr.com/3226/2904119864_f99cb5e45e_o.jpg&quot; title=&quot;Day 1 - First Tent&quot; rel=&quot;lightbox[oktoberfest]&quot;&gt;&lt;img src=&quot;//farm4.static.flickr.com/3226/2904119864_a37b04fd61_m.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; alt=&quot;Day 1 - First Tent&quot; style=&quot;border: 1px solid black; margin-left: 10px&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I won&apos;t go into details about how much fun we had during the week, except for these simple stats:&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;Made it into &lt;em&gt;The Tents&lt;/em&gt; 5 days in a row&lt;/li&gt;
&lt;li&gt;Mostly slept in until 2 or 4PM each day&lt;/li&gt; 
&lt;li&gt;No Hangovers (for me at least)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&apos;ve uploaded most of the pictures I took to an &lt;a href=&quot;http://flickr.com/photos/mraible/sets/72157607621076504/&quot;&gt;Oktoberfest 2008 set on Flickr&lt;/a&gt;. I would like to thank &lt;a href=&quot;http://farm4.static.flickr.com/3136/2904127088_9fa0c382bd_o.jpg&quot; rel=&quot;lightbox[oktoberfest]&quot;&gt;Peter and friends&lt;/a&gt; for being fabulous hosts and showing us a great time on Thursday night. Below is a video I took of what the festivities were like (yes, that is Bon Jovi):&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/eBzoeUja8kA&amp;hl=en&amp;fs=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/eBzoeUja8kA&amp;hl=en&amp;fs=1&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;If you ever get a chance to attend Oktoberfest, I highly recommend it.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/oscon_2008_web_frameworks_of</id>
        <title type="html">[OSCON 2008] Web Frameworks of the Future: Flex, GWT, Grails and Rails</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/oscon_2008_web_frameworks_of"/>
        <published>2008-07-23T16:25:23-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Open Source" label="Open Source" />
        <category term="rails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="oscon" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rest" scheme="http://roller.apache.org/ns/tags/" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="oscon08" scheme="http://roller.apache.org/ns/tags/" />
        <category term="flex" scheme="http://roller.apache.org/ns/tags/" />
        <category term="grails" scheme="http://roller.apache.org/ns/tags/" />
        <category term="opensource" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Below is the presentation I&apos;m &lt;a href=&quot;http://en.oreilly.com/oscon2008/public/schedule/speaker/6444&quot;&gt;delivering at OSCON&lt;/a&gt; today. Unfortunately, I had to remove slides on GWT and Flex to fit w/in the 45 minute time limit. I hope to expand this presentation in the future, as well as continue to develop the side project I&apos;m working on using these technologies.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object style=&quot;margin:0px&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slideshare.net/swf/ssplayer2.swf?doc=webframeworksofthefutureflexgwtrailsandgrails-1216842992390310-9&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 src=&quot;//static.slideshare.net/swf/ssplayer2.swf?doc=webframeworksofthefutureflexgwtrailsandgrails-1216842992390310-9&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;div style=&quot;font-size: .9em; text-align: center&quot;&gt;
&lt;a href=&quot;http://www.slideshare.net/mraible/web-frameworks-of-the-future-flex-gwt-grail-and-rails-525747?src=embed&quot; title=&quot;View Web Frameworks of the Future: Flex, GWT, Grail, and Rails on SlideShare&quot;&gt;view on slideshare&lt;/a&gt; | 
&lt;a href=&quot;http://www.slideshare.net/mraible/web-frameworks-of-the-future-flex-gwt-grail-and-rails-525747/download&quot;&gt;download&lt;/a&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/running_spring_mvc_web_applications</id>
        <title type="html">Running Spring MVC Web Applications in OSGi</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/running_spring_mvc_web_applications"/>
        <published>2008-04-30T00:42:34-06:00</published>
        <updated>2008-04-30T06:51:04-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springmvc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="osgi" scheme="http://roller.apache.org/ns/tags/" />
        <category term="equinox" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">For the past couple of weeks, I&apos;ve been developing a web application that deploys into an OSGi container (Equinox) and uses Spring DM&apos;s &lt;a href=&quot;http://static.springframework.org/osgi/docs/1.1.0-m2/reference/html/web.html#web:spring-mvc&quot;&gt;Spring MVC support&lt;/a&gt;. The first thing I discovered was that Spring MVC&apos;s annotations weren&apos;t supported in the M1 release. This was apparently caused by a &lt;a href=&quot;http://groups.google.com/group/spring-osgi/browse_thread/thread/cf1fa802f846feac/b0f7483ea63b8f8e?lnk=gst#b0f7483ea63b8f8e&quot;&gt;bug &lt;/a&gt; in Spring 2.5.3 and not Spring DM. Since Spring DM 1.1.0 M2 was released with Spring 2.5.4 &lt;a href=&quot;http://www.springframework.org/node/646&quot;&gt;today&lt;/a&gt;, I believe this is fixed now.
&lt;/p&gt;
&lt;p&gt;The story below is about my experience getting a Spring MVC application up and running in Equinox 3.2.2, Jetty 6.1.9 and Spring DM 1.1.0 M2 SNAPSHOT (from last week). If you want to read more about why Spring MVC + OSGi is cool, see Costin Leau&apos;s &lt;a href=&quot;http://blog.springsource.com/main/2008/04/29/web-applications-and-osgi/&quot;&gt;Web Applications and OSGi&lt;/a&gt; article.&lt;/p&gt;
&lt;p&gt;To get a simple &quot;Hello World&quot; Spring MVC application working in OSGi is pretty easy. The hard part is setting up a container with all the Spring and Jetty bundles installed and started. I imagine &lt;a href=&quot;http://www.infoq.com/news/2008/04/springsource-app-platform&quot;&gt;SSAP&lt;/a&gt; might solve this. Luckily for me, this was done by another member of my team.&lt;/p&gt;
&lt;p&gt;After you&apos;ve done this, it&apos;s simply a matter of creating a MANIFEST.MF for your WAR that contains the proper information for OSGi to recognize. Below is the one that I used when I first tried to get my application working. 
&lt;/p&gt;
&lt;pre&gt;
Manifest-Version: 1
Bundle-ManifestVersion: 2
Spring-DM-Version: 1.1.0-m2-SNAPSHOT
Spring-Version: 2.5.2
Bundle-Name: Simple OSGi War
Bundle-SymbolicName: myapp
Bundle-Classpath: .,WEB-INF/classes,WEB-INF/lib/freemarker-2.3.12.jar,
 WEB-INF/lib/sitemesh-2.3.jar,WEB-INF/lib/urlrewritefilter-3.0.4.jar,
 WEB-INF/lib/spring-beans-2.5.2.jar,WEB-INF/lib/spring-context-2.5.2.jar,
 WEB-INF/lib/spring-context-support-2.5.2.jar,WEB-INF/lib/spring-core-2.5.2.jar,
 WEB-INF/lib/spring-web-2.5.2.jar,WEB-INF/lib/spring-webmvc-2.5.2.jar 
Import-Package: javax.servlet,javax.servlet.http,javax.servlet.resources,javax.swing.tree,
 javax.naming,org.w3c.dom,org.apache.commons.logging,javax.xml.parsers;resolution:=optional,
 org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional
&lt;/pre&gt;
&lt;p class=&quot;smokey&quot;&gt;Ideally, you could generate this MANIFEST.MF using the &lt;a href=&quot;http://felix.apache.org/site/maven-bundle-plugin-bnd.html&quot;&gt;maven-bundle-plugin&lt;/a&gt;. However, it &lt;a href=&quot;http://www.nabble.com/Is-it-possible-to-use-the-maven-bundle-plugin-on-a-WAR-project--ts16763483.html&quot;&gt;doesn&apos;t support WARs&lt;/a&gt; in its 1.4.0 release.&lt;/p&gt;

&lt;p&gt;You can see this is an application that uses Spring MVC, FreeMarker, SiteMesh and the URLRewriteFilter. You should be able to &lt;a href=&quot;http://static.raibledesigns.com/downloads/myapp-noosgi.zip&quot;&gt;download it&lt;/a&gt;, unzip it, run &quot;mvn package&quot; and install it into Equinox using &quot;install file://&amp;lt;path to war&gt;&quot;.&lt;/p&gt;
&lt;p&gt;That&apos;s all fine and dandy, but doesn&apos;t give you any benefits of OSGi. This setup works great until you try to import OSGi services using a context file with an &lt;strong&gt;&amp;lt;osgi:reference&gt;&lt;/strong&gt; element. After adding such a reference, it&apos;s likely you&apos;ll get the following error:
&lt;/p&gt;
&lt;pre&gt;
SEVERE: Context initialization failed
org.springframework.beans.factory.parsing.BeanDefinitionParsingException:
Configuration problem: Unable to locate Spring NamespaceHandler for
XML schema namespace [http://www.springframework.org/schema/osgi]
&lt;/pre&gt;
&lt;p&gt;To fix this, add the following to your web.xml (if you&apos;re using ContextLoaderListener, as an &amp;lt;init-parameter&amp;gt; on DispatcherServlet if you&apos;re not):&lt;/p&gt;
&lt;pre&gt;
  &amp;lt;context-param&amp;gt;
    &amp;lt;param-name&amp;gt;contextClass&amp;lt;/param-name&amp;gt;
    &amp;lt;param-value&amp;gt;org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext&amp;lt;/param-value&amp;gt;
  &amp;lt;/context-param&amp;gt;
&lt;/pre&gt;
&lt;p&gt;After doing this, you might get the following error on startup:&lt;/p&gt;
&lt;pre&gt;
SEVERE: Context initialization failed
org.springframework.context.ApplicationContextException: Custom
context class [org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext]
is not of type [org.springframework.web.context.ConfigurableWebApplicationContext] 
&lt;/pre&gt;
&lt;p&gt;To fix this, I change from referencing the Spring JARs in WEB-INF/lib
to importing the packages for Spring (which were already installed in my
Equinox container).
&lt;/p&gt;
&lt;pre&gt;
Bundle-Classpath: .,WEB-INF/classes,WEB-INF/lib/freemarker-2.3.12.jar,
 WEB-INF/lib/sitemesh-2.3.jar,WEB-INF/lib/urlrewritefilter-3.0.4.jar
Import-Package:
javax.servlet,javax.servlet.http,javax.servlet.resources,javax.swing.tree,
 javax.naming,org.w3c.dom,org.apache.commons.logging,javax.xml.parsers;resolution:=optional,
 org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,
 org.springframework.osgi.web.context.support,
 org.springframework.context.support,
 org.springframework.web.context,
 org.springframework.web.context.support,
 org.springframework.web.servlet,
 org.springframework.web.servlet.mvc,
 org.springframework.web.servlet.mvc.support,
 org.springframework.web.servlet.view,
 org.springframework.ui,
 org.springframework.web.servlet.view.freemarker 
&lt;/pre&gt;
&lt;p&gt;After rebuilding my WAR and reloading the bundle in Equinox, I was confronted with the following error message:&lt;/p&gt;
&lt;pre&gt;
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name &apos;freemarkerConfig&apos; defined in ServletContext
resource [/WEB-INF/myapp-servlet.xml]: Instantiation of bean failed;
nested exception is java.lang.NoClassDefFoundError:
freemarker/cache/TemplateLoader
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:851) 
&lt;/pre&gt;
&lt;p&gt;As far as I can tell, this is because the version of Spring MVC installed in Equinox
cannot resolve the FreeMarker JAR in my WEB-INF/lib directory.
&lt;/p&gt;
&lt;p&gt;To prove I wasn&apos;t going insane, I commented out my &quot;freemarkerConfig&quot; and &quot;viewResolver&quot; beans in myapp-servlet.xml and changed to a regular ol&apos; InternalResourceViewResolver:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;bean id=&quot;viewResolver&quot; class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&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;
&lt;/pre&gt;
&lt;p&gt;This worked and I was able to successfully see &quot;Hello World&quot; from a JSP in my browser. FreeMarker/SiteMesh worked too, but FreeMarker didn&apos;t work as a View for Spring MVC.
&lt;/p&gt;
&lt;p&gt;
To attempt to solve this, I create a &lt;a href=&quot;http://static.raibledesigns.com/downloads/freemarker-2.3.12-bundle.jar&quot;&gt;bundle for FreeMarker&lt;/a&gt; using &quot;java -jar
bnd-0.0.249.jar wrap freemarker-2.3.12.jar&quot; and installed it in Equinox.
I then change my MANIFEST.MF to use FreeMarker imports instead of
referencing the JAR in WEB-INF/lib.
&lt;/p&gt;
&lt;pre&gt;
Bundle-Classpath:
.,WEB-INF/classes,WEB-INF/lib/sitemesh-2.3.jar,WEB-INF/lib/urlrewritefilter-3.0.4.jar
Import-Package:
javax.servlet,javax.servlet.http,javax.servlet.resources,javax.swing.tree,
 javax.naming,org.w3c.dom,org.apache.commons.logging,javax.xml.parsers;resolution:=optional,
 org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,
 org.springframework.osgi.web.context.support,
 org.springframework.context.support,
 org.springframework.web.context,
 org.springframework.web.context.support,
 org.springframework.web.servlet,
 org.springframework.web.servlet.mvc,
 org.springframework.web.servlet.mvc.support,
 org.springframework.web.servlet.view,
 org.springframework.ui,
 org.springframework.web.servlet.view.freemarker,
 freemarker.cache,freemarker.core,freemarker.template,freemarker.ext.servlet 
&lt;/pre&gt;
&lt;p&gt;Unfortunately, this still doesn&apos;t work and I still haven&apos;t been able to get FreeMarker to work with Spring MVC in OSGi. The crazy thing is I actually solved this at one point a week ago. Shortly after, I rebuilt Equinox from scratch and I&apos;m been banging my head against the wall over this issue ever since. Last week, I entered an &lt;a href=&quot;http://jira.springframework.org/browse/OSGI-461&quot;&gt;issue in Spring&apos;s JIRA&lt;/a&gt;, but thought I&apos;d fixed it a few hours later.
&lt;/p&gt;
&lt;p&gt;
I&apos;ve uploaded the final project that&apos;s not working to the following URL:&lt;/p&gt;
&lt;p style=&quot;padding-left: 15px&quot;&gt;&lt;a href=&quot;http://static.raibledesigns.com/downloads/myapp-osgi.zip&quot;&gt;http://static.raibledesigns.com/downloads/myapp-osgi.zip&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;If you&apos;d like to see this project work with Spring MVC + JSP, simply modify myapp-servlet.xml to remove the FreeMarker references and use the InternalResourceViewResolver instead.&lt;/p&gt;
&lt;p&gt;I hope Spring DM + Spring MVC supports more than just JSP as a view technology. I hope I can&apos;t get FreeMarker working because of some oversight on my part. 
If you have a Spring DM + Spring MVC application working with Velocity or FreeMarker, I&apos;d love to hear about it.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/upgrading_to_spring_security_2</id>
        <title type="html">Upgrading to Spring Security 2.0</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/upgrading_to_spring_security_2"/>
        <published>2008-04-17T02:45:47-06:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springsecurity" scheme="http://roller.apache.org/ns/tags/" />
        <category term="acegi" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This evening I spent a few hours and upgraded &lt;a href=&quot;http://appfuse.org&quot;&gt;AppFuse&lt;/a&gt; to use &lt;span style=&quot;text-decoration: line-through&quot;&gt;Acegi&lt;/span&gt; &lt;a href=&quot;http://www.springframework.org/node/627&quot;&gt;Spring Security 2.0&lt;/a&gt;. The upgrade was fairly straightforward:
&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;%s/org.acegisecurity/org.springframework.security/g&lt;/li&gt;
&lt;li&gt;Upgraded dependencies (exclusions are necessary if you&apos;re using Spring 2.5.x and don&apos;t want 2.0.x dependencies pulled in):
&lt;pre style=&quot;margin-top: 10px&quot;&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-core-tiger&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${spring.security.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-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-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&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-security-taglibs&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${spring.security.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;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;&lt;li&gt;Changed taglib prefix from &quot;authz&quot; to &quot;security&quot; and change the associated taglib declaration to:
&lt;pre style=&quot;margin-top: 10px&quot;&gt;
&amp;lt;%@ taglib uri=&quot;http://www.springframework.org/security/tags&quot; 
    prefix=&quot;security&quot; %&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;&lt;li&gt;In web.xml, I changed &amp;lt;filter-class&amp;gt; to &lt;em&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/em&gt;. Since I didn&apos;t name my filter &lt;em&gt;springSecurityFilterChain&lt;/em&gt;, I also had to add the following &amp;lt;init-param&amp;gt;:
&lt;pre style=&quot;margin-top: 10px&quot;&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;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Lastly, I modified security.xml to use the &lt;a href=&quot;http://static.springframework.org/spring-security/site/reference/html/ns-config.html&quot;&gt;new syntax&lt;/a&gt;. AppFuse&apos;s security.xml went from &lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/web/common/src/main/webapp/WEB-INF/security.xml?r1=3044&amp;amp;r2=3089&quot;&gt;175 lines to 33&lt;/a&gt; with the new security namespace configuration!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&apos;s hard to believe I first looked at Acegi almost &lt;a href=&quot;http://sourceforge.net/mailarchive/message.php?msg_name=E1BJ4Z3-0001A8-Ic%40sc8-sf-mx1.sourceforge.net&quot;&gt;4 years ago&lt;/a&gt;. At that time, I said it contained too much XML for my needs. Ben&apos;s reaction:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
Seriously, the &quot;whole lotta XML&quot; gives you exponentially more power and
flexibility than a method such as this could ever hope to provide you.
&lt;/p&gt;
&lt;p&gt;It&apos;s nice to see that Spring Security 2.0 gives you exponentially more power and flexibility without all the XML. &lt;em&gt;Thanks guys!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S. You can also view the &lt;a href=&quot;http://source.appfuse.org/changelog/appfuse/?cs=3089&quot;&gt;full changelog&lt;/a&gt; for this upgrade.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; If you&apos;re using &amp;lt;authz:authentication property=&quot;fullName&quot;/&amp;gt; in your JSPs, you&apos;ll need to change it to &amp;lt;security:authentication property=&quot;principal.fullName&quot;/&amp;gt;.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/selenium_user_meetup_videos_posted</id>
        <title type="html">Selenium User Meetup Videos Posted</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/selenium_user_meetup_videos_posted"/>
        <published>2008-03-05T21:19:23-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Open Source" label="Open Source" />
        <category term="meetup" scheme="http://roller.apache.org/ns/tags/" />
        <category term="selenium" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Videos of last week&apos;s &lt;a href=&quot;http://raibledesigns.com/rd/entry/last_night_s_selenium_users&quot;&gt;Selenium User Meetup&lt;/a&gt; have been posted on YouTube. You can watch them below or click on the video to watch it on YouTube. &lt;em&gt;Enjoy!&lt;/em&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;strong style=&quot;float: left; margin-left: 50px&quot;&gt;Lightning Talks&lt;/strong&gt;&lt;br/&gt;
&lt;object width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/EDb8yOM3Vpw&quot;&gt;&lt;/param&gt;&lt;param name=&quot;wmode&quot; value=&quot;transparent&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/EDb8yOM3Vpw&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;strong style=&quot;float: left; margin-left: 50px&quot;&gt;Q and A Session&lt;/strong&gt;&lt;br/&gt;
&lt;object width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/4y-3bllkkPc&quot;&gt;&lt;/param&gt;&lt;param name=&quot;wmode&quot; value=&quot;transparent&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;//www.youtube.com/v/4y-3bllkkPc&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/the_national_western_stock_show</id>
        <title type="html">The National Western Stock Show</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/the_national_western_stock_show"/>
        <published>2008-01-24T12:24:23-07:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/General" label="General" />
        <category term="rodeo" scheme="http://roller.apache.org/ns/tags/" />
        <category term="nationalwestern" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Last night, a friend and I went to the Rodeo at the &lt;a href=&quot;http://www.nationalwestern.com/nwss/home/index.asp&quot;&gt;National Western Stock Show&lt;/a&gt;. We had really nice seats (thanks to Cletus from Nebraska) and had a great time watching the Bareback Ridin&apos;, Bull Fightin&apos;, Bull Ridin&apos;, Mutton Bustin&apos; and Barrel Racin&apos;. The highlights were the bull fighting (the bulls almost always won) and the &lt;a href=&quot;http://www.nationalwestern.com/nwss/home/index.asp?rpg=/nwss/rodeo/special/mutton.asp&quot;&gt;Mutton Bustin&apos;&lt;/a&gt;. This is where they plop little kids on the back of a sheep and they hang on for deer life. I shot a video for your entertainment.
&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;
&lt;object width=&quot;425&quot; height=&quot;350&quot;&gt; &lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/UvW-D7_EN8s&quot;&gt; &lt;/param&gt; &lt;embed src=&quot;//www.youtube.com/v/UvW-D7_EN8s&quot; type=&quot;application/x-shockwave-flash&quot; width=&quot;425&quot; height=&quot;350&quot;&gt; &lt;/embed&gt; &lt;/object&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/mraible/sets/72157603786737238/&quot;&gt;Click here&lt;/a&gt; for more pictures from the event. Sorry about the picture blurriness, the high action and bad results from my camera made me realize I might need to upgrade.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/go_light_with_apache_struts</id>
        <title type="html">Go Light with Apache Struts 2 and REST by Don Brown</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/go_light_with_apache_struts"/>
        <published>2007-11-15T18:12:58-07:00</published>
        <updated>2007-11-16T01:12:58-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="rest" scheme="http://roller.apache.org/ns/tags/" />
        <category term="donbrown" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">After attending &lt;a href=&quot;http://raibledesigns.com/rd/entry/building_scalable_reliable_and_secure&quot;&gt;Dan&apos;s talk on REST&lt;/a&gt;, I stayed in the same room and listened to Don Brown talk about &lt;a href=&quot;http://us.apachecon.com/us2007/program/talk/2058&quot;&gt;Struts 2&apos;s support for building RESTful applications&lt;/a&gt;. Below are my notes from the event.
&lt;/p&gt;
&lt;p&gt;
&lt;p&gt;What is wrong with today&apos;s web applications? You&apos;re using a modern web framework and you&apos;ve cleanly separated your presentation and business logic. The biggest problem in modern web applications is Confusing URLs.
&lt;/p&gt;
&lt;p&gt;
A URL should be a resource indicator - not a method invocation. Often, web applications have little or no caching. People use GET to perform data manipulation and POST may or may not change state (especially with JSF). Another big issue with modern web frameworks is there&apos;s too many abstraction layers that hide HTTP headers and it&apos;s difficult to manipulate them.
&lt;/p&gt;
&lt;p&gt;
Today&apos;s applications are &quot;information silos&quot;. There&apos;s a lot of information in your applications, but it&apos;s all buried in HTML, JavaScript and CSS. There&apos;s no way to get this information out of your application unless you explicitly expose it.
&lt;/p&gt;
&lt;p&gt;
The answer to many of these problem is REST. It&apos;s the Way of the Web. To solve the information silo problem, you can create a single interface that has multiple representation of the same resource. There&apos;s one URI for all types of resources - be it XML, JSON or HTML. How does this work w/o modifying the URL? You modify the URL&apos;s extension.
&lt;/p&gt;
&lt;p&gt;
Struts 2 has a couple of plugins that make developing RESTful services easier. The first is the Codebehind plugin and the 2nd is the REST plugin. Don is doing a demo with the REST plugin and shows that there&apos;s no Struts configuration files needed (no struts.xml and no struts.properties). The only thing that&apos;s necessary is to specify an &quot;actionPackages&quot; init-param on the DispatcherFilter in web.xml. This activates the Codebehind plugin that uses conventions to determine the view template&apos;s path.
&lt;/p&gt;
&lt;p&gt;
In Don&apos;s demo, he&apos;s creating an &quot;OrdersController&quot; that implements ModelDriven. After implementing a setId() method (to set the id from the request parameters), a getModel() method (to return the Order object) and implementing a show() method that returns HttpHeaders, Don starts up his server and shows that http://localhost:8080/order/5 returns an HTML page. Changing the URL to end in /5.json returns JSON, /5.xml returns XML.
&lt;/p&gt;
&lt;pre&gt;
public HttpHeaders create() {
    service.save(order);
    return new DefaultHttpHeaders(&quot;success&quot;).setLocationId(order.getId());
}
&lt;/pre&gt;
&lt;p&gt;
The &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/2691&quot;&gt;Poster Plugin for Firefox&lt;/a&gt; is great when you&apos;re working with REST services. Don used this plugin to show us that it&apos;s possible to post to JSON and get back JSON results. His demo was impressive, especially the fact that there was no XML configuration required for Struts. I also like how the DefaultHttpHeaders class allows you to manipulate headers in a type-safe manner. 
&lt;/p&gt;
&lt;p&gt;
To use the REST plugin, you&apos;ll want to use Struts 2.1. If you&apos;re using Maven, all you need to depend on is struts-rest-plugin. The struts-codebehind-plugin (as well as struts-core) will be pulled in by transitive dependencies.
&lt;/p&gt;
&lt;p&gt;
One disadvantage of REST vs. WS-* is you can&apos;t generate client code from a WSDL. You&apos;ll have to write your client by hand. However, one advantage of REST is there&apos;s already lots of clients - your browser, curl, etc.
&lt;/p&gt;
&lt;p&gt;
The Struts REST Plugin hasn&apos;t been officially released, but hopefully will be in Struts 2.1.1. You can checkout the code from SVN using the URL below. The documentation is located &lt;a href=&quot;http://struts.apache.org/2.x/docs/rest-plugin.html&quot;&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;margin-left: 10px&quot;&gt;
&lt;a href=&quot;http://svn.apache.org/repos/asf/struts/struts2/trunk/plugins/rest/&quot;&gt;http://svn.apache.org/repos/asf/struts/struts2/trunk/plugins/rest&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Great talk Don - and excellent work on the REST plugin for Struts. I can&apos;t wait to try it out.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/integrating_struts_2_jsf_facelets</id>
        <title type="html">Integrating Struts 2 + JSF + Facelets</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/integrating_struts_2_jsf_facelets"/>
        <published>2007-07-26T12:13:59-06:00</published>
        <updated>2007-07-27T19:16:18-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="facelets" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsf" scheme="http://roller.apache.org/ns/tags/" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">What if you didn&apos;t have to choose between a request-based framework and a component-based framework? What if you could use them together and use request-based for some pages and component-based for others? This is the functionality that the &lt;a href=&quot;http://struts.apache.org/2.x/docs/jsf-plugin.html&quot;&gt;Struts 2 JSF Plugin&lt;/a&gt; provides. 
&lt;/p&gt;
&lt;blockquote style=&quot;background: #FAFAFA&quot;&gt;&lt;em&gt;To be fair, the JSF-Spring project says it does the same thing for Spring MVC + JSF, but &lt;a href=&quot;http://jsf-spring.sourceforge.net/reference/ch04.html&quot;&gt;there doesn&apos;t appear to be any documentation&lt;/a&gt;.&lt;/em&gt;&lt;/blockquote&gt;
&lt;p&gt;I did some prototyping of Struts 2 + JSF and discovered that it does indeed work. I also discovered that there&apos;s no documentation on integrating it with Facelets. Luckily, it&apos;s pretty easy to do - hence my reason for writing this entry. You might ask why I want to use Facelets when JSF 1.2 supports JSP fairly well? My reason is because JSP 2.1 hijacks #{}, which Struts 2&apos;s OGNL uses for some expressions. Because of this, I want to be able to run on a JSP 2.0 container until a workaround comes along. Sun&apos;s JSF 1.2 RI can run on a JSP 2.0 container, while MyFaces 2.1 cannot (at least &lt;a href=&quot;http://raibledesigns.com/rd/entry/thoughts_on_myfaces_1_2&quot;&gt;in my experience&lt;/a&gt;).
&lt;/p&gt;
&lt;p&gt;There&apos;s two ways to get Struts 2 + JSF + Facelets working:&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;Create a WEB-INF/faces-config.xml file and override the default view-handler:
&lt;pre style=&quot;margin-top: 10px&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;faces-config 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-facesconfig_1_2.xsd&quot;
    version=&quot;1.2&quot;&amp;gt;

    &amp;lt;application&amp;gt;
        &amp;lt;view-handler&amp;gt;com.sun.facelets.FaceletViewHandler&amp;lt;/view-handler&amp;gt;
    &amp;lt;/application&amp;gt;
&amp;lt;/faces-config&amp;gt; 
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;The 2nd way is to use Ajax4JSF and declare the view-handler in your web.xml (allowing you to get rid of faces-config.xml):
&lt;pre style=&quot;margin-top: 10px&quot;&gt;
&amp;lt;context-param&amp;gt;
    &amp;lt;param-name&amp;gt;org.ajax4jsf.VIEW_HANDLERS&amp;lt;/param-name&amp;gt;
    &amp;lt;param-value&amp;gt;com.sun.facelets.FaceletViewHandler&amp;lt;/param-value&amp;gt;
&amp;lt;/context-param&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;background: #FAFAFA&quot;&gt;&lt;i&gt;NOTE: You have to use 2nd method if you want to use Ajax4JSF. It &lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_facelets_and_ajax4jsf_with&quot;&gt;won&apos;t read the view-handler from faces-config.xml&lt;/a&gt;.&lt;/i&gt;&lt;/blockquote&gt;
&lt;p&gt;If you&apos;re using SiteMesh, you may have to add another &amp;lt;parser&gt; element to your sitemesh.xml to get Facelets pages decorated:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;parser content-type=&quot;application/xhtml+xml&quot;
    class=&quot;com.opensymphony.module.sitemesh.parser.HTMLPageParser&quot;/&amp;gt; 
&lt;/pre&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;http://www.nabble.com/forum/ViewPost.jtp?post=11802409&amp;framed=y&quot;&gt;Laurie Harper&lt;/a&gt; for his assistance figuring this stuff out.
&lt;/p&gt;
&lt;p&gt;
Now you might ask - why would you want to do this? For one, Struts 2 has a better navigation model (IMO) than JSF. Also, if developers want to use JSF and think it&apos;s a better way for a certain module - let them go to it!</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/java_web_frameworks_and_xss</id>
        <title type="html">Java Web Frameworks and XSS</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/java_web_frameworks_and_xss"/>
        <published>2007-07-19T10:16:15-06:00</published>
        <updated>2012-11-08T14:40:17-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="xss" scheme="http://roller.apache.org/ns/tags/" />
        <category term="webframeworks" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">In preparation for my &lt;a href=&quot;http://conferences.oreillynet.com/cs/os2007/view/e_sess/12341&quot;&gt;talk at OSCON next week&lt;/a&gt;, I&apos;ve been doing some research on &lt;a href=&quot;http://en.wikipedia.org/wiki/Cross-site_scripting&quot;&gt;cross-site scripting&lt;/a&gt; and how good Java web frameworks handle it. I&apos;m disappointed to report that the handling of XSS in Java web frameworks is abysmal. First of all, the 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;
With JSP 2.0 you can use the following to emit the description of a &quot;todo&quot; item:&lt;br/&gt;

&lt;code&gt;
${todo.description}
&lt;/code&gt;

&lt;br/&gt;That&apos;s pretty nice. What happens when someone has entered a description like this?&lt;br/&gt;

&lt;code&gt;
&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;alert(&apos;F#$@ you!&apos;);&amp;lt;/script&amp;gt;
&lt;/code&gt;

&lt;br/&gt;Well, it executes the JavaScript and pops up a nice little message to you. &lt;br/&gt;
...&lt;br/&gt;
My question is this: &lt;strong&gt;Why in the world did the expert group on the JSP 2.0 JSR decide to make not escaping XML content the default for EL expressions&lt;/strong&gt;, when they made the opposite decision for &lt;code&gt;c:out&lt;/code&gt;?
&lt;/p&gt;
&lt;p&gt;(Emphasis mine) If a company/developer wants to make sure their JSP-based code is not susceptible to XSS, they have two choices (as I see it): 
&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;Do lots of code review to make sure &amp;lt;c:out&gt; is used instead of ${}.&lt;/li&gt;
&lt;li&gt;Hack the jsp-compiler/el-engine to escape XML by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The good news is #2 doesn&apos;t seem to be that hard. I pulled down commons-el yesterday, added a hack to escape XML, re-jarred and put it in Tomcat 5.0.25&apos;s classpath. This actually worked and I was impressed it was so easy. However, when I looked at Tomcat 6, commons-el is no longer used and now there&apos;s a &quot;jasper-el.jar&quot; in the lib directory. I don&apos;t mind modifying another library, but what&apos;s the difference between jasper-el and commons-el? 
&lt;br/&gt;&lt;br/&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;br/&gt;&lt;br/&gt;
On a related note, there&apos;s a couple of web frameworks that I&apos;ve found to be susceptible to XSS: namely Spring MVC and Struts 2. For Spring MVC, its &lt;a href=&quot;http://shh.thathost.com/secadv/spring-form-xss/&quot;&gt;&amp;lt;form:input&gt; and &amp;lt;form:errors&gt; tags are vulnerable&lt;/a&gt;. For Struts 2, &lt;a href=&quot;http://javaswamy.blogspot.com/2007/07/has-struts2-lost-it.html&quot;&gt;OGNL expressions are evaluated&lt;/a&gt;, which is way worse than XSS and actually allows you to shutdown the JVM by putting &lt;code&gt;%{@java.lang.System@exit(0)}&quot;&lt;/code&gt; in a text field.
&lt;br/&gt;&lt;br/&gt;
Even though it was surprising for me to see the issues with Struts 2 and Spring MVC, I&apos;m somewhat glad they exist. If I hadn&apos;t discovered them, I might blissfully think that Java web frameworks aren&apos;t susceptible to XSS. However, it appears they&apos;re not only susceptible, but no one is really thinking about XSS when developing these framework. To further prove that theory, the Spring MVC and Struts 2 teams are aware of these issues, have been for quite some time - yet they&apos;ve done nothing in the form of releasing upgrades or patches. 
&lt;br/&gt;&lt;br/&gt;
Seems kinda strange doesn&apos;t it? 

</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/zero_configuration_in_struts_2</id>
        <title type="html">Zero Configuration in Struts 2</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/zero_configuration_in_struts_2"/>
        <published>2007-03-07T17:19:18-07:00</published>
        <updated>2007-03-08T00:20:32-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="struts2" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Struts 2 has a nifty &lt;a href=&quot;http://struts.apache.org/2.0.6/docs/zero-configuration.html&quot;&gt;zero configuration&lt;/a&gt; feature. However, it&apos;s only useful for registering actions, not for automatically registering results. In other words, you still have to use an @Result annotation to tell your action what page to dispatch to. To use default view names instead of requiring @Result, you can use the &lt;a href=&quot;http://struts.apache.org/2.0.6/docs/codebehind-plugin.html&quot;&gt;Codebehind Plugin&lt;/a&gt;. Also, did you know Struts 2 will autowire your Spring dependencies?  It&apos;s pretty slick.
&lt;br/&gt;&lt;br/&gt;
What does this all mean?  It means you can write your Struts 2 application &lt;em&gt;without writing any XML&lt;/em&gt;. Of course, you can still use XML to tweak behavior, but with these plugins enabled, you won&apos;t have to.
&lt;blockquote style=&quot;font-style: italic&quot;&gt;
IMO, these plugins should be combined into a single zero configuration feature.
&lt;/blockquote&gt;
&lt;p&gt;Here&apos;s how you can enable Struts 2&apos;s Zero Configuration feature in AppFuse 2.0:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add a &lt;strong&gt;packageNames&lt;/strong&gt; parameter to the &quot;struts&quot; filter in your web.xml:&lt;br/&gt;
&lt;pre style=&quot;margin-top: 10px&quot;&gt;
&amp;lt;filter&amp;gt;
    &amp;lt;filter-name&amp;gt;struts&amp;lt;/filter-name&amp;gt;
    &amp;lt;filter-class&amp;gt;org.apache.struts2.dispatcher.FilterDispatcher&amp;lt;/filter-class&amp;gt;
    &amp;lt;init-param&amp;gt;
        &amp;lt;param-name&amp;gt;actionPackages&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;com.company.newapp.webapp.action&amp;lt;/param-value&amp;gt;
    &amp;lt;/init-param&amp;gt;
&amp;lt;/filter&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Add the Codebehind Plugin as a dependency in your pom.xml:
&lt;pre style=&quot;margin-top: 10px&quot;&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.struts&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;struts2-codebehind-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.0.6&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;struts.codebehind.pathPrefix&lt;/strong&gt; constant in struts.xml for your default pages directory:
&lt;pre style=&quot;margin-top: 10px&quot;&gt;
&amp;lt;constant name=&quot;struts.codebehind.pathPrefix&quot; value=&quot;/WEB-INF/pages/&quot;/&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&apos;s it - now you can code away without configuring anything!&lt;/p&gt;
&lt;p&gt;How does this compare to other web frameworks in AppFuse?  Tapestry has a similar feature, but Spring MVC and JSF don&apos;t. Spring MVC still requires you create a bean definition for Controllers and JSF requires you write a chunk of XML for each managed bean.  Of course, if you know how to do something similar with Spring MVC or JSF, please let me know.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/integrating_facelets_and_ajax4jsf_with</id>
        <title type="html">Integrating Facelets and Ajax4JSF with MyFaces</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/integrating_facelets_and_ajax4jsf_with"/>
        <published>2006-10-12T02:41:24-06:00</published>
        <updated>2007-02-10T20:07:57-07:00</updated> 
        <category term="/Java" label="Java" />
        <content type="html">I spent a few hours tonight integrating &lt;a href=&quot;http://facelets.dev.java.net&quot;&gt;Facelets&lt;/a&gt; into an AppFuse-based application. The integrating was fairly easy thanks to the work &lt;a href=&quot;http://www.jroller.com/page/thogau?entry=using_facelets_with_appfuse&quot;&gt;Thomas Gaudin&lt;/a&gt; did back in January. For the most part, it was just a matter of 1) replacing &lt;code style=&quot;background: #ffd&quot;&gt;&amp;lt;fmt:message&amp;gt;&lt;/code&gt; tags with &lt;code style=&quot;background: #ffd&quot;&gt;#{text[&apos;key&apos;]}&lt;/code&gt; tags, 2) replacing the &lt;code style=&quot;background: #ffd&quot;&gt;&amp;lt;%@ include file=&quot;/common/taglibs.jsp&quot;%&gt;&lt;/code&gt; at the top of each page with Facelet&apos;s namespace tags and 3) renaming the pages from *.jsp to *.xhtml. The only thing that tripped me up was I thought the &quot;c&quot; namespace was the same as JTLS&apos;s URI, but it&apos;s actually a whole new URI. Thanks to the Facelets developers for a much-needed fix for JSF.&lt;br/&gt;&lt;br/&gt;
After I got Facelets integrated and working, I dove into integrating &lt;a href=&quot;https://ajax4jsf.dev.java.net/nonav/ajax/ajax-jsf/&quot;&gt;Ajax4JSF&lt;/a&gt;. Two hours later and I have the &lt;a href=&quot;http://livedemo.exadel.com/a4j-simpleRepeatorFacelets/&quot;&gt;simple repeater demo&lt;/a&gt; working.  What took so long? I spent an hour staring at (and googling for) the solution to the following error:&lt;/p&gt;
&lt;pre&gt;
PhaseListenerManager.informPhaseListenersBefore(74) | Exception in PhaseListener RENDER_RESPONSE(6) beforePhase.
java.lang.NullPointerException
        at com.sun.facelets.FaceletViewHandler.writeState(FaceletViewHandler.java:759)
        at org.ajax4jsf.framework.renderer.AjaxRendererUtils.writeState(AjaxRendererUtils.java:850)
        at org.ajax4jsf.framework.renderer.AjaxRendererUtils.encodeAreas(AjaxRendererUtils.java:740)
        at org.ajax4jsf.framework.renderer.AjaxContainerRenderer.encodeAjax(AjaxContainerRenderer.java:128)
        at org.ajax4jsf.ajax.UIAjaxRegion.encodeAjax(UIAjaxRegion.java:210)
&lt;/pre&gt;
&lt;p&gt;The solution turned out to be &lt;strong&gt;&lt;em&gt;removing&lt;/em&gt;&lt;/strong&gt; the FaceletsViewHandler from faces-config.xml:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;view-handler&gt;com.sun.facelets.FaceletViewHandler&amp;lt;/view-handler&gt;
&lt;/pre&gt;
&lt;p&gt;Also, it seems the following is required in web.xml:&lt;/p&gt;
&lt;pre&gt;
    &amp;lt;context-param&amp;gt;
        &amp;lt;param-name&amp;gt;org.ajax4jsf.VIEW_HANDLERS&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;com.sun.facelets.FaceletViewHandler&amp;lt;/param-value&amp;gt;
    &amp;lt;/context-param&amp;gt;
&lt;/pre&gt;&lt;p&gt;Hopefully this helps others googling for the exception above.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/dependency_injection_with_sitemesh</id>
        <title type="html">Dependency Injection with SiteMesh</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/dependency_injection_with_sitemesh"/>
        <published>2006-02-16T09:57:23-07:00</published>
        <updated>2012-11-08T14:45:51-07:00</updated> 
        <category term="/Java" label="Java" />
        <content type="html">Let me start off by saying I think that both &lt;a href=&quot;http://opensymphony.com/sitemesh&quot;&gt;SiteMesh&lt;/a&gt; and &lt;a href=&quot;http://struts.apache.org/struts-tiles&quot;&gt;Tiles&lt;/a&gt; are great frameworks.  I was a long time user and fan of Tiles, and I think it&apos;s appropriate for certain situations.  However, I&apos;ve been a heavy user of SiteMesh since it &lt;a href=&quot;http://raibledesigns.com/page/rd?anchor=sitemesh_passed_the_10_minute&quot;&gt;passed the 10 minute test&lt;/a&gt;. While most heavy users of SiteMesh (the &lt;a href=&quot;http://www.atlassian.com/&quot;&gt;Atlassian&lt;/a&gt; guys come to mind) say that it can do everything that Tiles can do, these features are largely undocumented.  This is my attempt to document a cool feature.&lt;br/&gt;&lt;br/&gt;
In a site I recently helped develop, we needed a couple of features:&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;A tabbed menu that highlighted the current tab based on which page you were on.&lt;/li&gt;
&lt;li&gt;A bunch of &quot;panels&quot; on the right sidebar that changed according to the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To make this work, we used the &lt;a href=&quot;http://www.opensymphony.com/sitemesh/api/com/opensymphony/module/sitemesh/HTMLPage.html&quot;&gt;meta tag functionality&lt;/a&gt; that SiteMesh provides.
&lt;/p&gt;
&lt;p class=&quot;quote&quot; style=&quot;font-style: italic&quot;&gt;
Funny side/related note, I just googled for this tag and found &lt;a href=&quot;http://blog.gilluminate.com/?b=20060111103915&quot;&gt;this howto&lt;/a&gt;, which is similar to this one.&lt;/p&gt;
&lt;p&gt;In our pages, we added the meta tags to set the active menu, as well as which panels to show in the sidebar:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;fmt:message key=&quot;authorList.title&quot;/&amp;gt;&amp;lt;/title&amp;gt;
    &amp;lt;meta name=&quot;menu&quot; content=&quot;Authors&quot;/&amp;gt;
    &amp;lt;meta name=&quot;panels&quot; content=&quot;administration,blogs,events&quot;/&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Then, in our decorator, we interpret these separately. First, we used &lt;a href=&quot;http://struts-menu.sf.net&quot;&gt;Struts Menu&lt;/a&gt; (with Velocity) for the navigation system:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;c:set var=&quot;currentMenu&quot; scope=&quot;request&quot;&amp;gt;
    &amp;lt;decorator:getProperty property=&quot;meta.menu&quot;/&amp;gt;
&amp;lt;/c:set&amp;gt;
&amp;lt;c:import url=&quot;/WEB-INF/pages/menu.jsp&quot;&amp;gt;
    &amp;lt;c:param name=&quot;template&quot; value=&quot;/template/menu/tabs.html&quot;/&amp;gt;
&amp;lt;/c:import&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The menu.jsp page takes &quot;template&quot; as a parameter so we display the same menu links using a different Velocity template (for example, links at the bottom of the page).
&lt;/p&gt;
&lt;pre&gt;
&amp;lt;menu:useMenuDisplayer name=&quot;Velocity&quot; config=&quot;${param.template}&quot; permissions=&quot;rolesAdapter&quot;&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Then our tabs.html Velocity template uses the &quot;currentMenu&quot; attribute to determine which menu to highlight.&lt;/p&gt;
&lt;pre&gt;
## displayMenu is defined in WEB-INF/classes/globalMacros.vm
#macro( menuItem $menu $level )
  #set ($title = $displayer.getMessage($menu.title))
  #if ($menu.url)
    #if ($menu.name == $currentMenu)
      &amp;lt;span class=&quot;current&quot;&amp;gt;
    #end
      &amp;lt;a href=&quot;$!menu.url&quot; title=&quot;$title&quot;&amp;gt;&amp;lt;span&amp;gt;$title&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;
    #if ($menu.name == $request.getAttribute(&apos;currentMenu&apos;))
      &amp;lt;/span&amp;gt;
    #end
  #end
#end

#if ($displayer.isAllowed($menu))
    #displayMenu($menu 0)
#end
&lt;/pre&gt;
&lt;p&gt;As far as the panel injection goes, that&apos;s processed using the following logic in our decorator:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;c:set var=&quot;panels&quot;&amp;gt;&amp;lt;decorator:getProperty property=&quot;meta.panels&quot;/&amp;gt;&amp;lt;/c:set&amp;gt;
&amp;lt;!-- No panels set, use default set of panels --&amp;gt;
&amp;lt;c:if test=&quot;${empty panels}&quot;&amp;gt;&amp;lt;c:set var=&quot;panels&quot; value=&quot;different,partners&quot;/&amp;gt;&amp;lt;/c:if&amp;gt;
&amp;lt;c:forEach var=&quot;panel&quot; items=&quot;${panels}&quot;&amp;gt;
    &amp;lt;c:import url=&quot;/WEB-INF/pages/panels/${panel}.jsp&quot;/&amp;gt;
&amp;lt;/c:forEach&amp;gt;    
&lt;/pre&gt;
&lt;p&gt;Since this site used WebWork, the &amp;lt;ww:action&amp;gt; tag made it easy to give each panel independence. That is, each panel could load on its own, supply its own data, and not worry about the data being prepared beforehand. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;%@ include file=&quot;/common/taglibs.jsp&quot;%&amp;gt;

&amp;lt;h2&amp;gt;Author Blogs&amp;lt;/h2&amp;gt;

&amp;lt;ww:action name=&quot;&apos;authors&apos;&quot; id=&quot;authors&quot; namespace=&quot;default&quot;/&amp;gt;

&amp;lt;div class=&quot;item&quot;&amp;gt;
    &amp;lt;ww:iterator value=&quot;#authors.authors&quot; status=&quot;index&quot;&amp;gt;
        &amp;lt;a href=&quot;&amp;lt;ww:property value=&quot;blog.feedUrl&quot;/&amp;gt;&quot;&amp;gt;
            &amp;lt;img src=&quot;${ctxPath}/images/icons/xml.gif&quot; alt=&quot;XML Feed&quot; 
                style=&quot;margin-right: 5px; vertical-align: middle&quot;/&amp;gt;&amp;lt;/a&amp;gt;
        &amp;lt;a href=&quot;&amp;lt;ww:property value=&quot;blog.url&quot;/&amp;gt;&quot;&amp;gt;&amp;lt;ww:property value=&quot;name&quot;/&amp;gt;&amp;lt;/a&amp;gt;
        &amp;lt;br /&amp;gt;
    &amp;lt;/ww:iterator&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Of course, now that you can use Tiles with &lt;a href=&quot;http://raibledesigns.com/page/rd?anchor=how_to_use_tiles_with&quot;&gt;WebWork&lt;/a&gt;, Struts, Spring MVC and JSF - you could use Tiles for the injection and SiteMesh for the decoration.&lt;br /&gt;&lt;br /&gt;
Now if we could just get someone to write a JSF Decorator for SiteMesh, like Erik Hatcher &lt;a href=&quot;http://jira.opensymphony.com/browse/SIM-165&quot;&gt;did for Tapestry&lt;/a&gt;.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/how_to_use_tiles_with</id>
        <title type="html">How to use Tiles with WebWork</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/how_to_use_tiles_with"/>
        <published>2006-02-16T01:08:42-07:00</published>
        <updated>2007-02-10T20:07:57-07:00</updated> 
        <category term="/Java" label="Java" />
        <content type="html">This evening, I created a TilesResult for WebWork that allows you to use Tiles with WebWork. For the following to work in your application, you&apos;ll need a &lt;a href=&quot;http://cvs.apache.org/builds/jakarta-struts/nightly/sandbox/tiles-core/&quot;&gt;nightly build of Tiles&lt;/a&gt;, commons-digester (which Tiles requires) and &lt;a href=&quot;http://jira.opensymphony.com/browse/WW-1185&quot;&gt;this patch&lt;/a&gt; for WebWork. For your convenience, I&apos;ve posted a &lt;a href=&quot;https://equinox.dev.java.net/files/documents/1901/29230/webwork-2.2.2.jar&quot;&gt;patched webwork-2.2.2.jar&lt;/a&gt; (with TilesResult). 
&lt;br /&gt;&lt;br /&gt;
I also posted a &lt;a href=&quot;https://equinox.dev.java.net/files/documents/1901/29229/webwork-tiles.war&quot;&gt;webwork-tiles.war&lt;/a&gt; that you can try and download yourself.  It&apos;s based on &lt;a href=&quot;http://equinox.dev.java.net&quot;&gt;Equinox&lt;/a&gt;, so you will need to setup PostgreSQL and an &quot;equinox&quot; database - or you can just change the database settings in WEB-INF/lib/jdbc.properties.
&lt;br /&gt;&lt;br /&gt;
On to the instructions:&lt;/p&gt;
&lt;p&gt;1. In your web.xml file, you need to add a servlet entry for TilesServlet to load the tiles definitions into the ServletContext.&lt;/p&gt;
&lt;pre&gt;
    &amp;lt;servlet&amp;gt;
        &amp;lt;servlet-name&amp;gt;tiles&amp;lt;/servlet-name&amp;gt;
        &amp;lt;servlet-class&amp;gt;org.apache.tiles.servlets.TilesServlet&amp;lt;/servlet-class&amp;gt;
        &amp;lt;init-param&amp;gt;
            &amp;lt;param-name&amp;gt;definitions-config&amp;lt;/param-name&amp;gt;
            &amp;lt;param-value&amp;gt;/WEB-INF/tiles-config.xml&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&gt;2. In xwork.xml, use type=&quot;tiles&quot; on your &amp;lt;result&amp;gt;.&lt;/p&gt;
&lt;pre&gt;
    &amp;lt;action name=&quot;editUser&quot; class=&quot;userAction&quot; method=&quot;edit&quot;&amp;gt;
        &amp;lt;result name=&quot;success&quot; type=&quot;tiles&quot;&amp;gt;userForm&amp;lt;/result&amp;gt;
        &amp;lt;result name=&quot;input&quot; type=&quot;tiles&quot;&amp;gt;userList&amp;lt;/result&amp;gt;
    &amp;lt;/action&amp;gt;
&lt;/pre&gt;
&lt;p&gt;I&apos;m sure WebWork has a way of making this result type the default, I just haven&apos;t found it yet. 
&lt;br /&gt;&lt;br /&gt;
Hat tip to Spring&apos;s &lt;a href=&quot;http://www.springframework.org/docs/api/org/springframework/web/servlet/view/tiles/TilesView.html&quot;&gt;TilesView&lt;/a&gt;  (&lt;a href=&quot;http://fisheye1.cenqua.com/viewrep/springframework/spring/src/org/springframework/web/servlet/view/tiles/TilesView.java&quot;&gt;source&lt;/a&gt;) for showing how to make this work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; While I&apos;m a happy SiteMesh user, I&apos;ve recently had some clients who were &lt;a href=&quot;http://raibledesigns.com/page/rd?anchor=large_sites_powered_by_java&quot;&gt;more interested in Tiles&lt;/a&gt;. This largely inspired me to see if WebWork + Tiles was possible.&lt;br /&gt;&lt;br /&gt;
&lt;strong&gt;Update 2:&lt;/strong&gt; It looks like &lt;a href=&quot;http://jira.opensymphony.com/browse/WW-1185&quot;&gt;TilesResult will be included in WebWork 2.2.2&lt;/a&gt;. Now if we could just get the Tiles team to cut a release.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/using_dwr_with_spring_and</id>
        <title type="html">Using DWR with Spring and Hibernate</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/using_dwr_with_spring_and"/>
        <published>2005-04-28T14:10:26-06:00</published>
        <updated>2007-02-10T20:07:56-07:00</updated> 
        <category term="/Java" label="Java" />
        <content type="html">For the past few weeks, I&apos;ve been developing an application using Struts, Spring, Hibernate and the &lt;a href=&quot;http://dwr.dev.java.net&quot;&gt;DWR project&lt;/a&gt; for my XmlHttpRequest framework. As you might remember, I used &lt;a href=&quot;http://raibledesigns.com/page/rd?anchor=simplifying_xmlhttprequest_with_json_rpc&quot;&gt;JSON-RPC&lt;/a&gt; for Ajax stuff on my last project.  I found DWR to be much more full-featured and easier to use.  This post is meant to capture some issues I encountered so others won&apos;t have to jump the hurdles that I did. For those of you that get bored quickly, &lt;a href=&quot;http://static.raibledesigns.com/repository/media/dwr.mov&quot;&gt;here&apos;s a movie&lt;/a&gt; (QuickTime) of the app&apos;s Ajax features.
&lt;/p&gt;
&lt;p&gt;
I&apos;ve been using version 0.4 of DWR, and I haven&apos;t had a chance to try out &lt;a href=&quot;http://www.getahead.ltd.uk/blog/joe/2005/04/28/1114692652085.html&quot;&gt;version 0.5&lt;/a&gt;.  When I first started using it, I ran into a &lt;a href=&quot;https://dwr.dev.java.net/servlets/ReadMsg?list=users&amp;amp;msgNo=8&quot;&gt;ThreadDeath problem&lt;/a&gt; that was easily resolved by changing a log.debug message to System.out.println.  I tried to reproduce this issue yesterday and couldn&apos;t, so who knows what that was all about. As far as configuring DWR in your webapp, that&apos;s pretty easy to do, and well documented. See the &lt;a href=&quot;http://www.getahead.ltd.uk/dwr/config-howto.html&quot;&gt;project&apos;s documentation&lt;/a&gt; or &lt;a href=&quot;http://bram.jteam.nl/?p=2&quot;&gt;this Spring MVC HowTo&lt;/a&gt;.  
&lt;/p&gt;
&lt;p&gt;Here are a few things I remember from my development experience.&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;The examples are great, especially &lt;a href=&quot;http://www.getahead.ltd.uk/dwr/demo-table.html&quot;&gt;how to dynamically edit a table&lt;/a&gt;.
&lt;li&gt;When developing, make sure to set the &quot;debug&quot; init-param to &quot;true&quot;.  This allows you to go to http://location:8080/yourapp/dwr and see a screen that allows you to call methods on your exposed classes.&lt;/li&gt;
&lt;li&gt;In WEB-INF/dwr.xml, you need to specify a converter for each POJO you want to expose to your UI via JavaScript. I started out by converting a whole package, but found this to be *extremely* slow (we have a package of around 50 DTOs).  So I changed it to be only the DTOs I was using.  This turned out to take about 30 seconds to do the conversion, and was again unacceptable.  The problem turned out to be that the converter was invoking all the lazy-loaded children for each DTO.  My final solution was to create a NameValue object and only convert that.  Then in my Spring bean, I populate it from DAOs and DTOs.  I&apos;m using Spring&apos;s OSIVF for Hibernate to ensure that DWR doesn&apos;t invoke lazy-loading.&lt;/li&gt;
&lt;li&gt;I had to override a few of DWR&apos;s JavaScript functions in util.js b/c they didn&apos;t work for me. I changed showById() and toggleDisplay() to use style.display=&apos;&apos; instead of style.display=&apos;block&apos; b/c this is what I&apos;ve always used and block doesn&apos;t work that well. I also changed useLoadingMessage() to have a cleaner-looking load message.&lt;/li&gt;
&lt;li&gt;I used the &lt;a href=&quot;http://www.axentric.com/posts/default/7&quot;&gt;Fade Anything Technique&lt;/a&gt; in this project and found that IE likes to have full 6-digit hex values for colors in CSS rules.  The shorter 3-digit hex values simply don&apos;t work in IE.&lt;/li&gt;
&lt;li&gt;Using &quot;test&quot; buttons that only showed up for my username proved to be a great way to test the UI and the Ajax stuff.  These buttons called a number of JavaScript functions to drive the UI and wait between invoking different functions using window.setTimeout.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in all, using DWR was a great experience and I definitely plan to use it more in my projects.  The client loves the app - especially since it&apos;s wicked fast and seems to work like a desktop app.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/use_sitemesh_to_decorate_multiple</id>
        <title type="html">Use SiteMesh to decorate multiple webapps</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/use_sitemesh_to_decorate_multiple"/>
        <published>2005-04-12T10:05:19-06:00</published>
        <updated>2007-02-10T20:07:56-07:00</updated> 
        <category term="/Java" label="Java" />
        <content type="html">Did you know it&apos;s possible to decorate multiple webapps with the same SiteMesh decorator?  I learned how to do this from the &lt;a href=&quot;https://sitemesh.dev.java.net/servlets/ReadMsg?list=users&amp;amp;msgNo=711&quot;&gt;SiteMesh mailing list&lt;/a&gt;:&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;Put sitemesh.jar in your container&apos;s classpath.  You could put it into each webapp&apos;s WEB-INF/lib, but it looks like &lt;a href=&quot;https://sitemesh.dev.java.net/servlets/ReadMsg?list=users&amp;amp;msgNo=721&quot;&gt;there&apos;s problems with that&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create and deploy a webapp that contains the common decorator.&lt;/li&gt;
&lt;li&gt;In each webapp&apos;s decorators.xml, add a &quot;webapp&quot; attribute to point to the webapp you deployed in Step 2.
&lt;pre style=&quot;margin-top: 10px&quot;&gt;
&amp;lt;decorators&amp;gt;
    &amp;lt;!-- load decorator from a different web-app deployed in the server --&amp;gt;
    &amp;lt;decorator name=&quot;main&quot; webapp=&quot;some-other-webapp&quot; 
        page=&quot;/decorators/main.jsp&quot;&amp;gt;
        &amp;lt;pattern&amp;gt;/*&amp;lt;/pattern&amp;gt;
    &amp;lt;/decorator&amp;gt;
&amp;lt;/decorators&amp;gt;
&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Try to do *that* with Tiles. &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/trim_spaces_in_your_jsp</id>
        <title type="html">Trim Spaces in your JSP&apos;s HTML</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/trim_spaces_in_your_jsp"/>
        <published>2005-03-23T22:24:58-07:00</published>
        <updated>2007-08-01T23:15:04-06:00</updated> 
        <category term="/Java" label="Java" />
        <content type="html">One of the annoying things about JSPs is all of the dynamic (non-rendered) parts of the page still produce line breaks.  This means that if you do a view-source, you&apos;ll likely see large blocks of whitespace.
&lt;p&gt;The good news is you can get rid of this whitespace if you&apos;re using Tomcat 5.5.x. Just locate the &quot;jsp&quot; servlet in $CATALINA_HOME/conf/web.xml and add the following &amp;lt;init-param&amp;gt;:&lt;/p&gt;
&lt;/p&gt;
&lt;pre&gt;
    &amp;lt;init-param&amp;gt;
        &amp;lt;param-name&amp;gt;trimSpaces&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;
&lt;/pre&gt;

&lt;p&gt;I tested it and it works great. This begs the question - why isn&apos;t this on by default? Source: &lt;a href=&quot;http://www.mail-archive.com/user%40struts.apache.org/msg23987.html&quot;&gt;Struts Mailing List&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; JSP 2.1 &lt;a href=&quot;http://raibledesigns.com/rd/entry/trim_spaces_in_your_jsp1&quot;&gt;adds the ability to trim whitespaces&lt;/a&gt;.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/ajax_webapps_are_cool_but</id>
        <title type="html">Ajax webapps are cool, but non-javascript versions still needed</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/ajax_webapps_are_cool_but"/>
        <published>2005-03-07T07:42:18-07:00</published>
        <updated>2007-02-10T20:07:56-07:00</updated> 
        <category term="/Java" label="Java" />
        <content type="html">I think we can all probably learn a lesson from Google.  I&apos;ve heard that GMail is the &quot;gold standard&quot; for Ajax applications.  If that&apos;s the case, then you should note that they&apos;ve recently added a &quot;basic HTML&quot; link to the bottom of their pages.  With this link, you can view your e-mail using the old way: Yahoo-style, no-JavaScript-needed.  My guess is they added it because of demand, or simply to compete with other providers who have this feature.  I think it&apos;s a good lesson though: use Ajax features in webapps where appropriate, but don&apos;t make JavaScript necessary to use your app.
&lt;br /&gt;&lt;br /&gt;
A couple of Ajax features I&apos;ve been thinking of developing:
&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;Saving forms with XMLHttpRequest: just display a success message at the top, and switch the &quot;Cancel&quot; button to &quot;Done&quot;.  Since the form&apos;s content doesn&apos;t change, this seems like a reasonable use of the technology.&lt;/li&gt;
&lt;li&gt;Switching out entire &quot;content&quot; &amp;lt;div&amp;gt; elements.  Most of my apps have a &amp;lt;div id=&quot;content&quot;&amp;gt;, so it&apos;d probably pretty easy to just replace that in response to button and link clicks.  Of course, the hard part is having the requested server-side object load the view template, process it, and send back the content.  This is probably more trouble than it&apos;s worth.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/simplifying_xmlhttprequest_with_json_rpc</id>
        <title type="html">Simplifying XmlHttpRequest with JSON-RPC</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/simplifying_xmlhttprequest_with_json_rpc"/>
        <published>2005-03-03T08:44:40-07:00</published>
        <updated>2007-02-10T20:07:56-07:00</updated> 
        <category term="/Java" label="Java" />
        <content type="html">In my day job, we decided to use a little &lt;a href=&quot;http://raibledesigns.com/page/rd?anchor=xmlhttprequest&quot;&gt;XMLHttpRequest&lt;/a&gt; lovin&apos;
    to populate one drop-down from another. This is my review of &lt;a href=&quot;http://oss.metaparadigm.com/jsonrpc/&quot;&gt;JSON-RPC&lt;/a&gt;,
    an open source JavaScript library and servlet for simplifying XMLHttpRequest.
    I considered integrate &lt;a href=&quot;https://dwr.dev.java.net/&quot;&gt;Direct Web Remoting&lt;/a&gt; (DWR)
    as well, but its java.net site was down the day I needed it. I started out
    with JSON-RPC 0.7, which caused some conflicts with Commons Validator client-side
    validation. This was fixed in the 0.8 release. JSON-RPC takes a little more
    setup than I care for, but it&apos;s pretty easy nonetheless:&lt;/p&gt;
&lt;ol style=&quot;margin-left: 25px&quot;&gt;
    &lt;li&gt; Download the 0.8 release from &lt;a href=&quot;http://oss.metaparadigm.com/jsonrpc-dist/json-rpc-java-0.8.tar.gz&quot;&gt;http://oss.metaparadigm.com/jsonrpc-dist/json-rpc-java-0.8.tar.gz&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;Add the JAR to your project and the webapps/jsonrpc/jsonrpc.js to your
        projects&apos; &amp;quot;scripts&amp;quot; folder. Include this file in your &lt;a href=&quot;http://www.opensympony.com/sitemesh&quot;&gt;SiteMesh&lt;/a&gt; decorator
        or &lt;a href=&quot;http://struts.apache.org/userGuide/dev_tiles.html&quot;&gt;Tiles&lt;/a&gt; layout. If you&apos;re not using SiteMesh or Tiles, it&apos;s high time
        you started.&lt;/li&gt;
    &lt;li&gt;JSON-RPC currently requires that you register each class you want call
        methods on. In our project, I registered a Spring bean (LookupHelper)
        that&apos;s a singleton with references to Maps in the ServletContext. Then
        we used JavaScript functions to call JSON-PRC and look up units for
        a plant, and vice versa. I&apos;m not going to put the LookupHelper class
        here - you&apos;ll have to trust its methods  return a single String
        or a comma-separated list of Strings. To register this bean with JSON-RPC,
        I created an HttpSessionListener and configured it in web.xml.
&lt;p&gt;

&lt;!-- ======================================================== --&gt;
&lt;!-- = Java Sourcecode to HTML automatically converted code = --&gt;
&lt;!-- =   Java2Html Converter 5.0 [2006-02-26] by Markus Gebhard  markus@jave.de   = --&gt;
&lt;!-- =     Further information: http://www.java2html.de     = --&gt;
&lt;div align=&quot;left&quot; class=&quot;java&quot;&gt;
&lt;table border=&quot;0&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; bgcolor=&quot;#ffffff&quot;&gt;
   &lt;tr&gt;
  &lt;!-- start source code --&gt;
   &lt;td nowrap=&quot;nowrap&quot; valign=&quot;top&quot; align=&quot;left&quot;&gt;
    &lt;code&gt;
&lt;font color=&quot;#3f5fbf&quot;&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&amp;nbsp;UserListener&amp;nbsp;class&amp;nbsp;used&amp;nbsp;to&amp;nbsp;add/remove&amp;nbsp;session&amp;nbsp;attributes&amp;nbsp;when&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&amp;nbsp;a&amp;nbsp;user&amp;nbsp;first&amp;nbsp;logs&amp;nbsp;in.&amp;nbsp;&amp;nbsp;Mainly&amp;nbsp;for&amp;nbsp;JavaScript&amp;nbsp;Remote&amp;nbsp;Scripting&amp;nbsp;stuff.&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f9fbf&quot;&gt;@author&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;Matt&amp;nbsp;Raible&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;UserListener&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;implements&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;HttpSessionListener,&amp;nbsp;HttpSessionAttributeListener&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;{&amp;nbsp;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;private&amp;nbsp;final&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;Log&amp;nbsp;log&amp;nbsp;=&amp;nbsp;LogFactory.getLog&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;UserListener.&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;public&amp;nbsp;final&amp;nbsp;static&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;String&amp;nbsp;BRIDGE_KEY&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;JSONRPCBridge&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&amp;nbsp;Initializes&amp;nbsp;LookupHelper&amp;nbsp;singleton&amp;nbsp;with&amp;nbsp;values&amp;nbsp;needed&amp;nbsp;for&amp;nbsp;lookup&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f9fbf&quot;&gt;@param&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;event&amp;nbsp;the&amp;nbsp;HttpSessionEvent&amp;nbsp;to&amp;nbsp;grab&amp;nbsp;session&amp;nbsp;information&amp;nbsp;from&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;sessionCreated&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;HttpSessionEvent&amp;nbsp;event&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;Find&amp;nbsp;the&amp;nbsp;JSONRPCBridge&amp;nbsp;for&amp;nbsp;this&amp;nbsp;session&amp;nbsp;or&amp;nbsp;create&amp;nbsp;one&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;if&amp;nbsp;it&amp;nbsp;doesn&apos;t&amp;nbsp;exist.&amp;nbsp;Note&amp;nbsp;the&amp;nbsp;bridge&amp;nbsp;must&amp;nbsp;be&amp;nbsp;named&amp;nbsp;BRIDGE_KEY&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;in&amp;nbsp;the&amp;nbsp;HttpSession&amp;nbsp;for&amp;nbsp;the&amp;nbsp;JSONRPCServlet&amp;nbsp;to&amp;nbsp;find&amp;nbsp;it.&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;HttpSession&amp;nbsp;session&amp;nbsp;=&amp;nbsp;event.getSession&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;()&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;JSONRPCBridge&amp;nbsp;jsonBridge&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;JSONRPCBridge&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;()&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;jsonBridge.setDebug&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;true&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;session.setAttribute&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;BRIDGE_KEY,&amp;nbsp;jsonBridge&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&amp;nbsp;Destroys&amp;nbsp;LookupHelper&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f9fbf&quot;&gt;@param&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;event&amp;nbsp;the&amp;nbsp;HttpSessionEvent&amp;nbsp;to&amp;nbsp;grab&amp;nbsp;session&amp;nbsp;information&amp;nbsp;from&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f5fbf&quot;&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;sessionDestroyed&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;HttpSessionEvent&amp;nbsp;event&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;event.getSession&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;()&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;!=&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;event.getSession&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;()&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;.removeAttribute&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;BRIDGE_KEY&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;attributeAdded&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;HttpSessionBindingEvent&amp;nbsp;event&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;event.getName&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;()&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;.equals&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;BRIDGE_KEY&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;))&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;HttpSession&amp;nbsp;session&amp;nbsp;=&amp;nbsp;event.getSession&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;()&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;register&amp;nbsp;LookupHelper&amp;nbsp;so&amp;nbsp;we&amp;nbsp;can&amp;nbsp;call&amp;nbsp;methods&amp;nbsp;on&amp;nbsp;it&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;ApplicationContext&amp;nbsp;ctx&amp;nbsp;=&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;WebApplicationContextUtils&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;.getWebApplicationContext&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;session.getServletContext&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;())&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;check&amp;nbsp;for&amp;nbsp;null&amp;nbsp;so&amp;nbsp;we&amp;nbsp;don&apos;t&amp;nbsp;have&amp;nbsp;to&amp;nbsp;initialize&amp;nbsp;Spring&amp;nbsp;in&amp;nbsp;tests&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;ctx&amp;nbsp;!=&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;log.debug&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;Registering&amp;nbsp;lookupHelper&amp;nbsp;for&amp;nbsp;XmlHttpRequest...&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;JSONRPCBridge&amp;nbsp;jsonBridge&amp;nbsp;=&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;JSONRPCBridge&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;session.getAttribute&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;BRIDGE_KEY&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;jsonBridge.registerObject&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;lookupHelper&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;,&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;ctx.getBean&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;lookupHelper&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;))&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;attributeRemoved&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;HttpSessionBindingEvent&amp;nbsp;event&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;don&apos;t&amp;nbsp;care&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;attributeReplaced&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;HttpSessionBindingEvent&amp;nbsp;event&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;same&amp;nbsp;as&amp;nbsp;attribute&amp;nbsp;added&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;attributeAdded&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;event&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;/code&gt;
    
   &lt;/td&gt;
  &lt;!-- end source code --&gt;
   &lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;!-- =       END of automatically generated HTML code       = --&gt;
&lt;!-- ======================================================== --&gt;


&lt;/p&gt;
&lt;p&gt;		&lt;/li&gt;
    &lt;li&gt;After this setup was complete, I was able to add the following JavaScript
        to the bottom of my JSP. These are functions that our drop-downs call
        to populate each other, and keep their options in synch.
&lt;/p&gt;
&lt;p&gt;

&lt;!-- ======================================================== --&gt;
&lt;!-- = Java Sourcecode to HTML automatically converted code = --&gt;
&lt;!-- =   Java2Html Converter 5.0 [2006-02-26] by Markus Gebhard  markus@jave.de   = --&gt;
&lt;!-- =     Further information: http://www.java2html.de     = --&gt;
&lt;div align=&quot;left&quot; class=&quot;java&quot;&gt;
&lt;table border=&quot;0&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; bgcolor=&quot;#ffffff&quot;&gt;
   &lt;tr&gt;
  &lt;!-- start source code --&gt;
   &lt;td nowrap=&quot;nowrap&quot; valign=&quot;top&quot; align=&quot;left&quot;&gt;
    &lt;code&gt;
&lt;font color=&quot;#000000&quot;&gt;&amp;lt;script&amp;nbsp;type=&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;text/javascript&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;&amp;gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;var&amp;nbsp;jsonurl&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;${ctx}/jsonrpc&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;var&amp;nbsp;jsonrpc&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;var&amp;nbsp;unitDropDown&amp;nbsp;=&amp;nbsp;document.getElementById&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;equipmentName&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;function&amp;nbsp;filterUnits&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;plantDropDown&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;var&amp;nbsp;plantName&amp;nbsp;=&amp;nbsp;plantDropDown.options&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;plantDropDown.selectedIndex&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;]&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;.value;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;plantName&amp;nbsp;==&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;reloadUnits&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;try&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;jsonrpc&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;JSONRpcClient&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;jsonurl&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;catch&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;e&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;alert&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;e&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;Call&amp;nbsp;a&amp;nbsp;Java&amp;nbsp;method&amp;nbsp;on&amp;nbsp;the&amp;nbsp;server&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;var&amp;nbsp;units&amp;nbsp;=&amp;nbsp;jsonrpc.lookupHelper.getUnitsForPlant&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;plantName&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;setUnits&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;units&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;function&amp;nbsp;reloadUnits&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;value&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;value&amp;nbsp;==&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;try&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;jsonrpc&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;JSONRpcClient&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;jsonurl&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;catch&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;e&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;alert&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;e&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;Call&amp;nbsp;a&amp;nbsp;Java&amp;nbsp;method&amp;nbsp;on&amp;nbsp;the&amp;nbsp;server&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;var&amp;nbsp;units&amp;nbsp;=&amp;nbsp;jsonrpc.lookupHelper.getAllUnits&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;()&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;setUnits&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;units&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;function&amp;nbsp;setUnits&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;units&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;var&amp;nbsp;unitArray&amp;nbsp;=&amp;nbsp;units.split&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#2a00ff&quot;&gt;&amp;#34;,&amp;#34;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;unitDropDown.options.length&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#990000&quot;&gt;1&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#3f7f5f&quot;&gt;//&amp;nbsp;keep&amp;nbsp;&amp;#34;All&amp;#34;&amp;nbsp;option&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;for&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;i=&lt;/font&gt;&lt;font color=&quot;#990000&quot;&gt;0&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;unitArray.length;&amp;nbsp;i++&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;unitDropDown.options&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;unitDropDown.options.length&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;]&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;=&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#7f0055&quot;&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;Option&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;(&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;unitArray&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;i&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;]&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;,&amp;nbsp;unitArray&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;[&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;i&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;])&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#ffffff&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color=&quot;#000000&quot;&gt;&amp;lt;/script&amp;gt;&lt;/font&gt;&lt;/code&gt;
    
   &lt;/td&gt;
  &lt;!-- end source code --&gt;
   &lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;!-- =       END of automatically generated HTML code       = --&gt;
&lt;!-- ======================================================== --&gt;


&lt;/p&gt;
&lt;p&gt;    &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The hardest part of using JSON-RPC is setting it up. We only experienced minor issues with Commons Validator, but since the JSON-RPC 0.8 release - everything has  worked great, on all browsers we need to support. The only thing I don&apos;t like about this library is that you have to register objects for each user&apos;s session. I briefly looked at DWR and it looks a little cleaner - especially b/c of its Spring integration. The next time we need XMLHttpRequest, we&apos;ll probably use DWR just to compare the two.&lt;/p&gt;
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/edit_screens_with_jsf</id>
        <title type="html">Edit Screens with JSF</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/edit_screens_with_jsf"/>
        <published>2004-11-28T10:02:25-07:00</published>
        <updated>2007-02-10T20:07:56-07:00</updated> 
        <category term="/Java" label="Java" />
        <content type="html">I&apos;m working with JSF this morning and I&apos;m finding one thing particularly annoying.  I&apos;m working on a simple master/detail screen and I&apos;m tweaking the detail screen to fit my needs.  It&apos;s just a &amp;lt;form&amp;gt; with some form elements.  I change something, run &quot;ant deploy-web&quot; and hit &quot;refresh&quot; to see my updated page.  Since everything in JSF is a post, I get prompted to re-submit the form.  Fine, I agree - then I&apos;m returned to the list screen.  Argggh - why can&apos;t I just view the form again?!  This might just be a MyFaces nuance, I&apos;m not sure.  Anyone know of a workaround?
&lt;br /&gt;&lt;br /&gt;
Wanna see the bug/feature in action?  Go to &lt;a href=&quot;http://demo.raibledesigns.com/equinox-jsf/userList.html&quot;&gt;http://demo.raibledesigns.com/equinox-jsf/userList.html&lt;/a&gt;, click on a row - and after the edit screen displays, hit refresh on your browser.  In an ideal world, you&apos;d see the form again, but nope - you get the list instead.</content>
    </entry>
</feed>

