<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en"><title type="text">Owen Ou's Blog</title><link rel="alternate" type="text/html" href="http://owenou.com" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/OwenOu" /><subtitle type="text">= Blog.new(:kind =&gt; "geek")</subtitle><author><name>Jingwen Owen Ou</name><email>jingweno@gmail.com</email></author><updated>2012-02-10T16:06:21+00:00</updated><feedburner:info uri="owenou" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><id>http://owenou.com/</id><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-sa/3.0/" /><xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" /><meta xmlns="http://pipes.yahoo.com" name="pipes" content="noprocess" /><feedburner:emailServiceId>OwenOu</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry><title type="text">PoEAA on Rails</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/CnmBUF9vOwA/poeaa-on-rails.html" /><updated>2011-09-24T00:00:00-07:00</updated><id>http://owenou.com/2011/09/24/poeaa-on-rails</id><content type="html">&lt;p&gt;The book &lt;a href='http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420'&gt;Patterns of Enterprise Application Architecture&lt;/a&gt; (PoEAA) laid the blueprints for Rails&amp;#8217; architecture. When choosing which enterprise design patterns to encode into the framework, Rails picked, to name a few, &lt;a href='http://martinfowler.com/eaaCatalog/activeRecord.html'&gt;Active Record&lt;/a&gt;, &lt;a href='http://martinfowler.com/eaaCatalog/templateView.html'&gt;Template View&lt;/a&gt;, &lt;a href='http://martinfowler.com/eaaCatalog/applicationController.html'&gt;Application Controller&lt;/a&gt;, etc. By covering these patterns with a sweet coating of convention-over-configuration, Rails simplifies pattern analysis a lot.&lt;/p&gt;

&lt;p&gt;These design assumptions were absolutely pragmatic for the type of applications that Rails was targeting at. However, as applications growing more and more complex, developers are starting to realize these default architectural patterns may not scale very well. Typically, four main areas are overloaded in an enterprise application:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;high coupling between domain model and data source,&lt;/li&gt;

&lt;li&gt;bloated domain model with a mix of domain logic and application logic,&lt;/li&gt;

&lt;li&gt;presentation behaviour leaked into views, and&lt;/li&gt;

&lt;li&gt;high coupling between view data and template&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To understand these problems better as well as to figure out possible solutions, I would like to walk you through some enterprise patterns from the same book that Rails&amp;#8217; architecture heavily bases upon.&lt;/p&gt;

&lt;p&gt;Note that the patterns I am mentioning here will benefit more for complex applications, for example, an e-commerce web application selling digital goods. There&amp;#8217;s clearly some overhead to use these patterns for simple projects where the default Rails patterns shine. Most importantly, you should only apply these patterns where they make sense. I am a strong believer in contextual solution and these patterns are definitely not the only way to go.&lt;/p&gt;

&lt;h4 id='data_mapper'&gt;Data Mapper&lt;/h4&gt;

&lt;p&gt;&lt;a href='http://martinfowler.com/eaaCatalog/dataMapper.html'&gt;Data Mapper&lt;/a&gt; is a layer that transfers data between objects and a database. It typically creates &lt;a href='http://martinfowler.com/eaaCatalog/domainModel.html'&gt;Domain Model&lt;/a&gt; objects by populating their attributes from the database.&lt;/p&gt;
&lt;div class='center'&gt;
&lt;p&gt;&lt;img src='/images/posts/data_mapper.png' alt='Data Mapper' /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Assuming we are building an e-commerce platform, we get a store object by going through the store mapper which connects to the database:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/controllers/stores_controller.rb&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;StoreController&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ApplicationController&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;show&lt;/span&gt;
    &lt;span class='vi'&gt;@store&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;StoreMapper&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The difference between &lt;a href='http://martinfowler.com/eaaCatalog/activeRecord.html'&gt;Active Record&lt;/a&gt; and Data Mapper is actually that in the Active Record implementation, Domain Model not only encapsulates business logic, but also takes responsibility of database access, while in the Data Mapper implementation, Domain Model is ignorant of database and become Plain Old Ruby Object with business logic. Data Mapper allows database logic and the object model to evolve independently.&lt;/p&gt;

&lt;p&gt;Note that the Active Record pattern and the Data Mapper pattern mentioned are not the Ruby libraries these patterns inspire. The &lt;a href='http://rubygems.org/gems/activerecord'&gt;active_record&lt;/a&gt; gem is an implementation of the Active Record pattern. The &lt;a href='http://datamapper.org/'&gt;data_mapper&lt;/a&gt; gem is also a &amp;#8220;Active Record&amp;#8221;-ish implementation, although it has elements of the Data Mapper pattern. For those who are interested in seeing the implementation difference between these two gems, I created a &lt;a href='https://gist.github.com/1244351'&gt;gist&lt;/a&gt; for you.&lt;/p&gt;

&lt;p&gt;Here is &lt;a href='http://martinfowler.com/'&gt;Martin Fowler&lt;/a&gt; on the choice of Active Record or Data Mapper for Domain Model:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An OO domain model will often look similar to a database model, yet it will still have a lot of differences. A Domain Model mingles data and process, has multivalued attributes and a complex web of associations, and uses inheritance.&lt;/p&gt;

&lt;p&gt;As a result I see two styles of Domain Model in the field. A simple Domain Model looks very much like the database design with mostly one domain object for each database table. A rich Domain Model can look different from the database design, with inheritance, strategies, and other [Gang of Four] patterns, and complex webs of interconnected objects. A rich Domain Model is better for more complex logic, but is harder to map to the database. &lt;strong&gt;A simple Domain Model can use Active Record, whereas a rich Domain Model requires Data Mapper&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In an enterprise Rails application, it&amp;#8217;s not rare to see complex domain models stuffed with associations, validations, scopes and business logics. It has become a growing pain to deal with such &amp;#8220;fat models&amp;#8221;. We need to separate the database concerns out into a new dedicated layer: the data mappers. However, as far as I know, there&amp;#8217;s no ORM in Ruby giving us such separation yet, although it&amp;#8217;s been said the upcoming 2.0 release of the data_mapper gem will &lt;a href='https://github.com/datamapper/dm-core/wiki/Roadmap'&gt;fully implement the Data Mapper pattern&lt;/a&gt;. Before we are able to consume the new data_mapper gem, is there a way to mitigate existing overloaded Rails models? Besides, switching an ORM for existing code is not effortless.&lt;/p&gt;

&lt;p&gt;[Updated 01/10 2012], &lt;a href='http://solnic.eu/'&gt;Piotr Solnica&lt;/a&gt; from the data_mapper gem made an official announcement saying they are actively working on Data Mapper 2.0. Announcement goes &lt;a href='http://solnic.eu/2012/01/10/ruby-datamapper-status.html'&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a compromised solution, I would extract database related logic for each &lt;em&gt;ActiveRecord::Base&lt;/em&gt; model (e.g., validations and scopes) out into a module and then mix it in:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/mappers/store_mapper.rb&lt;/span&gt;

&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;StoreMapper&lt;/span&gt;
  &lt;span class='kp'&gt;extend&lt;/span&gt; &lt;span class='no'&gt;ActiveSupport&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Concern&lt;/span&gt;

  &lt;span class='n'&gt;included&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='c1'&gt;# validations&lt;/span&gt;
    &lt;span class='n'&gt;validates_presence_of&lt;/span&gt; &lt;span class='ss'&gt;:name&lt;/span&gt;
    &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;

    &lt;span class='c1'&gt;# scopes&lt;/span&gt;
    &lt;span class='n'&gt;scope&lt;/span&gt; &lt;span class='ss'&gt;:disabled&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;where&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:disabled&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='kp'&gt;true&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/models/store.rb&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Store&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActiveRecord&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
  &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;StoreMapper&lt;/span&gt;

  &lt;span class='c1'&gt;# associations&lt;/span&gt;
  &lt;span class='n'&gt;has_many&lt;/span&gt; &lt;span class='ss'&gt;:products&lt;/span&gt;
  &lt;span class='n'&gt;belongs_to&lt;/span&gt; &lt;span class='ss'&gt;:company&lt;/span&gt;
  &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;

  &lt;span class='c1'&gt;# business logics&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;calculate_sells&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;from_date&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;to_date&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='c1'&gt;# calculate sells from date to date&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This half-baked solution, although not migrating to the Data Mapper pattern, cleanly isolates the definitions of database logic with the ones of business logic. Of course, it&amp;#8217;s recommended to use the Data Mapper pattern where possible.&lt;/p&gt;

&lt;h4 id='service_layer'&gt;Service Layer&lt;/h4&gt;

&lt;p&gt;Layering is one of the most common techniques to break apart a complex software system. The higher layer uses service defined by the lower layer, but the lower layer is unaware of the higher layer. Each layer usually hides its lower layers from the layers above. A Rails project is typically divided into three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;presentation layer, including views and controllers,&lt;/li&gt;

&lt;li&gt;domain layer, including models, and&lt;/li&gt;

&lt;li&gt;data source layer, which is hidden behind models extending from &lt;em&gt;ActiveRecord::Base&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It&amp;#8217;s not difficult to understand the Data Mapper pattern is an effort to break down #3 into another layer to lower the complexity of models. However, in the context of enterprise application, models are still overwhelmed by complicated business logic. As Fowler pointed out, business logic can be further divided into &amp;#8220;domain logic&amp;#8221; and &amp;#8220;application logic&amp;#8221;, and &lt;a href='http://martinfowler.com/eaaCatalog/serviceLayer.html'&gt;Service Layer&lt;/a&gt; is a pattern to encapsulate model&amp;#8217;s &amp;#8220;application logic&amp;#8221; by establishing a boundary where the presentation layers interact with the application:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8230; Service Layer is a pattern for organization business logic. Many Designers, including me, like to divide &amp;#8220;business logic&amp;#8221; into two kinds: &amp;#8220;domain logic&amp;#8221;, having to do purely with the problem domain (such as strategies for calculating revenue recognition on a contract), and &amp;#8220;application logic&amp;#8221;, having to do with application responsibilities [Cockburn UC] (such as notifying contract administrators, and integrated applications, of revenue recognition calculations). Application logic is sometimes referred to as &amp;#8220;workflow logic&amp;#8221;, although different people have different interpretations of &amp;#8220;workflow&amp;#8221;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He also pointed out, Service Layer is a good fit for coordinating operations among multiple models, as well as for talking to multiple presentation layers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The benefit of Service Layer is that it defines a common set of application operations available to many kinds of clients and it coordinates an application&amp;#8217;s response in each operation. &amp;#8230;&lt;/p&gt;

&lt;p&gt;The easier question to answer is probably when not to use it. You probably don&amp;#8217;t need a Service Layer if your application&amp;#8217;s business logic will only have one kind of client - say, a user interface - and its use case responses don&amp;#8217;t involve multiple transactional resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To translate this into a code example, let&amp;#8217;s assume in an e-commerce platform, we need to email monthly sells report to the store owner. In this example, &lt;em&gt;StoreService&lt;/em&gt; acts as a coordinator of multiple models for the &amp;#8220;mailing sells report&amp;#8221; workflow:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/services/store_service.rb&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;StoreService&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;mail_sells_report&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;store_id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;from_date&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;to_date&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;store&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;StoreMapper&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;store_id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;store_sells&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;store&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;calculate_sells&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;from_date&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;to_date&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;store_report&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;SellsReport&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;generate&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;store_sells&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='no'&gt;SellsReportMailer&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;report_mailer&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;store&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;owner&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;store_report&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;deliver&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Another place where Service Layer shines is reusing workflows for different controllers, for example, the same workflow in the above example is used in the &lt;em&gt;Storefront::StoresController&lt;/em&gt; for store front and in the &lt;em&gt;Api::StoresController&lt;/em&gt; for REST API calls. Service Layer becomes a &lt;a href='http://en.wikipedia.org/wiki/Facade_pattern'&gt;Facade&lt;/a&gt; in this case.&lt;/p&gt;

&lt;h4 id='presentation_model'&gt;Presentation Model&lt;/h4&gt;

&lt;p&gt;It&amp;#8217;s not uncommon to present multiple models in a view. Most importantly, not all attributes of a model are needed for a certain presentation. In a complex system where there are lots of screens, views become a very busy place for extracting state and behavior from models. The &lt;a href='http://martinfowler.com/eaaDev/PresentationModel.html'&gt;Presentation Model&lt;/a&gt; comes to ease the pain:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Presentation Model pulls the state and behavior of the view out into a model class that is part of the presentation. The Presentation Model coordinates with the domain layer and provides an interface to the view that minimizes decision making in the view. The view either stores all its state in the Presentation Model or synchronizes its state with Presentation Model frequently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As an example, let&amp;#8217;s build a view for the scenario &amp;#8220;creating a store for a user&amp;#8221;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/presenters/create_store_presenter.rb&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;CreateStorePresenter&lt;/span&gt;
  &lt;span class='kp'&gt;attr_reader&lt;/span&gt; &lt;span class='ss'&gt;:store&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:user&lt;/span&gt;

  &lt;span class='n'&gt;delegate&lt;/span&gt; &lt;span class='ss'&gt;:name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:to&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:store&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:prefix&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='kp'&gt;true&lt;/span&gt;
  &lt;span class='n'&gt;delegate&lt;/span&gt; &lt;span class='ss'&gt;:email&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:to&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:user&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:prefix&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='kp'&gt;true&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@store&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Store&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:store&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@store&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;build_user&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:user&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;valid?&lt;/span&gt;
    &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;valid?&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='vi'&gt;@store&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;valid?&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;save&lt;/span&gt;
    &lt;span class='vi'&gt;@store&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;save&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;&amp;lt;!-- app/views/stores/create_store.html.erb --&amp;gt;&lt;/span&gt;

&lt;span class='x'&gt;&amp;lt;h1&amp;gt;Create a store&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;form_for&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@create_store_presenter&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;  &amp;lt;p&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;label&lt;/span&gt; &lt;span class='ss'&gt;:store_name&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x'&gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;text_field&lt;/span&gt; &lt;span class='ss'&gt;:store_name&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class='x'&gt;  &amp;lt;p&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;label&lt;/span&gt; &lt;span class='ss'&gt;:user_email&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x'&gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;text_field&lt;/span&gt; &lt;span class='ss'&gt;:user_email&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class='x'&gt;  &amp;lt;p&amp;gt;&lt;/span&gt;
&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;submit&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Create&amp;quot;&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In the example, we wrap two models (&lt;em&gt;Store&lt;/em&gt; and &lt;em&gt;User&lt;/em&gt;) into a presenter and extract only the attributes needed (&lt;em&gt;Store#name&lt;/em&gt; and &lt;em&gt;User#email&lt;/em&gt;) for the &amp;#8220;create store&amp;#8221; screen. To summarize this pattern, I would like to once again consult Fowler:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Presentation Model is a pattern that pulls presentation behavior from a view. &amp;#8230; It&amp;#8217;s useful for allowing you to test without the UI, support for some form of multiple view and a separation of concerns which may make it easier to develop the user interface.&lt;/p&gt;

&lt;p&gt;&amp;#8230; Presentation Model allows you to write logic that is completely independent of the views used for display. You also do not need to rely on the view to store state. &amp;#8230;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id='two_step_views'&gt;Two Step Views&lt;/h4&gt;

&lt;p&gt;Rails comes with a neat templating system that allows you to quickly create dynamic pages. However, this &lt;a href='http://martinfowler.com/eaaCatalog/templateView.html'&gt;Template View&lt;/a&gt; pattern has drawbacks as Fowler pointed out, especially in a situation where the view is very complex:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8230; the common implementations make it too easy to put complicated logic in the page, thus making it hard to maintain, particularly by nonprogrammers. You need good discipline to keep the page simple and display oriented, putting logic in the helper. &amp;#8230;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What&amp;#8217;s worse, if the display of a view is based on conditions, for example in a multi-appearance application, you will find logic that determines which template to render leaked into many places in views or controllers. Again, this is fine for a simple Rails application. But it becomes unmanageable as the application growing more complex.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s think about an example: an e-commerce platform supports multiple stores and each store has its own storefront to display a product. It&amp;#8217;s common to see the following solution:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;&amp;lt;!-- app/views/products/_product.html.erb --&amp;gt;&lt;/span&gt;

&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;store&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;amazon_store?&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;  &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:partial&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/amazon/products/_product.html.erb&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:object&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;product&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;elsif&lt;/span&gt; &lt;span class='n'&gt;store&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;apple_store?&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;  &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:partial&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/apple/products/_product.html.erb&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:object&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;product&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;  &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:partial&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/default/products/_product.html.erb&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:object&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;product&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The determination logic for displaying a product based on store is leaked into the product partial. Apparently, to build the whole multi-appearance application, this approach does not scale. Thankfully, Fowler has something good for us - the &lt;a href='http://martinfowler.com/eaaCatalog/twoStepView.html'&gt;Two Step View&lt;/a&gt; pattern:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8230; You may also want to make global changes to the appearance of the site easily, but common approaches using Template View or Transform View make this difficult because presentation decisions are often duplicated across multiple pages or transform modules. A global change can force you to change several files.&lt;/p&gt;

&lt;p&gt;Two Step View deals with this problem by splitting the transformation into two stages. The first transforms the model data into a logical presentation without any special formatting; the second converts that logical presentation with the actual formatting needed. &amp;#8230;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class='center'&gt;
&lt;p&gt;&lt;img src='/images/posts/two_step_view.png' alt='Two Step View' /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;From the above diagram, the multi-storefront example can be reimplemented with the Two Step View pattern. The process is in two steps. The first step is to transform the product data into a logical presentation. The second step is to convert this logical presentation into different HTML.&lt;/p&gt;

&lt;p&gt;Note that in the implementation, a gem called &lt;a href='https://github.com/apotonick/cells'&gt;cells&lt;/a&gt; is used to help define logical presentation. The cells gem is very helpful in this respect although it was originally designed for other purposes.&lt;/p&gt;

&lt;p&gt;For the logical presentation, we define it to display name, description, price and reviews of a product for every store:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;&amp;lt;!-- app/views/products/_product.html.erb --&amp;gt;&lt;/span&gt;

&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;render_cell&lt;/span&gt; &lt;span class='ss'&gt;:product&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;product&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;render_cell&lt;/span&gt; &lt;span class='ss'&gt;:product&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:description&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;product&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;description&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;render_cell&lt;/span&gt; &lt;span class='ss'&gt;:product&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:price&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;product&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;price&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;render_cell&lt;/span&gt; &lt;span class='ss'&gt;:product&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:reviews&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;product&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;reviews&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We then define three strategies (&lt;em&gt;ProductCell&lt;/em&gt;, &lt;em&gt;Amazon::ProductCell&lt;/em&gt;, and &lt;em&gt;Apple::ProductCell&lt;/em&gt;) to convert the logical presentation to different HTML. We make use of cells&amp;#8217; strategy builder to return strategy class based on current store in session:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/cells/product_cell.rb&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;ProductCell&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Cell&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Rails&lt;/span&gt;
  &lt;span class='c1'&gt;# return strategy class based on current store in session&lt;/span&gt;
  &lt;span class='n'&gt;build&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;current_store&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;::ProductCell&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;classify&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;constantize&lt;/span&gt; &lt;span class='k'&gt;rescue&lt;/span&gt; &lt;span class='kp'&gt;nil&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;name&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;content_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:h1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;reviews&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;reviews&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='c1'&gt;# display reviews&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/cells/amazon/product_cell.rb&lt;/span&gt;

&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;Amazon&lt;/span&gt;
  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;ProductCell&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;ProductCell&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;name&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='n'&gt;content_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:p&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;reviews&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;reviews&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='c1'&gt;# display reviews for Amazon store&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/cells/apple/product_cell.rb&lt;/span&gt;

&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;Apple&lt;/span&gt;
  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;ProductCell&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;ProductCell&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;name&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='n'&gt;content_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:div&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:class&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;reviews&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;reviews&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='c1'&gt;# display reviews for Apple store&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;As you may see, the Two Step View pattern makes multi-appearance implementation manageable in a way that different appearance implementations are organized in a set of strategy classes to parse a common logial presentation.&lt;/p&gt;

&lt;h4 id='summary'&gt;Summary&lt;/h4&gt;

&lt;p&gt;The default enterprise design patterns encoded into Rails are perfect matches for small/medium size projects. They are light weight and easy to understand. However, as the application growing more mature, these patterns do not scale well due to layers taking too much responsibility. That said, a &amp;#8220;fat&amp;#8221; layer need to be broken into smaller ones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Data Mapper is an effort to extract out data source layer from Domain Model that implements Active Record,&lt;/li&gt;

&lt;li&gt;Service Layer is an endeavor to extract out application logic from Domain Model,&lt;/li&gt;

&lt;li&gt;Presentation Model is an attempt to extract out presentation logic from a single or multiple Domain Model, and&lt;/li&gt;

&lt;li&gt;Two Step View is a try to break down presentation logic into two processing steps so that a view can be generated in different formats.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In return for breaking apart a system into smaller layers, each layer becomes easier to maintain, reuse, test and scale.&lt;/p&gt;

&lt;p&gt;Last but not least, I would like to thank Martin Fowler for his awesome book and would love to hear any feedback for you.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=CnmBUF9vOwA:G1kKOOqRykA:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=CnmBUF9vOwA:G1kKOOqRykA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=CnmBUF9vOwA:G1kKOOqRykA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=CnmBUF9vOwA:G1kKOOqRykA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=CnmBUF9vOwA:G1kKOOqRykA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=CnmBUF9vOwA:G1kKOOqRykA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=CnmBUF9vOwA:G1kKOOqRykA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=CnmBUF9vOwA:G1kKOOqRykA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=CnmBUF9vOwA:G1kKOOqRykA:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=CnmBUF9vOwA:G1kKOOqRykA:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=CnmBUF9vOwA:G1kKOOqRykA:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/CnmBUF9vOwA" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2011/09/24/poeaa-on-rails.html</feedburner:origLink></entry><entry><title type="text">Automatic Testing of REST Web Services Client with Rails</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/9oGCp8Bvgsk/testing-rest-web-services-with-rails.html" /><updated>2011-07-20T00:00:00-07:00</updated><id>http://owenou.com/2011/07/20/testing-rest-web-services-with-rails</id><content type="html">&lt;p&gt;Testing REST web services client has never been easy. It requires a running web server, multiple threads, network conection and complex transaction management.&lt;/p&gt;

&lt;p&gt;Ideally, REST web service client test should have the following characteristics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The experience of testing REST resource is similar to that of testing a ActiveRecord model&lt;/li&gt;

&lt;li&gt;Start up and shut down web server for the purpose of running REST web services&lt;/li&gt;

&lt;li&gt;Rollback test data after each test&lt;/li&gt;

&lt;li&gt;Control fixture creation for REST web services&lt;/li&gt;

&lt;li&gt;All tests are automatic&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this article, I demonstrate solutions to each of those mentioned.&lt;/p&gt;

&lt;p&gt;As an example throughout the article, let&amp;#8217;s assume we have web services for a model called &lt;em&gt;Task&lt;/em&gt; and we are testing its corresponding client code. Here is a sample action in the &lt;em&gt;TasksController&lt;/em&gt; of the web server:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# server/app/controllers/tasks_controller.rb&lt;/span&gt;

&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;index&lt;/span&gt;
  &lt;span class='vi'&gt;@tasks&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Task&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;
  &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:status&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:ok&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:json&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='vi'&gt;@tasks&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We render &lt;em&gt;@tasks&lt;/em&gt; as the JSON format where &lt;em&gt;to_json&lt;/em&gt; is called on the object. When you run &amp;#8221;&lt;em&gt;curl http://localhost:3000/tasks.json&lt;/em&gt;&amp;#8221;, you will get the following result:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='nv'&gt;$ &lt;/span&gt;curl http://localhost:3000/tasks.json
&lt;span class='o'&gt;[{&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;id&amp;quot;&lt;/span&gt;:1,&lt;span class='s2'&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class='s2'&gt;&amp;quot;Write a blog post&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;:&lt;span class='s2'&gt;&amp;quot;2011-07-20T04:05:41Z&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;updated_at&amp;quot;&lt;/span&gt;:&lt;span class='s2'&gt;&amp;quot;2011-07-20T04:05:41Z&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;ends_at&amp;quot;&lt;/span&gt;:&lt;span class='s2'&gt;&amp;quot;2011-08-20T03:15:00Z&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id='activeresource'&gt;ActiveResource&lt;/h4&gt;

&lt;p&gt;In order to test our REST web services, we need a HTTP client. There are &lt;a href='http://ruby-toolbox.com/categories/http_clients.html'&gt;lots of them&lt;/a&gt; out there, but I found &lt;a href='http://api.rubyonrails.org/classes/ActiveResource/Base.html'&gt;ActiveResource&lt;/a&gt; the most enjoyable to use in a less complex situation. ActiveResource provides ActiveRecord compatible APIs, so when writing web service client tests, we feel like we are writing unit tests for a ActiveRecord model.&lt;/p&gt;

&lt;p&gt;To start with, we just need to extend it from ActiveResource::Base and give it the web server URL and representation format. That&amp;#8217;s it!&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# client/app/models/task.rb&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Task&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActiveResource&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
  &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;site&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;http://localhost:3000&amp;quot;&lt;/span&gt;
  &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;format&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='ss'&gt;:json&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And we are using it as if you are using an ActiveRecord object:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# client/spec/models/task_spec.rb&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;Task&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should return all the tasks&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='vi'&gt;@tasks&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Task&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;
    &lt;span class='vi'&gt;@tasks&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;size&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id='web_server'&gt;Web Server&lt;/h4&gt;

&lt;p&gt;To maintain a zero-setup test environment, we’ll have our test control the stratup and shutdown of a web server. By having the tests start and stop the web server, they can be easily run with no external dependencies.&lt;/p&gt;

&lt;p&gt;To control the startup and shutdown of a web server before and after all suites run, it&amp;#8217;s as simple as having something like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# client/spec_helper.rb&lt;/span&gt;

&lt;span class='no'&gt;RSpec&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;configure&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='ss'&gt;:suite&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='vi'&gt;@server&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Server&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;server_path&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@server&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;start&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;after&lt;/span&gt; &lt;span class='ss'&gt;:suite&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='vi'&gt;@server&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stop&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The implementation of &lt;em&gt;Server&lt;/em&gt; is also dead simple. Execute &amp;#8220;script/rails server -d&amp;#8221; to daemonize the server and issue a kill to stop it:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# client/lib/server.rb&lt;/span&gt;

&lt;span class='no'&gt;Class&lt;/span&gt; &lt;span class='no'&gt;Server&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;server_path&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@server_path&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;server_path&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;start&lt;/span&gt;
    &lt;span class='sb'&gt;`&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;rails_script&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='sb'&gt; server -d -e test`&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;stop&lt;/span&gt;
    &lt;span class='n'&gt;pid&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;read&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;pidfile&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='sb'&gt;`kill -9 &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;pid&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='sb'&gt;`&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='kp'&gt;private&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;rails_script&lt;/span&gt;
    &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@server_path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;rails&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;pidfile&lt;/span&gt;
    &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@server_path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;tmp&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;pids&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;server.pid&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id='transaction_rollback'&gt;Transaction Rollback&lt;/h4&gt;

&lt;p&gt;For testing strategies of web services, most people recommend to either truncate test data on each run or to mock out the request and response. These approaches are less ideal since they&amp;#8217;re either less effective or they&amp;#8217;re not testing full stack of the targeted web services.&lt;/p&gt;

&lt;p&gt;Would it be possible to wrap web services calls in a transaction and rollback data after each test, like what Rails&amp;#8217;s &lt;a href='http://ar.rubyonrails.org/classes/Fixtures.html'&gt;transactional fixture&lt;/a&gt; does?&lt;/p&gt;

&lt;p&gt;Of course! But let&amp;#8217;s first try to understand why making transaction rollback for web service calls is difficult:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Tests and web server are running in two separate threads, web server&amp;#8217;s transactional boundary can&amp;#8217;t expand to tests&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Web service calls may commit its transaction&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Web server doesn&amp;#8217;t know when to rollback the test data&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To overcome these problems, we’ll need to fully control the lifecycle of web server&amp;#8217;s database connection in the client tests. But how are we able to do this in a client-server architecture?&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.ruby-doc.org/stdlib/libdoc/drb/rdoc/classes/DRb.html'&gt;dRuby&lt;/a&gt; to rescue!&lt;/p&gt;

&lt;p&gt;For those who are not familiar with it, dRuby is as the &lt;strong&gt;Remote Method Invocation&lt;/strong&gt; to Java as to Ruby. It allows methods to be called in one Ruby process upon a Ruby object located in another Ruby process. &lt;a href='http://segment7.net/projects/ruby/drb/introduction.html'&gt;Here&lt;/a&gt; is a good introduction to brush you up.&lt;/p&gt;

&lt;p&gt;We’ll make use of dRuby to directly control the lifecycle of web service&amp;#8217;s database connection (&lt;a href='http://ar.rubyonrails.org/classes/ActiveRecord/Base.html#M000431'&gt;ActiveRecord::Base.connection&lt;/a&gt;) in our web services client tests. To do that, we add the following code to web server&amp;#8217;s &amp;#8221;&lt;em&gt;config/environments/test.rb&lt;/em&gt;&amp;#8221;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# server/config/environments/test.rb&lt;/span&gt;

&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;after_initialize&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='no'&gt;ActiveRecord&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;ConnectionAdapters&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;ConnectionPool&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;class_eval&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;alias_method&lt;/span&gt; &lt;span class='ss'&gt;:old_checkout&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:checkout&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;checkout&lt;/span&gt;
      &lt;span class='vi'&gt;@cached_connection&lt;/span&gt; &lt;span class='o'&gt;||=&lt;/span&gt; &lt;span class='n'&gt;old_checkout&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;drb&amp;#39;&lt;/span&gt;
  &lt;span class='no'&gt;DRb&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;start_service&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;druby://localhost:8000&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='no'&gt;ActiveRecord&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The above code snippet does two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Patch &lt;em&gt;ActiveRecord::ConnectionAdapters::ConnectionPool#checkout&lt;/em&gt; to make sure only one connection is shared across threads&lt;/li&gt;

&lt;li&gt;Start a dRuby service for ActiveRecord::Base to be used in tests&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In case you are wondering why it&amp;#8217;s necessary to share one database connection across threads: &lt;a href='https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L160'&gt;ActiveRecord creates one database connection for each thread&lt;/a&gt; in its connection pool. Our web service client tests run in a separate thread from the server&amp;#8217;s so it&amp;#8217;s impossible to track which connection to rollback data for the web services calls. What we are doing here is to make sure there is only one connection created and we always rollback data for this connection.&lt;/p&gt;

&lt;p&gt;After the aforementioned setup, we are able to expand the transaction boundary to tests:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# client/spec/models/task_spec.rb&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;Task&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='ss'&gt;:all&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='vi'&gt;@semaphore&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Mutex&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;
    &lt;span class='no'&gt;DRb&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;start_service&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;DRbObject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='kp'&gt;nil&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;druby://localhost:8000&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='ss'&gt;:each&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;begin_remote_transaction&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;after&lt;/span&gt; &lt;span class='ss'&gt;:each&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;rollback_remote_transaction&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;creates a task through web serices&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Task&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Write a blog post&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:ends_at&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;Date&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;tomorrow&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='no'&gt;Task&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;task&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='n'&gt;task&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='kp'&gt;private&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;begin_remote_transaction&lt;/span&gt;
    &lt;span class='vi'&gt;@semaphore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;lock&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;increment_open_transactions&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction_joinable&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;begin_db_transaction&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;rollback_remote_transaction&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rollback_db_transaction&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;decrement_open_transactions&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;clear_active_connections!&lt;/span&gt;
    &lt;span class='vi'&gt;@semaphore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;unlock&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Voila! With dRuby, we use begin+rollback to isolate changes of web services calls to the database, instead of having to delete+insert for every test case. A huge performance boost!&lt;/p&gt;

&lt;p&gt;Note that the Mutex lock in the code is to make sure that multiple web service client tests can run concurrently, for exmaple, using the &lt;a href='https://github.com/grosser/parallel_tests'&gt;parallel_tests&lt;/a&gt; gem. Without this lock, while the remote ActiveRecord connection is shared, the tests will behavior strangely in a multi-threads environment. You can ignore those lines if your web service client tests never run concurrently.&lt;/p&gt;

&lt;p&gt;We can easily refactor out the &lt;em&gt;begin_remote_transaction&lt;/em&gt; method and the &lt;em&gt;rollback_remote_transaction&lt;/em&gt; method to &lt;em&gt;spec_helper.rb&lt;/em&gt;, so that our web services client tests have little difference from usual ActiveRecord unit tests.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# client/spec_helper.rb&lt;/span&gt;

&lt;span class='no'&gt;RSpec&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;configure&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='ss'&gt;:all&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='vi'&gt;@semaphore&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Mutex&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;
    &lt;span class='no'&gt;DRb&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;start_service&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;DRbObject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='kp'&gt;nil&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;druby://localhost:8000&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='ss'&gt;:each&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='vi'&gt;@semaphore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;lock&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;increment_open_transactions&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction_joinable&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;begin_db_transaction&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;after&lt;/span&gt; &lt;span class='ss'&gt;:each&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rollback_db_transaction&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connection&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;decrement_open_transactions&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_base&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;clear_active_connections!&lt;/span&gt;
    &lt;span class='vi'&gt;@semaphore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;unlock&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# client/spec/models/task_spec.rb&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;Task&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;creates a task through web serices&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Task&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Write a blog post&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:ends_at&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;Date&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;tomorrow&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='no'&gt;Task&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;task&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='n'&gt;task&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id='fixture_creation'&gt;Fixture Creation&lt;/h4&gt;

&lt;p&gt;Most of the time, we create test fixtures to quickly define prototypes for each of the models and ask for instances with properties that are important to the test at hand. But in the context of REST web services, we can&amp;#8217;t create fixtures unless there is a REST API defined. To break this constraint, we use dRuby to open up another channel to directly interact with fixture data on web server.&lt;/p&gt;

&lt;p&gt;Assuming we are using the &lt;a href='https://github.com/thoughtbot/factory_girl/'&gt;factory_girl&lt;/a&gt; gem for fixture creation, We create a dRuby service for port discovery and a dRuby service for each fixture instance:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# server/lib/drb_active_record_instance_factory.rb&lt;/span&gt;

&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;factory_girl&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;DRbActiveRecordInstanceFactory&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;get_port_for_fixture_instance&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;factory_instance&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;port&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;create_port&lt;/span&gt;
    &lt;span class='n'&gt;inst&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Factory&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;factory_instance&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='no'&gt;DRb&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;start_service&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;druby://localhost:&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;port&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;inst&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;port&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;create_port&lt;/span&gt;
    &lt;span class='c1'&gt;# create a random port&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='no'&gt;DRb&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;start_service&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;druby://localhost:9000&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='no'&gt;DRbActiveRecordInstanceFactory&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In tests, we ask for the port of the fixture instance and query its corresponding remote reference:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# client/spec/models/task_spec.rb&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;Task&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='ss'&gt;:all&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='vi'&gt;@drb_factory&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;DRbObject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kp'&gt;nil&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;druby://localhost:9000&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;remote_task_port&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@drb_factory&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get_port_for_fixture_instance&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:task&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@remote_task&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;DRbObject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kp'&gt;nil&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;druby://localhost:&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;remote_task_port&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should ...&amp;quot;&lt;/span&gt;
    &lt;span class='c1'&gt;# test REST web services calls with @remote_task&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id='summary'&gt;Summary&lt;/h4&gt;

&lt;p&gt;Testing REST web services client can be less complex if we have full control over objects on the web server. ActiveResource and dRuby stand out to help! They make writing web service client tests feel like writing local unit tests.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9oGCp8Bvgsk:Sw2u1mcS3PU:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9oGCp8Bvgsk:Sw2u1mcS3PU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=9oGCp8Bvgsk:Sw2u1mcS3PU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9oGCp8Bvgsk:Sw2u1mcS3PU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9oGCp8Bvgsk:Sw2u1mcS3PU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9oGCp8Bvgsk:Sw2u1mcS3PU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=9oGCp8Bvgsk:Sw2u1mcS3PU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9oGCp8Bvgsk:Sw2u1mcS3PU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9oGCp8Bvgsk:Sw2u1mcS3PU:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9oGCp8Bvgsk:Sw2u1mcS3PU:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=9oGCp8Bvgsk:Sw2u1mcS3PU:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/9oGCp8Bvgsk" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2011/07/20/testing-rest-web-services-with-rails.html</feedburner:origLink></entry><entry><title type="text">Git Up Perforce with git-p4</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/7aPhnpJXJ1U/git-up-perforce-with-git-p4.html" /><updated>2011-03-23T00:00:00-07:00</updated><id>http://owenou.com/2011/03/23/git-up-perforce-with-git-p4</id><content type="html">&lt;p&gt;&lt;a href='http://en.wikipedia.org/wiki/Distributed_revision_control'&gt;Distributed version control systems&lt;/a&gt; open up lots of flexibility and provide lots of efficiency in work-flow than their centralized cousins (e.g. &lt;a href='http://www.perforce.com/'&gt;Perforce&lt;/a&gt;). There&amp;#8217;s often value to use DVCS in the team.&lt;/p&gt;

&lt;p&gt;However, the case that I run into frequently is where there is a corporate standard for a deficient VCS, but the team wish to work efficiently by using a more powerful VCS. In that case, there are many successful stories of using &lt;a href='http://martinfowler.com/bliki/VersionControlTools.html'&gt;multiple VCS&lt;/a&gt;: DVCS for local version control and committing to a shared centralized VCS with a DVCS-to-VCS bridge.&lt;/p&gt;

&lt;p&gt;Git is particularly good at this aspect which provides tons of &lt;a href='https://github.com/git/git/tree/master/contrib'&gt;bridges&lt;/a&gt; to other VCS (That&amp;#8217;s another good reason for preferring Git over Mercurial :-)). Lately I have been using the &lt;a href='https://github.com/git/git/blob/master/contrib/fast-import/git-p4'&gt;git-p4&lt;/a&gt; bridge to synchronize codes between a centralized Perforce repository and a local Git repository. This post is a tutorial on how to set this up.&lt;/p&gt;
&lt;div class='center'&gt;
&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/git-p4-20110323-172404.jpg' alt='git-p4 bridge' /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h4 id='setting_up_the_perforce_command_line_client'&gt;Setting up the Perforce command line client&lt;/h4&gt;

&lt;p&gt;The git-p4 bridge requires the &lt;a href='http://www.perforce.com/perforce/products/p4.html'&gt;p4 command line client&lt;/a&gt; properly set up. There is a &lt;a href='http://www.perforce.com/perforce/doc.current/manuals/p4guide/02_config.html'&gt;lengthy tutorial&lt;/a&gt; on Perforce&amp;#8217;s documentation website. The following is a short sums-up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install the p4 command line client (use &lt;a href='http://www.macports.org/'&gt;MacPort&lt;/a&gt; or &lt;a href='http://mxcl.github.com/homebrew/'&gt;Homebrew&lt;/a&gt; if you are a Mac guy :-))&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Create a .p4settings file in your home directory with the global &lt;a href='http://www.perforce.com/perforce/doc.current/manuals/cmdref/_env.html#1045283'&gt;environment settings&lt;/a&gt; for your Perforce repository. And in your .bashrc, export P4CONFIG=/path/to/your/.p4settings. For example, here is what my settings look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;P4PORT=repo_url:repo_port
P4USER=user_name
P4PASSWD=password
P4CLIENT=client_workspace_name
P4EDITOR=vim&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Run &amp;#8220;p4 client&amp;#8221; to define the workspace mappings&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Run &amp;#8220;p4 info&amp;#8221; to verify the settings&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After you have done all these, don&amp;#8217;t forget to issue &amp;#8220;p4 sync repo_url&amp;#8221; to test whether you are able to checkout stuff from your repository.&lt;/p&gt;

&lt;h4 id='installing_gitp4_bridge'&gt;Installing git-p4 bridge&lt;/h4&gt;

&lt;p&gt;The &lt;a href='https://github.com/git/git/tree/master/contrib/fast-import'&gt;git-p4&lt;/a&gt; bridge is a Python script to enable bidirectional operation between a Perforce depot and Git. It doesn&amp;#8217;t come with the Git distribution by default. To make it invokable in your system, you need to download the script and put it into your system path. For me, I clone the Git source code from GitHub and make a soft-link to the script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Clone the Git repository to somewhere&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone https://github.com/git/git.git git_source_path&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Create a soft-link to the git-p4 script in one of your system paths&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ln -s git_source_path/contrib/fast-import/git-p4 /usr/bin/git-p4 &lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Windows users need to include the &lt;a href='https://github.com/git/git/blob/master/contrib/fast-import/git-p4.bat'&gt;git-p4.bat&lt;/a&gt; file in the system path.&lt;/p&gt;

&lt;h4 id='commands'&gt;Commands&lt;/h4&gt;

&lt;p&gt;Four things to remember when using git-p4:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of using &amp;#8220;git push&amp;#8221; to push local commits to remote repository, use &amp;#8220;git-p4 submit&amp;#8221;&lt;/li&gt;

&lt;li&gt;Instead of using &amp;#8220;git fetch&amp;#8221; to fetch changes from remote repository to local, use &amp;#8220;git-p4 sync&amp;#8221;&lt;/li&gt;

&lt;li&gt;Instead of using &amp;#8220;git pull&amp;#8221; to fetch and merge changes from remote repository to local, use &amp;#8220;git-p4 rebase&amp;#8221;&lt;/li&gt;

&lt;li&gt;Instead of using &amp;#8220;git merge&amp;#8221; to merge local branches, use &amp;#8220;git rebase&amp;#8221;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the last one, the reason is that when you run &amp;#8220;git merge&amp;#8221;, Git creates an extra commit on top of the stack for the merging. This is not something we wanna show in the remote non-git repository. So we merge code with &amp;#8220;git rebase&amp;#8221;. Detailed explanation of the difference between git-merge and git-rebase goes &lt;a href='http://www.jarrodspillers.com/2009/08/19/git-merge-vs-git-rebase-avoiding-rebase-hell/'&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id='workflow'&gt;Workflow&lt;/h4&gt;

&lt;p&gt;There is a &lt;a href='https://github.com/git/git/blob/master/contrib/fast-import/git-p4.txt'&gt;detailed explanation&lt;/a&gt; on the usage of git-p4 in Git&amp;#8217;s source. Here is an example almost covering daily usage:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Login with &amp;#8220;p4 login&amp;#8221; and clone a Perforce project:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git-p4 clone //depot/path/project&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Make some changes to the project and commit locally to Git:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git commit changed_file&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;In the meantime somebody in the team submitted changes to the remote Perforce repository. Merge it to your local repository:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git-p4 rebase&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Submit your local changes back to Perforce:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git-p4 submit&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id='ignoring_the_gitignore_file'&gt;Ignoring the .gitignore file&lt;/h4&gt;

&lt;p&gt;Normally we check in a .gitignore file to ignore files that we don&amp;#8217;t want to check into the remote repository for each project. However, since the remote repository is not Git, it&amp;#8217;s meaningless to check in this .gitignore file. To ignore this file, simply add an entry to .git/info/exclude.&lt;/p&gt;

&lt;h4 id='under_the_hook'&gt;Under the hook&lt;/h4&gt;

&lt;p&gt;There is no magic happening with git-p4. What it does is simply invoking the p4 command line tool to download sources to local, and then clone a Git repository out of it. You can simply verify this by typing &amp;#8220;git branch -a&amp;#8221;:&lt;/p&gt;
&lt;div class='center'&gt;
&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/Terminal_%E2%80%94_%E2%8C%981-20110323-171241.jpg' alt='under the hook of git-p4' /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;You may be amazed once again by how flexible the design of Git is which makes it possible to bridge to multiple VCS!&lt;/p&gt;

&lt;h4 id='summary'&gt;Summary&lt;/h4&gt;

&lt;p&gt;To quote &lt;a href='http://martinfowler.com'&gt;Martin Fowler&lt;/a&gt;&amp;#8217;s &lt;a href='http://martinfowler.com/bliki/VersionControlTools.html'&gt;opinions&lt;/a&gt; on dual VCS, &amp;#8220;a lot of teams can benefit from this dual-VCS working style, particularly if there&amp;#8217;s a lot of corporate ceremony enforced by their corporate VCS. Using dual-VCS can often make both the local development team happier and the corporate controllers happier as their motivations for VCS are often different&amp;#8221;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=7aPhnpJXJ1U:6i8GfcJKCVg:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=7aPhnpJXJ1U:6i8GfcJKCVg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=7aPhnpJXJ1U:6i8GfcJKCVg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=7aPhnpJXJ1U:6i8GfcJKCVg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=7aPhnpJXJ1U:6i8GfcJKCVg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=7aPhnpJXJ1U:6i8GfcJKCVg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=7aPhnpJXJ1U:6i8GfcJKCVg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=7aPhnpJXJ1U:6i8GfcJKCVg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=7aPhnpJXJ1U:6i8GfcJKCVg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=7aPhnpJXJ1U:6i8GfcJKCVg:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=7aPhnpJXJ1U:6i8GfcJKCVg:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/7aPhnpJXJ1U" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2011/03/23/git-up-perforce-with-git-p4.html</feedburner:origLink></entry><entry><title type="text">Speed Up J2EE Environment Setup With Jetty Maven Plugin</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/rb03Z7pd1eY/speed-up-j2ee-environment-setup-with-jetty-maven-plugin.html" /><updated>2011-02-23T00:00:00-08:00</updated><id>http://owenou.com/2011/02/23/speed-up-j2ee-environment-setup-with-jetty-maven-plugin</id><content type="html">&lt;p&gt;Setting up a J2EE development environment is typically complex and full of repetition. It wastes a lot of programmers&amp;#8217; time before they can happily get the app up and running. They need to configure the IDE, set up the database, configure the server, deploy app to the server, etc.. What&amp;#8217;s worse, they have to repeat all the setup steps or a subset of the setup steps if they have multiple workspaces. I am not saying all of these steps are unnecessary. But can we just think for a moment why this is causing pain? How can we be &lt;a href='http://en.wikipedia.org/wiki/Don%27t_repeat_yourself'&gt;DRY&lt;/a&gt; in environment setup?&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s take a look at where other web frameworks such as &lt;a href='http://rubyonrails.org'&gt;Rails&lt;/a&gt; shine. If you carefully think about how you get a Rails app running, you will be surprised to find out almost no configuration is needed. And it&amp;#8217;s so automatic! Here is how it rolls:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; git clone &amp;lt;some_app&amp;gt;
&amp;gt; cd &amp;lt;some_app&amp;gt;
&amp;gt; bundle install
&amp;gt; rails server&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Boom! Your app is up with just 2 commands (ignoring the step to download the source)! The last command is especially interesting. It is to start up the Rails server with the app loaded. Can we do the same in the Java world? Of course, Maven + Jetty Maven Plugin.&lt;/p&gt;

&lt;h4 id='introducing_jetty_maven_plugin'&gt;Introducing Jetty Maven Plugin&lt;/h4&gt;

&lt;p&gt;Jetty is a web server and javax.servlet container. One of its greatest features is its ability to be embedded into any Java application. The Jetty Maven plugin is just a simple integration of Jetty into the Maven build process. But don&amp;#8217;t get it wrong, being embeddable doesn&amp;#8217;t mean being less performing. Jetty is actually the powering engine behind &lt;a href='http://code.google.com/appengine'&gt;Google App Engine&lt;/a&gt; and &lt;a href='http://www.zimbra.com'&gt;VMware Zimbra&lt;/a&gt;. After all, scalability is more related to your app&amp;#8217;s implementation than the container.&lt;/p&gt;

&lt;h4 id='running_a_single_web_app'&gt;Running a single web app&lt;/h4&gt;

&lt;p&gt;To run a single web app, it is as simple as including the Jetty Maven Plugin as a plugin dependency in your pom file and run the &amp;#8221;&lt;em&gt;mvn jetty:run&lt;/em&gt;&amp;#8221; command:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;project&lt;/span&gt; &lt;span class='na'&gt;xmlns=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;xmlns:xsi=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
&lt;span class='na'&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class='nt'&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;foo&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;foo&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;war&lt;span class='nt'&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;finalName&amp;gt;&lt;/span&gt;foo&lt;span class='nt'&gt;&amp;lt;/finalName&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
		&lt;span class='nt'&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mortbay.jetty&lt;span class='nt'&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jetty-maven-plugin&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;version&amp;gt;&lt;/span&gt;7.2.2.v20101205&lt;span class='nt'&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
		&lt;span class='nt'&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There are lots of useful &lt;a href='http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin'&gt;settings&lt;/a&gt; that you can fine-tune Jetty, such as &amp;#8220;scanIntervalSeconds&amp;#8221; for the time interval of automatic hot redeploy, &amp;#8220;systemProperties&amp;#8221; for System properties of the execution of the plugin, and &amp;#8220;jettyEnvXml&amp;#8221; for the file that defines JNDI bindings.&lt;/p&gt;

&lt;h4 id='running_a_single_web_app_with_jndi'&gt;Running a single web app with JNDI&lt;/h4&gt;

&lt;p&gt;In the case that you are defining data source using JNDI, you need to describe the data source in a &amp;#8220;jetty-env.xml&amp;#8221; file and refer it in the Jetty Maven Plugin. The jetty-env.xml file may look something like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='cp'&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class='cp'&gt;&amp;lt;!DOCTYPE Configure PUBLIC &amp;quot;-//Mort Bay Consulting//DTD Configure//EN&amp;quot; &amp;quot;http://jetty.mortbay.org/configure.dtd&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;Configure&lt;/span&gt; &lt;span class='na'&gt;class=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;org.eclipse.jetty.webapp.WebAppContext&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;New&lt;/span&gt; &lt;span class='na'&gt;id=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;jndi&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;class=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;org.eclipse.jetty.plus.jndi.Resource&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
		&lt;span class='nt'&gt;&amp;lt;Arg&amp;gt;&lt;/span&gt;jdbc/jndi&lt;span class='nt'&gt;&amp;lt;/Arg&amp;gt;&lt;/span&gt;
		&lt;span class='nt'&gt;&amp;lt;Arg&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;New&lt;/span&gt; &lt;span class='na'&gt;class=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;org.apache.commons.dbcp.BasicDataSource&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
				&lt;span class='nt'&gt;&amp;lt;Set&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;driverClassName&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;${db_connection_driver_class}&lt;span class='nt'&gt;&amp;lt;/Set&amp;gt;&lt;/span&gt;
				&lt;span class='nt'&gt;&amp;lt;Set&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;${db_connection_url}&lt;span class='nt'&gt;&amp;lt;/Set&amp;gt;&lt;/span&gt;
				&lt;span class='nt'&gt;&amp;lt;Set&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;${db_connection_username}&lt;span class='nt'&gt;&amp;lt;/Set&amp;gt;&lt;/span&gt;
				&lt;span class='nt'&gt;&amp;lt;Set&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;${db_connection_password}&lt;span class='nt'&gt;&amp;lt;/Set&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;/New&amp;gt;&lt;/span&gt;
		&lt;span class='nt'&gt;&amp;lt;/Arg&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;/New&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/Configure&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The pom.xml now becomes:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;project&lt;/span&gt; &lt;span class='na'&gt;xmlns=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;xmlns:xsi=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
&lt;span class='na'&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class='nt'&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;foo&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;foo&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;war&lt;span class='nt'&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;finalName&amp;gt;&lt;/span&gt;foo&lt;span class='nt'&gt;&amp;lt;/finalName&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
		&lt;span class='nt'&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mortbay.jetty&lt;span class='nt'&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jetty-maven-plugin&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;version&amp;gt;&lt;/span&gt;7.2.2.v20101205&lt;span class='nt'&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;webAppConfig&amp;gt;&lt;/span&gt;
				&lt;span class='nt'&gt;&amp;lt;jettyEnvXml&amp;gt;&lt;/span&gt;${basedir}/src/over/here/jetty-env.xml&lt;span class='nt'&gt;&amp;lt;/jettyEnvXml&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;/webAppConfig&amp;gt;&lt;/span&gt;		
		&lt;span class='nt'&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id='running_multiple_web_apps'&gt;Running multiple web apps&lt;/h4&gt;

&lt;p&gt;It&amp;#8217;s a bit tricky to run multiple web apps at once with the Jetty Maven Plugin. You need to have a running web app to delegate the requests. If you are using JNDI to define data source, you also need to configure your web apps to load up their environment settings.&lt;/p&gt;

&lt;p&gt;As an example, assuming you have two web apps &lt;strong&gt;foo&lt;/strong&gt; and &lt;strong&gt;bar&lt;/strong&gt;. They are organized in different Maven projects like the followings:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- pom.xml
- foo/
  - pom.xml
- bar/
  - pom.xml&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we wanna deploy both servers with the Jetty Maven Plugin, we need to either get foo running and delegate requests to bar, or the other way around. So it&amp;#8217;s a good practice to keep foo and bar untouched and introduce a third server to do the request delegation. The ultimate folder structure will look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- pom.xml
- foo/
  - pom.xml
- bar/
  - pom.xml
- servers/
  - pom.xml&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The servers project is basically an empty server with nothing but a web.xml. In its pom file, we define the redirection path and make sure it loads up settings such as JNDI for each web app:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;project&lt;/span&gt; &lt;span class='na'&gt;xmlns=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;xmlns:xsi=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
&lt;span class='na'&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;	
&lt;span class='nt'&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class='nt'&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;mavenJettyPluginExample&lt;span class='nt'&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;parent&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class='nt'&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;servers&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;war&lt;span class='nt'&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;servers&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;finalName&amp;gt;&lt;/span&gt;servers&lt;span class='nt'&gt;&amp;lt;/finalName&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
		&lt;span class='nt'&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mortbay.jetty&lt;span class='nt'&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jetty-maven-plugin&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
			&lt;span class='nt'&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
				&lt;span class='nt'&gt;&amp;lt;contextHandlers&amp;gt;&lt;/span&gt;            
					&lt;span class='nt'&gt;&amp;lt;contextHandler&lt;/span&gt; &lt;span class='na'&gt;implementation=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;org.eclipse.jetty.webapp.WebAppContext&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
						&lt;span class='nt'&gt;&amp;lt;contextPath&amp;gt;&lt;/span&gt;/foo&lt;span class='nt'&gt;&amp;lt;/contextPath&amp;gt;&lt;/span&gt;
						&lt;span class='nt'&gt;&amp;lt;resourceBase&amp;gt;&lt;/span&gt;${basedir}/../foo/target/foo&lt;span class='nt'&gt;&amp;lt;/resourceBase&amp;gt;&lt;/span&gt;
						&lt;span class='nt'&gt;&amp;lt;configurationClasses&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.WebInfConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.WebXmlConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.MetaInfConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.FragmentConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.plus.webapp.EnvConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.plus.webapp.PlusConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.JettyWebXmlConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.TagLibConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
						&lt;span class='nt'&gt;&amp;lt;/configurationClasses&amp;gt;&lt;/span&gt;
					&lt;span class='nt'&gt;&amp;lt;/contextHandler&amp;gt;&lt;/span&gt;
					&lt;span class='nt'&gt;&amp;lt;contextHandler&lt;/span&gt; &lt;span class='na'&gt;implementation=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;org.eclipse.jetty.webapp.WebAppContext&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
						&lt;span class='nt'&gt;&amp;lt;contextPath&amp;gt;&lt;/span&gt;/bar&lt;span class='nt'&gt;&amp;lt;/contextPath&amp;gt;&lt;/span&gt;
						&lt;span class='nt'&gt;&amp;lt;resourceBase&amp;gt;&lt;/span&gt;${basedir}/../bar/target/bar&lt;span class='nt'&gt;&amp;lt;/resourceBase&amp;gt;&lt;/span&gt;
						&lt;span class='nt'&gt;&amp;lt;configurationClasses&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.WebInfConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.WebXmlConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.MetaInfConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.FragmentConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.plus.webapp.EnvConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.plus.webapp.PlusConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.JettyWebXmlConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
							&lt;span class='nt'&gt;&amp;lt;configurationClass&amp;gt;&lt;/span&gt;org.eclipse.jetty.webapp.TagLibConfiguration&lt;span class='nt'&gt;&amp;lt;/configurationClass&amp;gt;&lt;/span&gt;
						&lt;span class='nt'&gt;&amp;lt;/configurationClasses&amp;gt;&lt;/span&gt;
					&lt;span class='nt'&gt;&amp;lt;/contextHandler&amp;gt;&lt;/span&gt;
				&lt;span class='nt'&gt;&amp;lt;/contextHandlers&amp;gt;&lt;/span&gt;  
			&lt;span class='nt'&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
		&lt;span class='nt'&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
	&lt;span class='nt'&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The &amp;#8220;resourceBase&amp;#8221; of each web app is set to its corresponding target folder. That means we have to compile the web app before running them. The &amp;#8220;contextPath&amp;#8221; is to tell Jetty the path of the web app. The list of &amp;#8220;configurationClasses&amp;#8221; is to tell Jetty to load corresponding configurations including the jetty-env.xml file for JNDI definition.&lt;/p&gt;

&lt;p&gt;Again, running &amp;#8221;&lt;em&gt;mvn jetty:run&lt;/em&gt;&amp;#8221; will start up these two servers at once.&lt;/p&gt;

&lt;h4 id='summary'&gt;Summary&lt;/h4&gt;

&lt;p&gt;As you may see, after setting up Jetty in the build process, we are able to start up the server with just one command. It speeds up the setup of our development environment and free ourselves from repeating the setup steps in the future. Most importantly, your teammates will thank you for saving a lot of their precious time.&lt;/p&gt;

&lt;p&gt;The source code of the example is available here: &lt;a href='https://github.com/jingweno/maven_jetty_plugin_example'&gt;https://github.com/jingweno/maven_jetty_plugin_example&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=rb03Z7pd1eY:05ajYYgDNOw:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=rb03Z7pd1eY:05ajYYgDNOw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=rb03Z7pd1eY:05ajYYgDNOw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=rb03Z7pd1eY:05ajYYgDNOw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=rb03Z7pd1eY:05ajYYgDNOw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=rb03Z7pd1eY:05ajYYgDNOw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=rb03Z7pd1eY:05ajYYgDNOw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=rb03Z7pd1eY:05ajYYgDNOw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=rb03Z7pd1eY:05ajYYgDNOw:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=rb03Z7pd1eY:05ajYYgDNOw:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=rb03Z7pd1eY:05ajYYgDNOw:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/rb03Z7pd1eY" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2011/02/23/speed-up-j2ee-environment-setup-with-jetty-maven-plugin.html</feedburner:origLink></entry><entry><title type="text">Agile is an adjective, not a noun!</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/ZsIQZaMEfXw/agile-is-an-adjective-not-a-noun.html" /><updated>2011-02-07T00:00:00-08:00</updated><id>http://owenou.com/2011/02/07/agile-is-an-adjective-not-a-noun</id><content type="html">&lt;p&gt;&lt;a href='http://twitter.com/pragdave'&gt;Dave Thomas&lt;/a&gt; was right, &lt;a href='http://pragprog.com/magazines/2011-02/agile--'&gt;there’s a growing tendency to treat the word &amp;#8220;Agile&amp;#8221; as a noun&lt;/a&gt;. Being an agile software developer means doing things in an agile manner, not just naming things that you do &amp;#8220;Agile&amp;#8221;. Being an agile software developer means persisting your agile way of doing things, not compromising it in any case. Being an agile software developer means evangelizing your core values, not isolating your agile self.&lt;/p&gt;

&lt;p&gt;If you miss any of these, you are just fooling yourself.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=ZsIQZaMEfXw:AXgKOs6Ruzg:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=ZsIQZaMEfXw:AXgKOs6Ruzg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=ZsIQZaMEfXw:AXgKOs6Ruzg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=ZsIQZaMEfXw:AXgKOs6Ruzg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=ZsIQZaMEfXw:AXgKOs6Ruzg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=ZsIQZaMEfXw:AXgKOs6Ruzg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=ZsIQZaMEfXw:AXgKOs6Ruzg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=ZsIQZaMEfXw:AXgKOs6Ruzg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=ZsIQZaMEfXw:AXgKOs6Ruzg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=ZsIQZaMEfXw:AXgKOs6Ruzg:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=ZsIQZaMEfXw:AXgKOs6Ruzg:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/ZsIQZaMEfXw" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2011/02/07/agile-is-an-adjective-not-a-noun.html</feedburner:origLink></entry><entry><title type="text">Running a single JUnit test in Eclipse</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/HJCeHs9zTLo/running-a-single-junit-test-in-eclipse.html" /><updated>2011-02-05T00:00:00-08:00</updated><id>http://owenou.com/2011/02/05/running-a-single-junit-test-in-eclipse</id><content type="html">&lt;p&gt;A lot of the test-driven developers may find it annoying to run a single JUnit test in Eclipse: if there is a test suite with multiple tests, when running a single unit test, either from the context menu of the code editor, or from the JUnit view, Eclipse seems to always insist on running the entire suite, rather than the single test.&lt;/p&gt;

&lt;p&gt;Like the example below, running &lt;em&gt;testOne&lt;/em&gt; will trigger running the rest of the tests in the suite which are grouped under the &amp;#8221;&lt;strong&gt;Unrooted Tests&lt;/strong&gt;&amp;#8221; node. This is quite irritating sometimes since running unexpected tests may slow down the workflow if they take time to finish. It&amp;#8217;s also quite confusing since programmers get unwanted test results. Some of my coworkers solve this problem by commenting out unwanted tests each time before running a test. However, it&amp;#8217;s not very effective and it&amp;#8217;s error-prone.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/a_single_test_triggers_multiple_tests-20110213-233120.jpg' alt='A single test triggers multiple tests' /&gt;&lt;/p&gt;

&lt;p&gt;This happens mainly because we are running JUnit 3 tests with the JUnit 4 runner. Before version 4.6, the &lt;a href='https://github.com/KentBeck/junit/blob/r4.6/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java'&gt;JUnit 4 runner&lt;/a&gt; seems to have the problem of falling back to run a single JUnit 3 test.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/running_junit3_with_junit4_runner-20110213-233707.jpg' alt='Running JUnit 3 tests with JUnit 4 runner' /&gt;&lt;/p&gt;

&lt;p&gt;So&amp;#8230;the solution is quite simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;change the JUnit runner to JUnit 3 in Eclipse&lt;/strong&gt;, or&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;upgrade your JUnit 4 library to 4.6 or higher&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now the problem is gone and the test-driven developers are happy :-).&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=HJCeHs9zTLo:BDX9-JibKRs:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=HJCeHs9zTLo:BDX9-JibKRs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=HJCeHs9zTLo:BDX9-JibKRs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=HJCeHs9zTLo:BDX9-JibKRs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=HJCeHs9zTLo:BDX9-JibKRs:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=HJCeHs9zTLo:BDX9-JibKRs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=HJCeHs9zTLo:BDX9-JibKRs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=HJCeHs9zTLo:BDX9-JibKRs:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=HJCeHs9zTLo:BDX9-JibKRs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=HJCeHs9zTLo:BDX9-JibKRs:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=HJCeHs9zTLo:BDX9-JibKRs:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/HJCeHs9zTLo" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2011/02/05/running-a-single-junit-test-in-eclipse.html</feedburner:origLink></entry><entry><title type="text">Loading Path Gotchas in Rails 3</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/9J0R2TXMcI0/loading-path-gotchas-in-rails3.html" /><updated>2011-01-20T00:00:00-08:00</updated><id>http://owenou.com/2011/01/20/loading-path-gotchas-in-rails3</id><content type="html">&lt;p&gt;The algorithm of load path inferring in Rails 3 is a bit weird when class caching is turned off. Assuming you add all subdirectories under app/models to the load paths by using the new &amp;#8220;config.autoload_paths&amp;#8221; setting in config/application.rb:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;autoload_paths&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='no'&gt;Dir&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;root&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/app/models/**/&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And you have a subdirectory under app/models with name class1 and a file under this subdirectory with the same name class1.rb. When you are referring any classes in class1.rb under this subdirectory, you have to make sure they are in the namespace of Class1. Otherwise Rails will complain about your referred class is not in the namespace of Class1. In more details, if you have a directory structure like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- app
  - models
    - class1
      - class1.rb
      - class1_reference.rb&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you refer to Class1Reference in Class1, you will get &amp;#8221;&lt;strong&gt;Expected app/models/class1/class1_reference.rb to define Class1::Class1Reference&lt;/strong&gt;&amp;#8221;. If the subdirectory is not named class1, strangely this example will work&amp;#8230; Let&amp;#8217;s take a look at a comparing directory structure:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- app
  - models
    - not_class2
      - class2.rb
      - class2_reference.rb&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This second example have everything the same as the first one (Class2 referring to Class2Reference) except that the subdirectory name (not_class2) is different from the file name (class2.rb). There is no exception raised and everything works as expected.&lt;/p&gt;

&lt;p&gt;The result indicates either a (strange) directory naming convention in Rails 3 or a potential bug in its path inferring algorithm. Here are the &lt;a href='https://github.com/rails/rails/blob/master/activesupport/lib/active_support/dependencies.rb'&gt;lines&lt;/a&gt; in Rails 3 that does the magic:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# Load the constant named +const_name+ which is missing from +from_mod+. If&lt;/span&gt;
&lt;span class='c1'&gt;# it is not possible to load the constant into from_mod, try its parent module&lt;/span&gt;
&lt;span class='c1'&gt;# using const_missing.&lt;/span&gt;
&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;load_missing_constant&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;from_mod&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;const_name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;

  &lt;span class='n'&gt;file_path&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;search_for_file&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;path_suffix&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;file_path&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt; &lt;span class='n'&gt;loaded&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;include?&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;expand_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;file_path&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='c1'&gt;# We found a matching file to load&lt;/span&gt;
    &lt;span class='n'&gt;require_or_load&lt;/span&gt; &lt;span class='n'&gt;file_path&lt;/span&gt;
    &lt;span class='k'&gt;raise&lt;/span&gt; &lt;span class='no'&gt;LoadError&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Expected &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;file_path&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; to define &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;qualified_name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;unless&lt;/span&gt; &lt;span class='n'&gt;local_const_defined?&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;from_mod&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;const_name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;from_mod&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;const_get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;const_name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;elsif&lt;/span&gt; 
	&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Please note that if class caching is turned on, both cases work. Now everything becomes quite clear, the line with &amp;#8220;unless&amp;#8221; after the &amp;#8220;raise&amp;#8221; is causing the problem: when class caching is turned off, &amp;#8220;local_const_defined?&amp;#8221; always returns false hence raising the &amp;#8220;LoadError&amp;#8221;. I have created a &lt;a href='https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/6320-autoloading-behaves-weird-when-class-caching-is-turned-off'&gt;bug report&lt;/a&gt; on this issue and I will post replies here once I get anything :).&lt;/p&gt;

&lt;p&gt;The code of the two examples above are available &lt;a href='https://github.com/jingweno/loading_path_gotchas_in_rails3/tree/master/app/models'&gt;here&lt;/a&gt;. It has a simple view to display the output of the load path exception. To get started, just run:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; bundle install
&amp;gt; rails server&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And check two pages: &lt;a href='http://localhost:3000/class1'&gt;http://localhost:3000/class1&lt;/a&gt; and &lt;a href='http://localhost:3000/class2'&gt;http://localhost:3000/class2&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9J0R2TXMcI0:uSUOYjdY16c:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9J0R2TXMcI0:uSUOYjdY16c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=9J0R2TXMcI0:uSUOYjdY16c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9J0R2TXMcI0:uSUOYjdY16c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9J0R2TXMcI0:uSUOYjdY16c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9J0R2TXMcI0:uSUOYjdY16c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=9J0R2TXMcI0:uSUOYjdY16c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9J0R2TXMcI0:uSUOYjdY16c:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9J0R2TXMcI0:uSUOYjdY16c:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=9J0R2TXMcI0:uSUOYjdY16c:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=9J0R2TXMcI0:uSUOYjdY16c:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/9J0R2TXMcI0" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2011/01/20/loading-path-gotchas-in-rails3.html</feedburner:origLink></entry><entry><title type="text">Planning for CodeFaces 1.1.1</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/XQOFcvHUC3k/planning_for_codefaces.html" /><updated>2010-09-21T00:00:00-07:00</updated><id>http://owenou.com/2010/09/21/planning_for_codefaces</id><content type="html">&lt;p&gt;For the pass couple months, amazing things have happened to &lt;a href='http://codefaces.org'&gt;CodeFaces&lt;/a&gt;: it has enough features and scalability to go live, it was listed as a demo app on Eclipse RAP&amp;#8217;s &lt;a href='http://www.eclipse.org/rap/demos'&gt;demo page&lt;/a&gt;, good feedback has been heard after people using it, and constant feature requests have been documented and pushed to our backlog. That&amp;#8217;s pretty encouraging both to me and to the &lt;a href='http://blog.codefaces.org/about/'&gt;CodeFaces Team&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In case you haven&amp;#8217;t know, CodeFaces is a web-based source control client that targets at easing the pain of navigating codes from a source control system on a browser. It allows connecting to multiple source control systems and structurally navigating codes on a unified web interface.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s nice to see a potential community growing and we decided to continue making cool stuff happen. We have already marked down what you asked for: file searching, connecting to private repositories, flat structure on showing the folder trees, etc.. Right now we are on our way to the next CodeFaces release (v1.1.1). This release will be a maintenance one and the main theme is bug fixing, performance tuning and minor feature upgrade. We will soon scope it down in our issue tracker and open to everybody. Do not hesitate to ask us for new features. We greatly appreciate it! :)&lt;/p&gt;

&lt;p&gt;Happy code navigating!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=XQOFcvHUC3k:rJQjrA92XVA:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=XQOFcvHUC3k:rJQjrA92XVA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=XQOFcvHUC3k:rJQjrA92XVA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=XQOFcvHUC3k:rJQjrA92XVA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=XQOFcvHUC3k:rJQjrA92XVA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=XQOFcvHUC3k:rJQjrA92XVA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=XQOFcvHUC3k:rJQjrA92XVA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=XQOFcvHUC3k:rJQjrA92XVA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=XQOFcvHUC3k:rJQjrA92XVA:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=XQOFcvHUC3k:rJQjrA92XVA:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=XQOFcvHUC3k:rJQjrA92XVA:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/XQOFcvHUC3k" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2010/09/21/planning_for_codefaces.html</feedburner:origLink></entry><entry><title type="text">How to set up and run PDE build</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/6xsOjyZQgC8/how-to-set-up-and-run-pde-build.html" /><updated>2010-09-19T00:00:00-07:00</updated><id>http://owenou.com/2010/09/19/how-to-set-up-and-run-pde-build</id><content type="html">&lt;p&gt;The &lt;a href='http://www.eclipse.org/pde/'&gt;Plug-in Development Environment&lt;/a&gt; (PDE) provides tools to build Eclipse plug-ins, fragments, features, update sites and RCP products. This post is about how to set up and run the PDE &lt;a href='http://wiki.eclipse.org/index.php/PDEBuild'&gt;headless build&lt;/a&gt;. Headless build means making the build outside the Eclipse IDE. You can also manually build it inside Eclipse with &lt;a href='http://www.eclipse.org/articles/Article-PDE-Automation/automation.html'&gt;its GUI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before running the PDE build, you need to set up the followings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build directory&lt;/li&gt;

&lt;li&gt;target platform&lt;/li&gt;

&lt;li&gt;build configuration file&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id='build_directory'&gt;Build directory&lt;/h4&gt;

&lt;p&gt;The first step in setting up a build is to create the directory in which the build will take place. Next, create two subdirectories called &amp;#8221;&lt;em&gt;plugins&lt;/em&gt;&amp;#8221; and &amp;#8221;&lt;em&gt;features&lt;/em&gt;&amp;#8221;, and copy the plug-ins and features that you want to build respectively into these two folders. The directory structure for the build directory should look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- build_directory
    - plugins
        - plugin_to_build_a
        - plugin_to_build_b
        - ...
    - features
        - feature_to_build
        - ...&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id='target_platform'&gt;Target platform&lt;/h4&gt;

&lt;p&gt;Features and plugins are compiled and run against a set of pre-built features and plugins. These dependencies constitute the target platform. For example, most RCP applications contribute to the UI by depending on the &lt;em&gt;org.eclipse.ui&lt;/em&gt; plug-in.&lt;/p&gt;

&lt;p&gt;In this step, you also need to create a directory with two subdirectories called &amp;#8221;&lt;em&gt;plugins&lt;/em&gt;&amp;#8221; and &amp;#8221;&lt;em&gt;features&lt;/em&gt;&amp;#8221;, and copy all the dependencies over. For developing RCP applications for multiple platforms, the &lt;a href='http://archive.eclipse.org/eclipse/downloads/drops/S-3.6RC4-201006031500/index.php#DeltaPack'&gt;RCP delta pack&lt;/a&gt; is a good option since it contains all the platform specific fragments from the Eclipse SDK. Download the delta pack and unzip it, then you finish setting up the target platform :). The directory structure for the target platform should look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- target_platform
    - plugins
        - org.eclipse.core.runtime
        - org.eclipse.ui
        - ...
    - features
        - org.eclipse.equinox.launcher
        - ...&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id='build_configuration_file'&gt;Build configuration file&lt;/h4&gt;

&lt;p&gt;After setting up the directory structure for the plugins/features to build and the target platform, we need to tell PDE how we want the build. We can configure it by adding a &lt;em&gt;build.properties&lt;/em&gt; file. The template of this file is available in any Eclipse distribution:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#{eclipseInstall}/plugins/org.eclipse.pde.build_#{version}/templates/headless-build/build.properties&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create a directory for the configuration file, copy the template file over, comment out unnecessary properties in the template file. The directory structure should look something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- build_config
    - build.properties &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;PDE build provides &lt;a href='http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse.pde.doc.user/tasks/pde_feature_generating_antcommandline.htm'&gt;a variety of properties&lt;/a&gt; that we can configure for the build, from checking out source from CVS to controlling the whole build lifecycle. In this post, we only discuss the most essential ones:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;topLevelElementType: feature or plugin
topLevelElementId: the id of the top level element we are building
archivePrefix: the prefix that will be used in the generated archive
collectingFolder: the location under which all of the build output will be collected
configs: the list of {os, ws, arch} configurations to build&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id='running_pde_build'&gt;Running PDE build&lt;/h4&gt;

&lt;p&gt;If you have followed me this far, you should have the following directory structure ready:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- build_directory
    - plugins
        - plugin_to_build_a
        - plugin_to_build_b
        - ...
    - features
        - feature_to_build
        - ...
- target_platform
    - plugins
        - org.eclipse.core.runtime
        - org.eclipse.ui
        - ...
    - features
        - org.eclipse.equinox.launcher
        - ...
- build_config
    - build.properties&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Open up a terminal, type in:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;java -jar #{eclipseInstall}/plugins/org.eclipse.equinox.launcher_#{version}.jar
     -application org.eclipse.ant.core.antRunner
     -buildfile #{eclipseInstall}/plugins/org.eclipse.pde.build_#{version}/scripts/build.xml
     -DbuildDirectory=#{path_to_the_build_directory}
     -DbaseLocation=#{path_to_the_target_platform_directory}
     -Dbuilder=#{path_to_the_build_configuration_directory}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should see PDE starts building :).&lt;/p&gt;

&lt;h4 id='summary'&gt;Summary&lt;/h4&gt;

&lt;p&gt;Setting up the PDE build looks scary at first, but once you understand &lt;a href='http://www.eclipse.org/equinox/'&gt;Equinox&lt;/a&gt; a little bit more, you will find everything make a lot of sense. All you need to get it to run is creating the directory structure for the plug-ins/features to build and their dependencies, and configuring some properties. The directory structure, probably as you have already realized, is Equinox&amp;#8217;s &lt;a href='http://en.wikipedia.org/wiki/Convention_over_configuration'&gt;convention&lt;/a&gt; of managing components.&lt;/p&gt;

&lt;p&gt;You can also set up &lt;a href='http://ant.apache.org/'&gt;Ant&lt;/a&gt; tasks or &lt;a href='http://rake.rubyforge.org/'&gt;Rake&lt;/a&gt; tasks to automate the whole process. Like the exercise that I have done lately, I used Rake to automate the PDE build for the Eclipse &lt;a href='http://sourceforge.net/projects/fitpro/'&gt;FITPro&lt;/a&gt; plugin. The source is available here: &lt;a href='https://fitpro.svn.sourceforge.net/svnroot/fitpro/Eclipse/trunk/com.luxoft.eclipse.fit.runner.releng/'&gt;https://fitpro.svn.sourceforge.net/svnroot/fitpro/Eclipse/trunk/com.luxoft.eclipse.fit.runner.releng/&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=6xsOjyZQgC8:5oF3cM8Z0nA:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=6xsOjyZQgC8:5oF3cM8Z0nA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=6xsOjyZQgC8:5oF3cM8Z0nA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=6xsOjyZQgC8:5oF3cM8Z0nA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=6xsOjyZQgC8:5oF3cM8Z0nA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=6xsOjyZQgC8:5oF3cM8Z0nA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=6xsOjyZQgC8:5oF3cM8Z0nA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=6xsOjyZQgC8:5oF3cM8Z0nA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=6xsOjyZQgC8:5oF3cM8Z0nA:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=6xsOjyZQgC8:5oF3cM8Z0nA:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=6xsOjyZQgC8:5oF3cM8Z0nA:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/6xsOjyZQgC8" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2010/09/19/how-to-set-up-and-run-pde-build.html</feedburner:origLink></entry><entry><title type="text">Patching with Class Shadowing and Maven</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/wILEWYyHJ98/patching-with-class-shadowing-and-maven.html" /><updated>2010-07-20T00:00:00-07:00</updated><id>http://owenou.com/2010/07/20/patching-with-class-shadowing-and-maven</id><content type="html">&lt;p&gt;Before we start, you may speculate about the usefulness of &lt;a href='http://mindprod.com/jgloss/shadow.html'&gt;class shadowing&lt;/a&gt;. Class shadowing can be used as a trick to patch or replace behaviours of classes at runtime, taking advantage of the first-come first-served algorithm of Java’s class loader. If there are more than one class with the same fully qualified name in the Java class loader, the first one that shows up always take precedence over the rest.&lt;/p&gt;

&lt;p&gt;This is extremely useful in some cases. For example, in order to make some out-of-the-box (OOTB) methods extensible without directly changing the source, or to provide backward-compatibility support, class shadowing is a good technique to separate the OOTB code and the customized code. By creating a patch jar against the OOTB jar and putting it before the OOTB jar on classpath, classes with the same qualified name are merged at runtime.&lt;/p&gt;

&lt;p&gt;Class shadowing is only one way of patching a class. It’s based on class loader’s runtime class resolution. Another way is to use class overlay. For example, the Maven &lt;a href='http://maven.apache.org/plugins/maven-war-plugin/examples/war-overlay.html'&gt;war overlays plugin&lt;/a&gt; expands the war file and copy them on top of the host classes.&lt;/p&gt;

&lt;p&gt;If you are already familiar with OSGi based technology, &lt;a href='http://wiki.eclipse.org/FAQ_Can_fragments_be_used_to_patch_a_plug-in%3F'&gt;patch fragment&lt;/a&gt; is actually taking advantage of the class shadowing mechanism. This post is not targeting at building OSGi application but at standard Maven project.&lt;/p&gt;

&lt;p&gt;To instruct Java’s class loader to load jars in a specific order, we can make use of the “-cp” option. For example,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;java -cp patch.jar ootb.jar -jar main.jar&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It tells the class loader that patch.jar is loaded before ootb.jar, hence any classes in patch.jar is overriding the ones in ootb.jar. Besides, we can also make use of the Class-Path attribute of the &lt;a href='http://download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/guide/jar/jar.html#JAR%20Manifest'&gt;jar manifest&lt;/a&gt; to specify the classpath. We will adopt this method in the follow-up example.&lt;/p&gt;

&lt;p&gt;Here is an example we are going to build. HelloWorldProxy is a &lt;em&gt;proxy&lt;/em&gt; artifact that exports its classpath in such an order that classes in HelloWorldPatch are replacing classes in HelloWorld. HelloWorldTest depends on HelloWorldProxy and doesn’t know which implementation (HelloWorld or HelloWorldPatch) HelloWorldProxy is exporting. The dependency graph is as followed:&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/maven_example_dep-20110213-233540.jpg' height='245' alt='example dependency' width='447' /&gt;&lt;/p&gt;

&lt;p&gt;In the pom.xml of HelloWorldProxy, it has two dependencies and we put HelloWorldPatch before HelloWorld, since we would like to see classes in HelloWorldPatch replacing the ones in HelloWorld. As of Maven 2.0.9, the ordering of dependencies on the classpath is &lt;a href='http://stackoverflow.com/questions/793054/maven-classpath-order-issues'&gt;preserved&lt;/a&gt;. The code snippet is as followed:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;HelloWorld&lt;span class='nt'&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;HelloWorldPatch&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class='nt'&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;type&amp;gt;&lt;/span&gt;jar&lt;span class='nt'&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;compile&lt;span class='nt'&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;HelloWorld&lt;span class='nt'&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;HelloWorld&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class='nt'&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;type&amp;gt;&lt;/span&gt;jar&lt;span class='nt'&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;compile&lt;span class='nt'&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We also need to make sure HelloWorldProxy exports the two jars in the Class-Path attribute of the MANIFEST.MF file with the correct ordering. The key is to set the &lt;a href='http://maven.apache.org/shared/maven-archiver/examples/classpath.html'&gt;addClasspath&lt;/a&gt; flag to true in the maven-jar-plugin:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class='nt'&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-jar-plugin&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.3.1&lt;span class='nt'&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;archive&amp;gt;&lt;/span&gt;
            &lt;span class='nt'&gt;&amp;lt;manifest&amp;gt;&lt;/span&gt;
                &lt;span class='nt'&gt;&amp;lt;addClasspath&amp;gt;&lt;/span&gt;true&lt;span class='nt'&gt;&amp;lt;/addClasspath&amp;gt;&lt;/span&gt;
            &lt;span class='nt'&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;/archive&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Run “mvn package” in HelloWorldProxy and take a look at the generated MANIFEST.MF:&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/maven_manifest-20110213-233556.jpg' height='102' alt='manifest' width='594' /&gt;&lt;/p&gt;

&lt;p&gt;Voila! That’s what we expect! HelloWorldPatch takes precedence over HelloWorld on HelloWorldProxy’s classpath!&lt;/p&gt;

&lt;p&gt;Now HelloWorldTest can safely depends on HelloWorldProxy and expects that HelloWorldProxy will export HelloWorldPatch’s implementations at runtime:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;HelloWorld&lt;span class='nt'&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;HelloWorldProxy&lt;span class='nt'&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class='nt'&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;type&amp;gt;&lt;/span&gt;jar&lt;span class='nt'&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;compile&lt;span class='nt'&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The source of this example is available on GitHub &lt;a href='http://github.com/jingweno/patching_with_class_shadowing_and_maven'&gt;http://github.com/jingweno/patching_with_class_shadowing_and_maven&lt;/a&gt;. You can also view it directly with CodeFaces &lt;a href='http://codefaces.org/http://github.com/jingweno/patching_with_class_shadowing_and_maven'&gt;http://codefaces.org/http://github.com/jingweno/patching_with_class_shadowing_and_maven&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=wILEWYyHJ98:z3szBrxcbN4:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=wILEWYyHJ98:z3szBrxcbN4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=wILEWYyHJ98:z3szBrxcbN4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=wILEWYyHJ98:z3szBrxcbN4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=wILEWYyHJ98:z3szBrxcbN4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=wILEWYyHJ98:z3szBrxcbN4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=wILEWYyHJ98:z3szBrxcbN4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=wILEWYyHJ98:z3szBrxcbN4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=wILEWYyHJ98:z3szBrxcbN4:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=wILEWYyHJ98:z3szBrxcbN4:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=wILEWYyHJ98:z3szBrxcbN4:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/wILEWYyHJ98" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2010/07/20/patching-with-class-shadowing-and-maven.html</feedburner:origLink></entry><entry><title type="text">Introducing Eclipse RAP</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/LAR6H7ch4bs/introducing-eclipse-rap.html" /><updated>2010-07-08T00:00:00-07:00</updated><id>http://owenou.com/2010/07/08/introducing-eclipse-rap</id><content type="html">&lt;p&gt;RAP, what? The Eclipse community is expanding its range to Hip Hop :)? Not exactly, although there is a chance. &lt;a href='http://eclipse.org/rap/'&gt;Eclipse Rich Ajax Platform&lt;/a&gt; (RAP) is a framework that empowers developers to build rich web clients “the Eclipse way.” From the latest &lt;a href='http://www.eclipse.org/downloads/'&gt;Helios download&lt;/a&gt;, RAP Tooling has become a default component of the RCP bundle:&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/rap_download-20110213-233700.jpg' height='37' alt='Eclipse rap download' width='463' /&gt;&lt;/p&gt;

&lt;p&gt;So what exactly is the Eclipse paradigm? Can we benefit from it?&lt;/p&gt;

&lt;h4 id='architecture'&gt;Architecture&lt;/h4&gt;

&lt;p&gt;RAP is to the web as RCP to the desktop. It inherits all the goodness from RCP such as workbench extension points model, event-driven SWT/JFace APIs, and componentized OSGi design. As indicated below, the only difference between the architecture of RAP and that of RCP is the implementation of SWT/RWT. RWT is actually a bundle providing web-specific implementation of SWT’s widgets based on the &lt;a href='http://qooxdoo.org/'&gt;qooxdoo&lt;/a&gt; toolkit. In RAP, almost no SWT API is changed.&lt;/p&gt;

&lt;p&gt;The following is the architecture of RAP:&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/rap_archi-20110213-233655.jpg' height='158' alt='rap architecture' width='521' /&gt;&lt;/p&gt;

&lt;p&gt;This architecture determines that developers can bring their RCP applications to the web with a single code base, also called single sourcing&lt;sup id='fnref:1'&gt;&lt;a href='#fn:1' rel='footnote'&gt;1&lt;/a&gt;&lt;/sup&gt;. Like building a RCP application, building a RAP application is a process of building plug-ins and bundles: On the UI side, contributing widget plug-ins; On the server side, since it is powered by &lt;a href='http://www.eclipse.org/equinox/server/'&gt;server-side Equinox&lt;/a&gt;, contributing servlet plug-ins. Unsurprisingly, it also inherits the benefits of any OSGi application such as dynamically adding/removing bundles.&lt;/p&gt;

&lt;p&gt;This architecture also determines that RAP is a server-centric AJAX framework&lt;sup id='fnref:2'&gt;&lt;a href='#fn:2' rel='footnote'&gt;2&lt;/a&gt;&lt;/sup&gt;. As indicated below, in a server-centric framework, the application is hosted on the application server and all processing is done on the server. The client browser is only used for data presentation. Consequently, it leaves small footprints on browsers: it waits for instructions from the server to create corresponding widgets on demand. In contrast, client-centric framework such as GWT statically compiles all widgets beforehand.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/server_centric_client_centric-20110213-233714.jpg' height='331' alt='server centric vs client centric' width='468' /&gt;&lt;/p&gt;

&lt;p&gt;Both methods have pros and cons. Server-centric frameworks handle all communication automatically and leaves as few JavaScript codes on the browsers as possible, hence potentially having less security holes on the browsers. Client-centric frameworks are more flexible but require more work to step deep into low-level implementations of client-to-server communication, e.g., figuring out how to update widgets effectively in an asynchronous callback.&lt;/p&gt;

&lt;h4 id='ui_testing'&gt;UI Testing&lt;/h4&gt;

&lt;p&gt;For a Java-based rich AJAX application, while server side can be tested with JUnit, testing UI is always a headache. Like GWT, testing UI has to rely on external JavaScript libraries such as &lt;a href='http://www.jsunit.net/'&gt;JsUnit&lt;/a&gt;. But for RAP, since it’s server-centric, UI code can be tested using JUnit with the special &lt;a href='http://www.eclipse.org/rap/noteworthy/1.1/news_M4.php#Tooling'&gt;RAPTestCase&lt;/a&gt;. Moreover, since the workbench APIs haven’t been changed, all existing SWT testing tools can be reused, e.g., &lt;a href='http://seleniumhq.org/'&gt;Selenium&lt;/a&gt; or &lt;a href='http://www.eclipse.org/swtbot/'&gt;SWTBot&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id='performance'&gt;Performance&lt;/h4&gt;

&lt;p&gt;In general, RAP pushes more work off the client onto the server, thus communicating more information and more frequently with the server. Some performance testings were available&lt;sup id='fnref:3'&gt;&lt;a href='#fn:3' rel='footnote'&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h4 id='deployment'&gt;Deployment&lt;/h4&gt;

&lt;p&gt;RAP is extremely easy to deploy on an OSGi based server &lt;sup id='fnref:4'&gt;&lt;a href='#fn:4' rel='footnote'&gt;4&lt;/a&gt;&lt;/sup&gt;, e.g., &lt;a href='http://www.springsource.org/osgi'&gt;Spring dm server&lt;/a&gt; which has moved to the &lt;a href='http://www.eclipse.org/proposals/virgo/'&gt;Eclipse Virgo&lt;/a&gt; project, because its server side implementation bases on the http OSGi standard. Deploying to a traditional J2EE such as Tomcat requires packaging an extra &amp;#8221;&lt;a href='http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.equinox/server-side/bundles/org.eclipse.equinox.servletbridge/?root=RT_Project'&gt;Servlet Bridge&lt;/a&gt;&amp;#8221; into the war. A drawback of RAP is that it can’t be deployed to a &lt;em&gt;plain&lt;/em&gt; web server such as Apache. You can do this to a GWT-based application without RPC and the generated JavaScript codes will still work fine on a browser. h4. Summary&lt;/p&gt;

&lt;p&gt;RAP is created to provide developers a possibility to bring the goodness of RCP applications to the web without the need to digging through low-level web-technologies. This greatly reduces cost by reuse of knowledge and code. It provides a thin client with a rich widget set and a stageful server-side on top of OSGi, and reuses the Eclipse workbench paradigm. As OSGi-based web containers such as Spring dm server are getting more prevalent, RAP will definitely enjoy more popularity. h4. Reference&lt;/p&gt;
&lt;div class='footnotes'&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id='fn:1'&gt;
&lt;p&gt;&lt;a href='http://www.amazon.com/Eclipse-Rich-Ajax-Platform-Firstpress/dp/1430218835/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1278568095&amp;amp;sr=8-1'&gt;Eclipse Rich Ajax Platform: Bringing Rich Client to the Web&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:1' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;li id='fn:2'&gt;
&lt;p&gt;&lt;a href='http://www.zkoss.org/smalltalks/gwtZk/'&gt;ZK vs. GWT : Server-Centric Matters&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:2' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;li id='fn:3'&gt;
&lt;p&gt;&lt;a href='http://eclipsesource.com/blogs/2008/09/17/the-new-eclipse-download-wizard-and-rap-performance'&gt;The new Eclipse download wizard and RAP performance&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:3' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;li id='fn:4'&gt;
&lt;p&gt;&lt;a href='http://live.eclipse.org/node/722'&gt;EclipseCon 09: RAP or GWT - Which Java-Based AJAX Technology is for You?&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:4' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=LAR6H7ch4bs:a5gwVcu3q0w:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=LAR6H7ch4bs:a5gwVcu3q0w:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=LAR6H7ch4bs:a5gwVcu3q0w:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=LAR6H7ch4bs:a5gwVcu3q0w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=LAR6H7ch4bs:a5gwVcu3q0w:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=LAR6H7ch4bs:a5gwVcu3q0w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=LAR6H7ch4bs:a5gwVcu3q0w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=LAR6H7ch4bs:a5gwVcu3q0w:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=LAR6H7ch4bs:a5gwVcu3q0w:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=LAR6H7ch4bs:a5gwVcu3q0w:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=LAR6H7ch4bs:a5gwVcu3q0w:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/LAR6H7ch4bs" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2010/07/08/introducing-eclipse-rap.html</feedburner:origLink></entry><entry><title type="text">Why code navigation sucks on most SCM's web interfaces?</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/uAMuIxYUr7Y/why-code-navigation-sucks-on-most-scm-web-interface.html" /><updated>2010-07-05T00:00:00-07:00</updated><id>http://owenou.com/2010/07/05/why-code-navigation-sucks-on-most-scm-web-interface</id><content type="html">&lt;p&gt;I am not surprised that you feel the same. It sucks to navigate codes on most source control system&amp;#8217;s web interfaces! Here are whys.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The display of files in most SCM&amp;#8217;s web interface is not in a tree, but in a list&lt;/strong&gt;. Files are in a tree structure; displaying them as a list is definitely a mismatch! The consequence of converting a tree structure to a list one is that the file context is lost during navigation. I believe you must feel annoying when clicking back and forth in order to find more than one file on &lt;a href='http://github.com/'&gt;GitHub&lt;/a&gt;&amp;#8217;s web interface:&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/github-20110213-233508.jpg' height='220' alt='GitHub' width='559' /&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;strong&gt;There is a disconnection between opened file&amp;#8217;s context and opened file&amp;#8217;s content&lt;/strong&gt;. Take &lt;a href='http://code.google.com/' target='_blank'&gt;Google Code&lt;/a&gt;&amp;#8217;s web interface as an example, although its display of files is in a tree structure, but after a file is opened, the context where the file belongs to is gone: only the path of the file is still kept:&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/google_code-20110213-233548.jpg' height='560' alt='Google Code' width='560' /&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Being impossible to open multiple files at once&lt;/strong&gt;. File is a module to separate concerns in almost all programming languages. At most of the time, reading code only from one file is not informative enough. In a programming language sense, files have connections to each other and being able to show related file modules at once is critical to understand the application. Moreover, we have been used to exploring pages with multiple tabs on a browser, and have been used to navigate codes with multiple viewers in an IDE. This feature is definitely a must!&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;strong&gt;There is no unified UI to navigate codes across all source control systems&lt;/strong&gt;. We have &lt;a href='http://www.viewvc.org/'&gt;ViewVC&lt;/a&gt;, &lt;a href='https://git.wiki.kernel.org/index.php/Gitweb'&gt;Gitweb&lt;/a&gt;, &lt;a href='http://www.warehouseapp.com/'&gt;Warehouse&lt;/a&gt;, many many&amp;#8230; But we don&amp;#8217;t have a web interface that adapts to all kinds of version control systems.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you feel there is a need to improve existing SCM&amp;#8217;s web interface, I would like to introduce to you a neat tool that &lt;a href='http://codefaces.com/about/'&gt;we&lt;/a&gt; built lately: &lt;a href='http://codefaces.org'&gt;CodeFaces&lt;/a&gt;.  CodeFaces is a source control client made for browsers. It provides an IDE-looking page to structurally navigate codes from a version control system. Check out &lt;a href='http://codefaces.org'&gt;http://codefaces.org&lt;/a&gt; for more updates and here is a screencast that walks you through all its features: &lt;a href='http://www.youtube.com/watch?v=JNVcyi0cDQ0&amp;amp;hd=1'&gt;http://www.youtube.com/watch?v=JNVcyi0cDQ0&amp;amp;hd=1&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=uAMuIxYUr7Y:VgveJqfZna0:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=uAMuIxYUr7Y:VgveJqfZna0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=uAMuIxYUr7Y:VgveJqfZna0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=uAMuIxYUr7Y:VgveJqfZna0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=uAMuIxYUr7Y:VgveJqfZna0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=uAMuIxYUr7Y:VgveJqfZna0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=uAMuIxYUr7Y:VgveJqfZna0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=uAMuIxYUr7Y:VgveJqfZna0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=uAMuIxYUr7Y:VgveJqfZna0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=uAMuIxYUr7Y:VgveJqfZna0:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=uAMuIxYUr7Y:VgveJqfZna0:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/uAMuIxYUr7Y" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2010/07/05/why-code-navigation-sucks-on-most-scm-web-interface.html</feedburner:origLink></entry><entry><title type="text">Pushing Adaptive Implementations with Eclipse's Extension Points</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/bkSYpRY_Uwk/pushing-adaptive-implementations-with-eclipse-extension-points.html" /><updated>2010-04-12T00:00:00-07:00</updated><id>http://owenou.com/2010/04/12/pushing-adaptive-implementations-with-eclipse-extension-points</id><content type="html">&lt;p&gt;A week ago, I blogged about &lt;a href='/2010/04/07/adaptive-implementations-with-eclipses-optional-plugin-dependencies.html'&gt;implementing adaptive components using Eclipse&amp;#8217;s optional plugin dependencies&lt;/a&gt;. In that post, I gave an example on displaying HTML files with different editors based on client&amp;#8217;s environment: open the HTML file with the HTML editor from &lt;a href='http://www.eclipse.org/webtools/'&gt;WTP&lt;/a&gt; if the plugin is installed, otherwise fallback to open with the default text editor. The final solution was to query the existence of the WTP editor through &lt;a href='http://www.eclipse.org/equinox/'&gt;Equinox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, the implementation is far from enjoyable: our main plugin knows everything about WTP! In other words, in order to specify the query, our main plugin has to know about WTP, hence containing environment-specific implementations. The following graph shows the dependency:&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/pull-20110213-233614.jpg' height='200' alt='pull method' width='300' /&gt;&lt;/p&gt;

&lt;p&gt;The reason causing this environment-specific coupling is that our main plugin uses the &lt;strong&gt;pull&lt;/strong&gt; method to retrieve the HTML editor implementations from WTP (code snippet goes &lt;a href='/2010/04/07/adaptive-implementations-with-eclipses-optional-plugin-dependencies.html'&gt;here&lt;/a&gt;). To solve this, we can &lt;a href='http://en.wikipedia.org/wiki/Inversion_of_control'&gt;inverse the control&lt;/a&gt; and have another plugin to &lt;strong&gt;push&lt;/strong&gt; specific implementations to the main plugin.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/push-20110213-233648.jpg' height='252' alt='push method' width='400' /&gt;&lt;/p&gt;

&lt;p&gt;Equinox has already offered a very powerful tool for this purpose: &lt;a href='http://wiki.eclipse.org/FAQ_What_are_extensions_and_extension_points%3F'&gt;extension points&lt;/a&gt;. In the dependency graph above, we separate the concerns by creating an adaptor plugin between the main plugin and the WTP plugin. We declare its dependency on WTP as optional to make sure the plugin will be installed on clients even if the WTP dependency is missing. If somehow WTP is installed in the future, the adaptor will automatically hook it up. Besides, we define an extension point in the main plugin so that the adaptor plugin knows what to contribute and where to contribute.&lt;/p&gt;

&lt;p&gt;Here are steps to implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an extension point in the main plugin to allow editor contributions. We confine that the contributing editors should be an instance of ITextEditor. The schema looks something like this:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;element&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;extension&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;complextype&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;sequence&amp;gt;&lt;/span&gt;
	  &lt;span class='nt'&gt;&amp;lt;element&lt;/span&gt; &lt;span class='na'&gt;ref=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;sourceEditor&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&amp;lt;/element&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/sequence&amp;gt;&lt;/span&gt;
	...
  &lt;span class='nt'&gt;&amp;lt;/complextype&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/element&amp;gt;&lt;/span&gt;

&lt;span class='nt'&gt;&amp;lt;element&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;sourceEditor&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;complextype&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;type=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;string&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;use=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
	  ...
	&lt;span class='nt'&gt;&amp;lt;/attribute&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class='na'&gt;name=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;class&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;type=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;string&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;use=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
	  &lt;span class='nt'&gt;&amp;lt;annotation&amp;gt;&lt;/span&gt;
	    &lt;span class='nt'&gt;&amp;lt;appinfo&amp;gt;&lt;/span&gt;
		  &lt;span class='nt'&gt;&amp;lt;meta.attribute&lt;/span&gt; &lt;span class='na'&gt;kind=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;java&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;basedon=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;:org.eclipse.ui.texteditor.ITextEditor&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;/&amp;gt;&lt;/span&gt;
	    &lt;span class='nt'&gt;&amp;lt;/appinfo&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;/annotation&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/attribute&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/complextype&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/element&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Create a factory class in the main plugin that knows how to create an ITextEditor after reading the extensions. We also need to reconcile that only one editor extension is initialized (in the case of multiple contributions):&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='java'&gt;&lt;span class='kd'&gt;public&lt;/span&gt; &lt;span class='kd'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;SourceEditorFactory&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
	&lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='kd'&gt;static&lt;/span&gt; &lt;span class='n'&gt;IConfigurationElement&lt;/span&gt; &lt;span class='n'&gt;cachedConfigurationElement&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

	&lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='kd'&gt;static&lt;/span&gt; &lt;span class='kd'&gt;final&lt;/span&gt; &lt;span class='n'&gt;String&lt;/span&gt; &lt;span class='n'&gt;ATTRIBUTE_CLASS&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;class&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

	&lt;span class='kd'&gt;public&lt;/span&gt; &lt;span class='kd'&gt;static&lt;/span&gt; &lt;span class='n'&gt;ITextEditor&lt;/span&gt; &lt;span class='nf'&gt;createSourceEditor&lt;/span&gt;&lt;span class='o'&gt;()&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
		&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;cachedConfigurationElement&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='kc'&gt;null&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
			&lt;span class='n'&gt;cachedConfigurationElement&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;readConfigurationElement&lt;/span&gt;&lt;span class='o'&gt;();&lt;/span&gt;
		&lt;span class='o'&gt;}&lt;/span&gt;

		&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;cachedConfigurationElement&lt;/span&gt; &lt;span class='o'&gt;!=&lt;/span&gt; &lt;span class='kc'&gt;null&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
			&lt;span class='k'&gt;try&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
				&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;ITextEditor&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='n'&gt;cachedConfigurationElement&lt;/span&gt;
						&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;createExecutableExtension&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;ATTRIBUTE_CLASS&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;
			&lt;span class='o'&gt;}&lt;/span&gt; &lt;span class='k'&gt;catch&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Exception&lt;/span&gt; &lt;span class='n'&gt;exception&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
				&lt;span class='c1'&gt;// errors when initializing the source editor&lt;/span&gt;
			&lt;span class='o'&gt;}&lt;/span&gt;
		&lt;span class='o'&gt;}&lt;/span&gt;

		&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nf'&gt;TextEditor&lt;/span&gt;&lt;span class='o'&gt;();&lt;/span&gt;
	&lt;span class='o'&gt;}&lt;/span&gt;

	&lt;span class='c1'&gt;// Reads the first configuration element whose implemented class is not&lt;/span&gt;
	&lt;span class='c1'&gt;// TextEditor&lt;/span&gt;
	&lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='kd'&gt;static&lt;/span&gt; &lt;span class='n'&gt;IConfigurationElement&lt;/span&gt; &lt;span class='nf'&gt;readConfigurationElement&lt;/span&gt;&lt;span class='o'&gt;()&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
		&lt;span class='n'&gt;IExtensionPoint&lt;/span&gt; &lt;span class='n'&gt;extensionPoint&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Platform&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getExtensionRegistry&lt;/span&gt;&lt;span class='o'&gt;()&lt;/span&gt;
				&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getExtensionPoint&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;FitPlugin&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;PLUGIN_ID&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;fitSourceEditor&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;

		&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;IConfigurationElement&lt;/span&gt; &lt;span class='n'&gt;configurationElement&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='n'&gt;extensionPoint&lt;/span&gt;
				&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getConfigurationElements&lt;/span&gt;&lt;span class='o'&gt;())&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
			&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;(!&lt;/span&gt;&lt;span class='n'&gt;StringUtils&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;equals&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;TextEditor&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;class&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getCanonicalName&lt;/span&gt;&lt;span class='o'&gt;(),&lt;/span&gt;
					&lt;span class='n'&gt;configurationElement&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getAttribute&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;ATTRIBUTE_CLASS&lt;/span&gt;&lt;span class='o'&gt;)))&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
				&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;configurationElement&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
			&lt;span class='o'&gt;}&lt;/span&gt;
		&lt;span class='o'&gt;}&lt;/span&gt;

		&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='kc'&gt;null&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
	&lt;span class='o'&gt;}&lt;/span&gt;
&lt;span class='o'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You might have noticed that lines 15 to 20 silently catch all exceptions and return the default text editor if there are any errors when initializing the extension. It ensures that even if WTP is not installed on the client, there is a fallback implementation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Declare an extension in the adaptor plugin which refers to the HTML editor from WTP.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;extension&lt;/span&gt; &lt;span class='na'&gt;point=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;com.luxoft.eclipse.fit.runner.fitSourceEditor&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;sourceeditor&lt;/span&gt; &lt;span class='na'&gt;class=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;org.eclipse.wst.sse.ui.StructuredTextEditor&amp;quot;&lt;/span&gt; 
		&lt;span class='na'&gt;id=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;com.luxoft.eclipse.fit.runner.optional.wtpHTMLEditor&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;/&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/extension&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;For more details, please check out &lt;a href='http://fitpro.svn.sourceforge.net/viewvc/fitpro/Eclipse/trunk/'&gt;the source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From above, we learn how to &lt;em&gt;push&lt;/em&gt; adaptive implementations using extension points, which decouples environment-specific implementations by inverting the controls. Another powerful tool that Equinox provides for adaptive implementations is &lt;a href='http://wiki.eclipse.org/FAQ_What_is_a_plug-in_fragment%3F'&gt;Fragment&lt;/a&gt;. If you are careful enough, you might have noticed that our adaptor plugin actually acts as a fragment, a library that is specific to a particular operating system or windowing system. In the next blog post, I will talk more about it in details.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=bkSYpRY_Uwk:q1XOkl1rhLY:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=bkSYpRY_Uwk:q1XOkl1rhLY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=bkSYpRY_Uwk:q1XOkl1rhLY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=bkSYpRY_Uwk:q1XOkl1rhLY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=bkSYpRY_Uwk:q1XOkl1rhLY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=bkSYpRY_Uwk:q1XOkl1rhLY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=bkSYpRY_Uwk:q1XOkl1rhLY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=bkSYpRY_Uwk:q1XOkl1rhLY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=bkSYpRY_Uwk:q1XOkl1rhLY:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=bkSYpRY_Uwk:q1XOkl1rhLY:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=bkSYpRY_Uwk:q1XOkl1rhLY:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/bkSYpRY_Uwk" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2010/04/12/pushing-adaptive-implementations-with-eclipse-extension-points.html</feedburner:origLink></entry><entry><title type="text">Adaptive Implementations with Eclipse's Optional Plugin Dependencies</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/Trj-kwHzaUE/adaptive-implementations-with-eclipses-optional-plugin-dependencies.html" /><updated>2010-04-07T00:00:00-07:00</updated><id>http://owenou.com/2010/04/07/adaptive-implementations-with-eclipses-optional-plugin-dependencies</id><content type="html">&lt;p&gt;&lt;a href='http://www.eclipse.org/equinox/'&gt;Equinox&lt;/a&gt; is an &lt;a href='http://www.osgi.org'&gt;OSGI&lt;/a&gt; implementation that allows bundles to find out what capabilities are available on the system and adapt the functionality they can provide. This adaptivity is achieved through the OSGi service registry. In this blog post, I am gonna talk about how to make use of Eclipse&amp;#8217;s optional plugin dependencies to support diverse runtime environment.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s get started with an example: When a HTML file is clicked, it should be open with the HTML editor from &lt;a href='http://www.eclipse.org/webtools/'&gt;WTP&lt;/a&gt; if the plugin is installed. Otherwise open it with a text editor. (This is a real world example from &lt;a href='http://sourceforge.net/projects/fitpro/'&gt;FITpro&lt;/a&gt; BTW :) ).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;First, we need to add the WTP UI component as an &lt;em&gt;optional&lt;/em&gt; dependency.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://idisk.me.com/jingweno/Public/Pictures/Skitch/optional_dependencies-20110213-233607.jpg' height='307' alt='push method' width='304' /&gt;&lt;/p&gt;

&lt;p&gt;The MANIFEST.MF should look something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Require-Bundle:
 ...
 org.eclipse.wst.sse.ui;resolution:=optional&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Create a HTML editor if WTP is installed on the client, otherwise fallback to text editor. Wait&amp;#8230;here we might have more than one solution:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First of all, we might consider directly initializing the HTML editor class from WTP and if it doesn&amp;#8217;t exist, initialize the text editor. However, &lt;a href='http://mobius.inria.fr/eclipse-doc/org/eclipse/osgi/framework/internal/core/BundleLoader.html#findClass(java.lang.String)'&gt;BundleLoader&lt;/a&gt; won&amp;#8217;t let this happen since it throws out ClassNotFoundException if a class doesn&amp;#8217;t exist (in the case of WTP not being installed on the client), and this exception can&amp;#8217;t be caught in client implementations.&lt;/p&gt;

&lt;p&gt;Secondly, we might also consider initializing the HTML editor class through reflection. In this way, we can catch our own ClassNotFoundException and fallback to create a text editor.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='java'&gt;&lt;span class='kd'&gt;public&lt;/span&gt; &lt;span class='n'&gt;TextEditor&lt;/span&gt; &lt;span class='nf'&gt;createHTMLTextEditor&lt;/span&gt;&lt;span class='o'&gt;()&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
	&lt;span class='k'&gt;try&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
		&lt;span class='n'&gt;Class&lt;/span&gt; &lt;span class='n'&gt;cls&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Class&lt;/span&gt;
			&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;forName&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;org.eclipse.wst.sse.ui.StructuredTextEditor&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;
		&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Constructor&lt;/span&gt; &lt;span class='n'&gt;constructor&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='n'&gt;cls&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getDeclaredConstructors&lt;/span&gt;&lt;span class='o'&gt;())&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
			&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;constructor&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getGenericParameterTypes&lt;/span&gt;&lt;span class='o'&gt;().&lt;/span&gt;&lt;span class='na'&gt;length&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
				&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;TextEditor&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='n'&gt;constructor&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;newInstance&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='n'&gt;Object&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;]);&lt;/span&gt;
			&lt;span class='o'&gt;}&lt;/span&gt;
		&lt;span class='o'&gt;}&lt;/span&gt;
	&lt;span class='o'&gt;}&lt;/span&gt; &lt;span class='k'&gt;catch&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Throwable&lt;/span&gt; &lt;span class='n'&gt;throwable&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
		&lt;span class='c1'&gt;// couldn&amp;#39;t find the WTP plugin&lt;/span&gt;
	&lt;span class='o'&gt;}&lt;/span&gt;

	&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nf'&gt;TextEditor&lt;/span&gt;&lt;span class='o'&gt;();&lt;/span&gt;
&lt;span class='o'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;However&amp;#8230;this is not quite &amp;#8220;OSGI&amp;#8221;. Actually, Equinox provides &lt;a href='http://help.eclipse.org/help32/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IConfigurationElement.html'&gt;APIs&lt;/a&gt; to retrieve extension configurations and initialize their implemented classes. It uses the same way to initialize classes like what we are doing here.&lt;/p&gt;

&lt;p&gt;We can ask Equinox for all the registered editor extensions and find out whether WTP&amp;#8217;s HTML editor is one of them. If yes, just initialize it. Otherwise, create the text editor that is available to all clients.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='java'&gt;&lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='kd'&gt;static&lt;/span&gt; &lt;span class='kd'&gt;final&lt;/span&gt; &lt;span class='n'&gt;String&lt;/span&gt; &lt;span class='n'&gt;HTML_EDITOR_ID&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;org.eclipse.wst.sse.ui.StructuredTextEditor&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

&lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='kd'&gt;static&lt;/span&gt; &lt;span class='kd'&gt;final&lt;/span&gt; &lt;span class='n'&gt;String&lt;/span&gt; &lt;span class='n'&gt;ATTRIBUTE_CLASS&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;class&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

&lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='kd'&gt;static&lt;/span&gt; &lt;span class='kd'&gt;final&lt;/span&gt; &lt;span class='n'&gt;String&lt;/span&gt; &lt;span class='n'&gt;ATTRIBUTE_ID&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

&lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='kd'&gt;static&lt;/span&gt; &lt;span class='kd'&gt;final&lt;/span&gt; &lt;span class='n'&gt;String&lt;/span&gt; &lt;span class='n'&gt;EDITOR_EXTENSION_POINT_ID&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;org.eclipse.ui.editors&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

&lt;span class='kd'&gt;public&lt;/span&gt; &lt;span class='n'&gt;TextEditor&lt;/span&gt; &lt;span class='nf'&gt;createHTMLTextEditor&lt;/span&gt;&lt;span class='o'&gt;()&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
	&lt;span class='k'&gt;try&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
		&lt;span class='n'&gt;IExtensionPoint&lt;/span&gt; &lt;span class='n'&gt;extensionPoint&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Platform&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getExtensionRegistry&lt;/span&gt;&lt;span class='o'&gt;()&lt;/span&gt;
			&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getExtensionPoint&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;EDITOR_EXTENSION_POINT_ID&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;
		&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;extensionPoint&lt;/span&gt; &lt;span class='o'&gt;!=&lt;/span&gt; &lt;span class='kc'&gt;null&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
			&lt;span class='n'&gt;IConfigurationElement&lt;/span&gt;&lt;span class='o'&gt;[]&lt;/span&gt; &lt;span class='n'&gt;configurationElements&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;extensionPoint&lt;/span&gt;
				&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getConfigurationElements&lt;/span&gt;&lt;span class='o'&gt;();&lt;/span&gt;
			&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;IConfigurationElement&lt;/span&gt; &lt;span class='n'&gt;element&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='n'&gt;configurationElements&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
				&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;StringUtils&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;equals&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;element&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;getAttribute&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;ATTRIBUTE_ID&lt;/span&gt;&lt;span class='o'&gt;),&lt;/span&gt;
				&lt;span class='n'&gt;HTML_EDITOR_ID&lt;/span&gt;&lt;span class='o'&gt;))&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
					&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;TextEditor&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='n'&gt;element&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='na'&gt;createExecutableExtension&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;ATTRIBUTE_CLASS&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;
				&lt;span class='o'&gt;}&lt;/span&gt;
			&lt;span class='o'&gt;}&lt;/span&gt;
		&lt;span class='o'&gt;}&lt;/span&gt;
	&lt;span class='o'&gt;}&lt;/span&gt; &lt;span class='k'&gt;catch&lt;/span&gt; &lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;Exception&lt;/span&gt; &lt;span class='n'&gt;exception&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
		&lt;span class='c1'&gt;// couldn&amp;#39;t find the WTP plugin&lt;/span&gt;
	&lt;span class='o'&gt;}&lt;/span&gt;

	&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nf'&gt;TextEditor&lt;/span&gt;&lt;span class='o'&gt;();&lt;/span&gt;
&lt;span class='o'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we see how flexible it is to provide an adaptive Implementation with Eclipse&amp;#8217;s optional plugin dependencies. With this power, we can also support something like upgrading a system without ruining the old working legacy components. A tips can be found &lt;a href='http://www.developer.com/java/web/article.php/3655231/Eclipse-Tip-Use-Optional-Plug-in-Dependencies-to-Support-Diverse-Runtime-Environments.htm'&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=Trj-kwHzaUE:tg664oqGx1U:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=Trj-kwHzaUE:tg664oqGx1U:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=Trj-kwHzaUE:tg664oqGx1U:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=Trj-kwHzaUE:tg664oqGx1U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=Trj-kwHzaUE:tg664oqGx1U:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=Trj-kwHzaUE:tg664oqGx1U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=Trj-kwHzaUE:tg664oqGx1U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=Trj-kwHzaUE:tg664oqGx1U:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=Trj-kwHzaUE:tg664oqGx1U:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=Trj-kwHzaUE:tg664oqGx1U:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=Trj-kwHzaUE:tg664oqGx1U:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/Trj-kwHzaUE" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2010/04/07/adaptive-implementations-with-eclipses-optional-plugin-dependencies.html</feedburner:origLink></entry><entry><title type="text">Judicious Serialization</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/E2f29lsEq0Q/judicious-serialization.html" /><updated>2009-11-26T00:00:00-08:00</updated><id>http://owenou.com/2009/11/26/judicious-serialization</id><content type="html">&lt;p&gt;I was fixing a bug related to &lt;a href='http://en.wikipedia.org/wiki/Serialization'&gt;Java Serialization&lt;/a&gt; the other day: Server 1 tried to send out an email by using one of the web services from Server 2 with serialized objects passed along. It almost took me half a day to dig out the problem because the stack trace wasn’t helpful enough other than saying there were &lt;a href='http://java.sun.com/javase/7/docs/api/java/io/Serializable.html'&gt;Serializable&lt;/a&gt; exceptions. After lots of debugging, I finally found out that the problem was one of the Serializable objects having non-Serializable attributes.&lt;/p&gt;

&lt;p&gt;There must be some lessons we can learn from here! I quickly checked the hierarchy of the object. Okay&amp;#8230;great! Its interface indirectly inherited from Serializable. A code smell came into my mind immediately: &lt;strong&gt;if a class is designed for inheritance (including interfaces), rarely extend it from Serializable&lt;/strong&gt;. It isn&amp;#8217;t too hard to understand why: once a class implements Serializable,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;all its attributes have to either accept the fact that they are Serializable or &lt;a href='http://en.wikibooks.org/wiki/Java_Programming/Keywords/transient'&gt;transient&lt;/a&gt;, and&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;all its subclasses have to tightly couple to the Serializable club, including their attributes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With Serializable exposed to interface level, the flexibility of the interface is highly reduced and we have to spend proportional effort on maintaining them. Just imagine there are 3 classes with 5 attributes each. To successfully transmit them through Internet, you need to make sure 18 items are Serializable (15 attributes + 3 classes). If you forget any of them, well, you could imagine how painful it is to count which one is missing with all your fingers (that&amp;#8217;s exactly what I have been through!!). Needless to say how to test them. For testing, you must ensure 18 times both that the serialization-deserialization process succeeds and that it results in a faithful replica of the original object.&lt;/p&gt;

&lt;p&gt;Alright, this is enough frustration! Serialization should be used judiciously! But how? First of all, of course, &lt;strong&gt;never expose Serializable to classes that are meant to be inherited&lt;/strong&gt;. Do it in its subclasses like the following:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='java'&gt;&lt;span class='kd'&gt;interface&lt;/span&gt; &lt;span class='nc'&gt;Foo&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt; &lt;span class='o'&gt;...&lt;/span&gt; &lt;span class='o'&gt;}&lt;/span&gt;
&lt;span class='kd'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Bar&lt;/span&gt; &lt;span class='kd'&gt;implements&lt;/span&gt; &lt;span class='n'&gt;Foo&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='n'&gt;Serializable&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt; &lt;span class='o'&gt;...&lt;/span&gt; &lt;span class='o'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Secondly, &lt;strong&gt;try to minimize as much as possible the scope of serialization&lt;/strong&gt;. Never serialize more than you need. It will just make it harder to debug if anything wrong happened. For example, you are passing the following Serializable object from Server 1 to Server 2.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='java'&gt;&lt;span class='kd'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Baz&lt;/span&gt; &lt;span class='kd'&gt;implements&lt;/span&gt; &lt;span class='n'&gt;Serializable&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
    &lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='n'&gt;A&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
    &lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='n'&gt;B&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
    &lt;span class='kd'&gt;private&lt;/span&gt; &lt;span class='n'&gt;C&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
    &lt;span class='o'&gt;...&lt;/span&gt;
&lt;span class='o'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;But somehow you know that only Baz.a and Baz.c are used on Server 2. So just pass Baz.a and Baz.c instead of the whole object! This is also true from the perspective of design: &lt;a href='http://en.wikipedia.org/wiki/You_ain%27t_gonna_need_it'&gt;YAGNI&lt;/a&gt;, only pass the objects that you care about.&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;use as much as possible classes from the Java library in serialization, or use other alternative technologies&lt;/strong&gt;. ArrayList, BigDecimal and many others come with the Serializable ability by default. Why reinventing the wheels and creating you own mess? Popular alternatives are XML, JSON, or YAML.&lt;/p&gt;

&lt;p&gt;There are lots of great articles on this topic, e.g.,  Chapter 11 of &lt;a href='http://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683'&gt;Effective Java&lt;/a&gt;. I don&amp;#8217;t wanna &lt;a href='http://en.wikipedia.org/wiki/Don%27t_repeat_yourself'&gt;DRY&lt;/a&gt; myself here :). Last but not least, bewared when you see Serializable! It&amp;#8217;s tricky!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=E2f29lsEq0Q:NXyO4Qi7sDs:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=E2f29lsEq0Q:NXyO4Qi7sDs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=E2f29lsEq0Q:NXyO4Qi7sDs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=E2f29lsEq0Q:NXyO4Qi7sDs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=E2f29lsEq0Q:NXyO4Qi7sDs:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=E2f29lsEq0Q:NXyO4Qi7sDs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=E2f29lsEq0Q:NXyO4Qi7sDs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=E2f29lsEq0Q:NXyO4Qi7sDs:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=E2f29lsEq0Q:NXyO4Qi7sDs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=E2f29lsEq0Q:NXyO4Qi7sDs:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=E2f29lsEq0Q:NXyO4Qi7sDs:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/E2f29lsEq0Q" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2009/11/26/judicious-serialization.html</feedburner:origLink></entry><entry><title type="text">Running Eclipse Java Compiler with Ant</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/OwenOu/~3/g3e8rVLmRVs/running-eclipse-java-compiler-with-ant.html" /><updated>2009-11-18T00:00:00-08:00</updated><id>http://owenou.com/2009/11/18/running-eclipse-java-compiler-with-ant</id><content type="html">&lt;p&gt;&lt;a href='http://www.eclipse.org/jdt/core/index.php'&gt;Eclipse Java Compiler&lt;/a&gt; (EJC) is an &lt;a href='http://en.wikipedia.org/wiki/Incremental_compiler'&gt;incremental compiler&lt;/a&gt; that is generally faster than any JDKs. It also fixes some incompatible problems related to JDK6, e.g. &lt;a href='http://issues.apache.org/jira/browse/OPENJPA-640'&gt;http://issues.apache.org/jira/browse/OPENJPA-640&lt;/a&gt;. This post is about how to run EJC with an ant target to compile your Java projects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;a href='http://ant.apache.org'&gt;Ant&lt;/a&gt; 1.7+.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Download the latest &lt;a href='http://download.eclipse.org/eclipse/downloads/drops/R-3.6.1-201009090800/index.php#JDTSDK'&gt;JDT Core Batch Compiler&lt;/a&gt; and put it directly into your $ANT_HOME/lib folder. Or, if you have Eclipse installed, you have the compiler by default: Locate the &lt;strong&gt;org.eclipse.jdt.core_xxx.jar&lt;/strong&gt; in the plugins directory of your Eclipse installation, put that jar file into the $ANT_HOME/lib folder, and at the same time unzip this jar file and make &lt;strong&gt;jdtCompilerAdapter.jar&lt;/strong&gt; available to ant. As an alternative, you can specify the path of the jar file by using the &amp;#8220;-lib&amp;#8221; flag of ant.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;You are now ready to test the Eclipse compiler in command line. The key is to direct ant to use EJC by specifying the compiler parameter &lt;strong&gt;-Dbuild.compiler&lt;/strong&gt; to &lt;strong&gt;org.eclipse.jdt.core.JDTCompilerAdapter&lt;/strong&gt;. Go to a Java project and type in:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ant -Dbuild.compiler=org.eclipse.jdt.core.JDTCompilerAdapter
    -Dant.build.javac.target=1.6
    -Dant.build.javac.source=1.6 compile&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;You can also set up an ant target to play around with it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;target name=&amp;quot;-eclipse-compile&amp;quot;&amp;gt;
  &amp;lt;javac source=&amp;quot;1.6&amp;quot; target=&amp;quot;1.6&amp;quot; compiler=&amp;quot;org.eclipse.jdt.core.JDTCompilerAdapter&amp;quot;&amp;gt;
     …
  &amp;lt;/javac&amp;gt;
&amp;lt;/target&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=g3e8rVLmRVs:mQmg31erbUE:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=g3e8rVLmRVs:mQmg31erbUE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=g3e8rVLmRVs:mQmg31erbUE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=g3e8rVLmRVs:mQmg31erbUE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=g3e8rVLmRVs:mQmg31erbUE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=g3e8rVLmRVs:mQmg31erbUE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=g3e8rVLmRVs:mQmg31erbUE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=g3e8rVLmRVs:mQmg31erbUE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=g3e8rVLmRVs:mQmg31erbUE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OwenOu?a=g3e8rVLmRVs:mQmg31erbUE:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OwenOu?i=g3e8rVLmRVs:mQmg31erbUE:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OwenOu/~4/g3e8rVLmRVs" height="1" width="1"/&gt;</content><feedburner:origLink>http://owenou.com/2009/11/18/running-eclipse-java-compiler-with-ant.html</feedburner:origLink></entry></feed>

