<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tapestry 5 Blog</title>
	<atom:link href="http://blog.tapestry5.de/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.tapestry5.de</link>
	<description>Thoughts on coding, technology and occasional stuff.</description>
	<lastBuildDate>Wed, 28 Jul 2010 17:45:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Reading Annotations of Service Implementation Classes</title>
		<link>http://blog.tapestry5.de/index.php/2010/07/28/reading-annotations-of-service-implementation-classes/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/07/28/reading-annotations-of-service-implementation-classes/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 17:45:51 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Tapestry]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1641</guid>
		<description><![CDATA[Today I committed some changes for Tapestry 5.2 that allow you to access annotations placed on service implementation classes. As you probably know Tapestry creates proxies for services. The proxy implements the service interface and delegates method invocations to the actual service instance. When you inject a service into your page, component or another service [...]]]></description>
			<content:encoded><![CDATA[<p>Today I committed some changes for Tapestry 5.2 that allow you to access annotations placed on service implementation classes. As you probably know Tapestry creates proxies for services. The proxy implements the service interface and delegates method invocations to the actual service instance. When you inject a service into your page, component or another service you get a proxy which creates an instance of the service implementation class on demand. The first time a method is invoked on the proxy, the actual service is instantiated and initialized.</p>
<p>Until today Tapestry&#8217;s proxies did not expose annotations of service implementation classes. If you have placed annotations on a service implementation class you was not able to read them reflectively. The reason was the way how proxy classes were fabricated. Tapestry just skipped copying annotations from implementation class to proxy. This caused some problems when integrating third party libraries into Tapestry applications. For example imagine you want to expose your service as a web service and place the <a title="@WebService" href="http://download-llnw.oracle.com/javaee/5/api/javax/jws/WebService.html" target="_blank">@WebService</a> on the service implementation class. Because the annotation was not copied to the service proxy class, your service was not identified as web service.</p>
<pre class="brush: java;">import javax.jws.WebService;
import javax.jws.WebMethod;

@WebService
public class CalculatorImpl implements Calculator {  

   @WebMethod
   public int add( int x, int y )  {
      return x + y;
   }
}</pre>
<p>As of version 5.2 the annotations from service implementation class will be placed on the proxy class if this implementation is bound to its interface inside a <em>bind</em> method.</p>
<pre class="brush: java;">public class AppModule {  

   public static void bind(ServiceBinder binder)  {
      binder.bind(Calculator.class, CalculatorImpl.class);
   }
}</pre>
<p>In case of <em>build</em> methods annotations are still lost. For build methods there is no way to determine the implementation class at proxy creation time. A proxy invokes the <em>build</em> method to instantiate the actual service on demand. At this time you know the implementation class but it&#8217;s just too late. The proxy class already have been fabricated.</p>
<pre class="brush: java;">public class AppModule {  

   public static Calculator buildCalculator()  {
      return new CalculatorImpl();
   }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/07/28/reading-annotations-of-service-implementation-classes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Tapestry Talk at Herbstcampus</title>
		<link>http://blog.tapestry5.de/index.php/2010/07/26/tapestry-talk-at-herbstcampus/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/07/26/tapestry-talk-at-herbstcampus/#comments</comments>
		<pubDate>Mon, 26 Jul 2010 18:13:34 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Tapestry]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1609</guid>
		<description><![CDATA[I was invited to present Tapestry 5 at Herbstcampus in Nürnberg, Germany. Herbstcampus is a conference for software developers, architects, and project managers with a technology focus in .NET and Java. My talk Fliegede Teppiche &#8211; Moderne Webanwendungen mit Tapestry 5 (Flying carpets &#8211; Modern web applications with Tapestry 5) takes place on September 14th, [...]]]></description>
			<content:encoded><![CDATA[<p>I was invited to present Tapestry 5 at <a title="Herbstcampus" href="http://www.herbstcampus.com" target="_blank">Herbstcampus</a> in Nürnberg, Germany. Herbstcampus is a conference for software developers, architects, and project managers with a technology focus in .NET and Java. My talk <a title="Talk" href="http://www.herbstcampus.com/hc10/program/sessions.html#74" target="_blank">Fliegede Teppiche &#8211; Moderne Webanwendungen mit Tapestry 5 </a> (Flying carpets &#8211; Modern web applications with Tapestry 5) takes place on September 14th, 2010. If you are living in Bavaria, this is a chance to learn Tapestry in a 70 minutes session. I’ll give an overview over Tapestry concepts and new features in the upcoming release 5.2. As always I will show a lot of demos.<a href="http://blog.tapestry5.de/wp-content/uploads/2010/07/herbstcampus.gif"><br />
</a><br />
<a title="Herbstcampus" href="http://www.herbstcampus.com" target="_blank"><img class="aligncenter size-medium wp-image-1624" title="Herbstcampus" src="http://blog.tapestry5.de/wp-content/uploads/2010/07/herbstcampus-299x41.gif" alt="" width="299" height="41" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/07/26/tapestry-talk-at-herbstcampus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Advanced Service Builders in Tapestry IoC: Chain of Responsibility Pattern</title>
		<link>http://blog.tapestry5.de/index.php/2010/07/20/advanced-service-builders-in-tapestry-ioc-chain-of-responsibility-pattern/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/07/20/advanced-service-builders-in-tapestry-ioc-chain-of-responsibility-pattern/#comments</comments>
		<pubDate>Tue, 20 Jul 2010 19:45:55 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Tapestry]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1460</guid>
		<description><![CDATA[In the article Advanced Service Builders in Tapestry IoC: Strategy Pattern I described how to implement the Strategy pattern with Tapestry. In this post I&#8217;ll cover the Gang of Four Chain of Responsibility Pattern. I&#8217;ll start with a simple example that demonstrates how to implement the pattern in Tapestry. At the end of the article, [...]]]></description>
			<content:encoded><![CDATA[<p>In the article <a title="Strategy Pattern" href="http://blog.tapestry5.de/index.php/2010/05/20/advanced-service-builders-in-tapestry-ioc-strategy-pattern/" target="_blank">Advanced Service Builders in Tapestry IoC: Strategy Pattern</a> I described how to implement the Strategy pattern with Tapestry. In this post I&#8217;ll cover the<em> Gang of Four Chain of Responsibility Pattern</em>. I&#8217;ll start with a simple example that demonstrates how to implement the pattern in Tapestry. At the end of the article, I&#8217;ll show you how the <em>Chain of Responsibility Pattern</em> is used inside Tapestry.</p>
<h2>The use case</h2>
<p>Suppose you need to support several authentication mechanisms in your application. Let&#8217;s say you need to support authentication based on both HTTP Basic authentication header (<a title="RFC 1945" href="http://www.ietf.org/rfc/rfc1945.txt" target="_blank">RFC 1945</a>) and HTTP Digest authentication header (<a title="RFC 2617" href="http://www.ietf.org/rfc/rfc2617.txt" target="_blank">RFC 2617</a>). Probably you would specify a service interface like <em>AuthenticationService</em>:</p>
<pre class="brush: java;">public interface AuthenticationService {
   boolean isAuthenticated();
}</pre>
<p>You would also provide two implementations of the service. The implementation details are not interesting yet.</p>
<ul>
<li><em>HttpBasicAuthenticationService</em>: authentication based on HTTP Basic authentication header</li>
</ul>
<ul>
<li><em>HttpDigestAuthenticationService</em>: authentication based on HTTP Digest authentication header</li>
</ul>
<p>Both implementations can be bound to their interface in the application module. Note that you need to provide the service id to disambiguate both implementations of the <em>AuthenticationService</em> interface.</p>
<pre class="brush: java;">public class AppModule {

   public static void bind(ServiceBinder binder) {

      binder.bind(AuthenticationService.class,
                  HttpBasicAuthenticationService.class)
            .withId("HttpBasic");</pre>
<pre class="brush: java;">      binder.bind(AuthenticationService.class,
                  HttpDigestAuthenticationService.class)
            .withId("HttpDigest");
   }
}</pre>
<h2>Naive Approach</h2>
<p>Now let&#8217;s first have a look at a naive usage of the <em>AuthenticationService</em> service. Let&#8217;s implement a simple <a title="Dispatcher" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/services/ComponentRequestFilter.html" target="_blank">ComponentRequestFilter</a> which is responsible for recognizing whether an incoming request is authenticated or not.  In the following example we need to inject both implementations of <em>AuthenticationService</em> service using the <a title="@InjectService annotation" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html" target="_blank">@InjectService</a> annotation. The value of the annotation is used to identify the service to be injected. When a component event request is handled or a page is rendered we check if the request is authenticated by invoking both services <em>HttpBasic</em> and <em>HttpDigest</em> one after another. If the request is unauthenticated, the filter will set the <em>WWW-Authenticate</em> header and send a 401 HTTP error indicating the request requires HTTP authentication.</p>
<pre class="brush: java;">public class AuthenticationFilter implements ComponentRequestFilter {

   @InjectService("HttpBasic")
   private AuthenticationService basicAuthService;

   @InjectService("HttpDigest")
   private AuthenticationService digestAuthService;

   @Inject
   private Response response;

   public void handleComponentEvent(
         ComponentEventRequestParameters parameters,
         ComponentRequestHandler handler) throws IOException {

      if (isAuthenticated()) {
         handler.handleComponentEvent(parameters);
      }
   }

   public void handlePageRender(
         PageRenderRequestParameters parameters,
         ComponentRequestHandler handler) throws IOException {

      if (isAuthenticated()) {
         handler.handlePageRender(parameters);
      }

   }

   private boolean isAuthenticated() throws IOException {

      if (this.basicAuthService.isAuthenticated()) {
         return true;
      }

      if (this.digestAuthService.isAuthenticated()) {
         return true;
      }

      this.response.setHeader("WWW-Authenticate",
            "Basic realm=\"Tapestry\"");

      this.response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
            "Request unauthorized");

      return false;
   }
}</pre>
<p>Injecting both services <em>HttpBasic</em> and <em>HttpDigest</em> and invoking them one after another is not really nice. If you decide to provide a further authentication mechanism in the future, you&#8217;ll have to change the <em>AuthenticationFilter</em> class. Imagine you decided to support the authentication based on a <em>Remember-Me-Token</em>. In this case you need to provide a new implementation of <em>AuthenticationService</em> interface which will be injected into <em>AuthenticationFilter</em> using the service id. Now you have three different instances of <em>AuthenticationService</em> that are invoked one after another.</p>
<h2>Chain of Responsibility</h2>
<p>Now let me show you how to improve our example. We&#8217;ll implement the <em>AuthenticationService</em> as a <em>Chain of Responsibility</em>. Instead of providing different implementations of <em>AuthenticationService</em> interface with dfferent service ids, we use the <a title="ChainBuilder" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/services/ChainBuilder.html" target="_blank">ChainBuilder</a> service to build a chain of <em>AuthenticationService</em> inside a <em>build method</em>.</p>
<p>The <a title="ChainBuilder" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/services/ChainBuilder.html" target="_blank">ChainBuilder</a> service is used to assemble a <em>Chain Of Command</em> implementation of an interface (the <em>command interface</em>) from an ordered list of objects implementing that interface (the <em>commands</em>). The commands of the chain are contributed to the service configuration.</p>
<pre class="brush: java;">public class AppModule {

   public static void contributeAuthenticationService(
       OrderedConfiguration&lt;AuthenticationService&gt; config) {

      config.addInstance("HttpBasic",
              HttpBasicAuthenticationService.class);</pre>
<pre class="brush: java;">      config.addInstance("HttpDigest",
              HttpDigestAuthenticationService.class);
   }

   public static AuthenticationService buildAuthenticationService(
         List&lt;AuthenticationService&gt; configuration,
         ChainBuilder chainBuilder) {

      return chainBuilder.build(AuthenticationService.class,
                                configuration);
   }
}</pre>
<p>The result is that there is a single instance of <em>AuthenticationService</em> service inside the <a title="Registry" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/Registry.html" target="_blank">Registry</a>. You don&#8217;t need to disambiguate different instances of the service by providing unique ids and don&#8217;t have to care which instance to inject. You just inject the <em>AuthenticationService</em> service and use it. Note that we are not using the <a title="@InjectService annotation" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html" target="_blank">@InjectService</a> annotation anymore. Now it is fine to use the <a title="@Inject annotation" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html" target="_blank">@Inject</a> annotation. Tapestry will call the <em>Chain of Command</em> behind the scenes for you. Now <em>AuthenticationFilter</em> can be simplified.</p>
<pre class="brush: java;">public class AuthenticationFilter implements ComponentRequestFilter {

   @Inject
   private AuthenticationService authenticationService;

   @Inject
   private Response response;

   public void handleComponentEvent(
         ComponentEventRequestParameters parameters,
         ComponentRequestHandler handler) throws IOException {

      if (isAuthenticated()) {
         handler.handleComponentEvent(parameters);
      }
   }

   public void handlePageRender(
         PageRenderRequestParameters parameters,
         ComponentRequestHandler handler) throws IOException {

      if (isAuthenticated()) {
         handler.handlePageRender(parameters);
      }

   }

   private boolean isAuthenticated() throws IOException {

      if (this.authenticationService.isAuthenticated()) {
         return true;
      }

      this.response.setHeader("WWW-Authenticate",
            "Basic realm=\"Tapestry\"");

      this.response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
            "Request unauthorized");

      return false;
   }
}</pre>
<p>Now that you know how to create a <em>Chain of Command</em> with Tapestry, let me explain you how Tapestry works down the list of commands.</p>
<h2>ChainBuilder Service</h2>
<p>As you already learned, the <a title="ChainBuilder" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/services/ChainBuilder.html" target="_blank">ChainBuilder</a> service creates a <em>Chain Of Command</em> based on a <em>command interface </em>and <em>commands</em>. Behind the scenes Tapestry generates an implementation of the <em>command interface </em>at runtime. For each method in the interface, the chain implementation will call the corresponding method on each <em>command</em> object in turn.  There are several situations when a chain is terminated:</p>
<ul>
<li>If the return type of the interface method is <em>boolean</em> and a command in the chain returned <em>true</em>.</li>
<li>If the return type of the interface method is numeric and a command in the chain returned a non-zero value.</li>
<li>If the return type of the interface method is other than <em>boolean</em> or numeric and a command in the chain returned a non-null value.</li>
<li>If a command in the chain throws an Exception.</li>
</ul>
<p>Note that in case of <em>void</em> methods only throwing an Exception can terminate the chain.</p>
<p>Now let me explain how chains can be terminated. In the following example you can see <em>HttpBasicAuthenticationService</em> service. It first checks if the <em>Authorization</em> header is set. If the header is not available, then <em>false</em> is returned. In this case the next command in the chain is invoked. If the header is present the command executions continues. If the credentials are available and valid, then <em>true</em> is returned. This terminsates the chain.</p>
<pre class="brush: java;">public class HttpBasicAuthenticationService implements AuthenticationService {
   @Inject
   private Request request;

   public boolean isAuthenticated() {
      String header = this.request.getHeader("Authorization");

      if (header == null || !header.startsWith("Basic ")) {
         return false;
      }

      String[] tokens = getCredentials(header);

      if (tokens.length != 2) {
         return false;
      }

      return tokens[0].equals("igor")
                  &amp;&amp; tokens[1].equals("secret");

   }

   public String[] getCredentials(String header) {
      ...
   }
}</pre>
<h2>Real Life Example</h2>
<p>Now that you know how to implement the <em>Chain Of Command Pattern</em> let me show you how this pattern is used inside Tapestry. As you know Tapestry performs the transformation of the page and component classes at runtime. This bytecode transformation is performed by the <a title="ComponentClassTransformWorker" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/services/ComponentClassTransformWorker.html" target="_blank">ComponentClassTransformWorker</a> service which is implemented as a <em>Chain of Command</em>. The commands of the chain transform a component or page class in turn. For example there is an internal implementation of the  <a title="ComponentClassTransformWorker" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/services/ComponentClassTransformWorker.html" target="_blank">ComponentClassTransformWorker</a> interface which is responsible for transforming a component or a page class in that way that you as page author can inject services into that component or page via <a title="@Inject annotation" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html" target="_blank">@Inject</a> annotation. Another command in the chain is responsible for identifying parameters via the <a title="@Parameter annotation" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/annotations/Parameter.html" target="_blank">@Parameter</a> annotation on component fields. Almost for every annotation, used in a component or a page, there is a specialized command which is a part of the class transformation chain.</p>
<p>Here is see an extract from <a title="TapestryModule" href="http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/services/TapestryModule.html" target="_blank">TapestryModule</a>:</p>
<pre class="brush: java;">public class TapestryModule {

    public void contributeComponentClassTransformWorker(
        OrderedConfiguration&lt;ComponentClassTransformWorker&gt;
                     configuration){

        configuration.addInstance("Inject",
                                  InjectWorker.class);
        configuration.addInstance("InjectService",
                                  InjectServiceWorker.class);
        configuration.addInstance("InjectPage",
                                  InjectPageWorker.class);

        ...

        configuration.add("OnEvent", new OnEventWorker());

        ...
        configuration.addInstance("Parameter",
                                  ParameterWorker.class,
                                  "after:Inject*");
   }

   public ComponentClassTransformWorker buildComponentClassTransformWorker(
         List&lt;ComponentClassTransformWorker&gt; configuration,
         ChainBuilder chainBuilder) {

      return chainBuilder.build(
                           ComponentClassTransformWorker.class,
                           configuration);
   }
}</pre>
<h2>Summary</h2>
<p>In this post I described how to implement <em>Chain of Responsibility Pattern</em> using Tapestry IoC. Based on the authentication example you learned how to decouple a sender of a request and its receiver by giving more than one service a chance to handle the request.</p>
<p>In the next post of this series I&#8217;ll cover further advance techniques for building services. You&#8217;ll learn how to use <em>Shadow services</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/07/20/advanced-service-builders-in-tapestry-ioc-chain-of-responsibility-pattern/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Registry Startup</title>
		<link>http://blog.tapestry5.de/index.php/2010/06/16/registry-startup/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/06/16/registry-startup/#comments</comments>
		<pubDate>Wed, 16 Jun 2010 05:49:42 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Tapestry]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1403</guid>
		<description><![CDATA[In web applications it&#8217;s often necessary to execute extra logic at application startup. When your application is starting, you might want to schedule a task for one-time or repeated execution. A typical use case is the initialization of the database. Imagine you deliver a demo version of your application to a customer in order to [...]]]></description>
			<content:encoded><![CDATA[<p>In web applications it&#8217;s often necessary to execute extra logic at application startup. When your application is starting, you might want to schedule a task for one-time or repeated execution. A typical use case is the initialization of the database. Imagine you deliver a demo version of your application to a customer in order to convince him that you did a better job than your competitors. When the customer drops the WAR file into the servlet container, the application should be usable immediately. In this case you might want to create some demo data (e.g. demo accounts with default credentials) at start time.</p>
<p>In Tapestry you can execute some logic at <a title="Registry" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/Registry.html" target="_blank">Registry</a> startup by making contributions to the <em>RegistryStartup</em> service configuration. The values contributed are <a title="Runnable" href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Runnable.html" target="_blank">Runnable</a> objects. Here is an example:</p>
<pre class="brush: java;">public class AppModule {

  public static void contributeRegistryStartup(
         OrderedConfiguration&lt;Runnable&gt; configuration,
         DatabaseStartup dbStartup) {

      configuration.add("DbStartup", new Runnable() {
          dbStartup.init();
      }, "before:*");
  }
}</pre>
<h2>Startup Methods in Tapestry 5.2</h2>
<p>In Tapestry 5.2 the way of providing extra logic to be executed at <a title="Registry" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/Registry.html" target="_blank">Registry</a> startup has been simplified. Instead of making contributions to the <em>RegistryStartup</em> service configuration you can provide startup methods inside your modules. As you can see in the following example you just annotate an arbitrary module method with @Startup annotation and that&#8217;s it. Tapestry will detect these methods and invoke them after the registry has been started.</p>
<pre class="brush: java;">public class AppModule {

  @Startup
  public static void initApplication(DatabaseStartup dbStartup) {
      dbStartup.init();
  }
}</pre>
<p>Note that <em>RegistryStartup</em> service configuration is ordered. Providing the order constraint it&#8217;s possible to control in what order the contributions are executed. In contrast the order of startup methods is determined by the alphabetical order of the method names. You should not rely on that. The alphabetical ordering of module methods is a part of the internal API and may be changed in the upcoming releases.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/06/16/registry-startup/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Manning Publications translates my Tapestry 5 book</title>
		<link>http://blog.tapestry5.de/index.php/2010/06/11/manning-publications-translates-my-tapestry-5-book/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/06/11/manning-publications-translates-my-tapestry-5-book/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 22:55:49 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Tapestry]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1375</guid>
		<description><![CDATA[I&#8217;m pleased to announce the amazing news. Manning Publications Co. will translate my Tapestry 5 book into English. Tapestry folks have been waiting for a book on Tapestry 5 for a long time and I&#8217;m excited to finally move forward with this book. We have a great team. Joachim Van der Auwera will translate the [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m pleased to announce the amazing news. <a title="Manning" href="http://www.manning.com/" target="_blank">Manning Publications Co.</a> will translate my <a title="Tapestry 5 Boook" href="http://www.amazon.de/gp/product/3827328446/ref=s9_simh_gw_p14_i1?pf_rd_m=A3JWKAKR8XB7XF&amp;pf_rd_s=center-1&amp;pf_rd_r=0K9HQ9YY1NAX93E735RG&amp;pf_rd_t=101&amp;pf_rd_p=463375193&amp;pf_rd_i=301128" target="_blank">Tapestry 5 book</a> into English. Tapestry folks have been waiting for a book on Tapestry 5 for a long time and I&#8217;m excited to finally move forward with this book.</p>
<p>We have a great team.<a title="Joachim Van der Auwera" href="http://www.progs.be/cv.html" target="_blank"> Joachim Van der Auwera</a> will translate the German copy into English. I&#8217;ll update the translated book with the Tapestry 5.2 contents. There is a lot of innovative stuff in the 5.2 trunk the world should know about. I&#8217;m also going to extend some chapters which were covered in the German version not in the depth. Maybe some of the articles from this blog will be available in the book. The German version has around 430 pages. The Manning book on Tapestry will get additional 50 &#8211; 70 pages. Finally <a title="Howard Lewis Ship" href="http://www.howardlewisship.com/" target="_blank">Howard Lewis Ship</a> is interested in joining the project as technical editor. If Howard will be available he will review whether the book covers his vision of Tapestry.</p>
<p>I would like to thank Angelika Ritthaler from<a title="Addison Wesley" href="http://addison-wesley.de/" target="_blank"> Addison Wesley</a> and Christina Rudloff from <a title="Manning" href="http://www.manning.com/" target="_blank">Manning Publications  Co.</a> for making this book real.</p>
<p>Stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/06/11/manning-publications-translates-my-tapestry-5-book/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>First Impressions From Jazoon</title>
		<link>http://blog.tapestry5.de/index.php/2010/06/04/first-impressions-from-jazoon/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/06/04/first-impressions-from-jazoon/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 06:38:58 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Tapestry]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1350</guid>
		<description><![CDATA[The Jazoon 2010 is closed. I enjoyed the most of the talks and met some folks. My talk JavaServer Faces 2.0 vs. Tapestry 5 took place on Thursday, 3 June in the arena 7. Unfortunately my presentation will not be available as video since only talks in the largest arena 5 has been recorded. The [...]]]></description>
			<content:encoded><![CDATA[<p>The Jazoon 2010 is closed. I enjoyed the most of the talks and met some folks. My talk <a title="JSF 2.0 vs. Tapestry 5" href="http://blog.tapestry5.de/index.php/2010/03/30/jazoon-2010-talk-javaserver-faces-2-0-vs-tapestry-5/">JavaServer Faces 2.0 vs. Tapestry 5</a> took place on Thursday, 3 June in the arena 7. Unfortunately my presentation will not be available as video since only talks in the largest arena 5 has been recorded. The slides of the talk are available <a title="Slides" href="http://blog.tapestry5.de/wp-content/uploads/2010/06/JSF-2.0-vs-Tapestry-5.pdf" target="_blank">here</a>. However, I enjoyed the conference and will submit some presentation proposals next year again.</p>
<p>Directly after my talk <a title="Roger Kitains" href="http://www.java.net/blogs/rogerk" target="_blank">Roger  Kitains</a>, a JSF co-specification lead, was giving a presentation <a title="Exploring HTML5 With JavaServer Faces 2.0" href="http://jazoon.com/Conference/Thursday/Kitain" target="_blank">Exploring  HTML5 With JavaServer Faces 2.0</a>. He was attending my presentation and I had the pleasure to discuss Tapestry and JSF with him. Roger told me he enjoyed my talk and was impressed by Tapestry. He likes Tapestry&#8217;s annotation-based approach and implicit type conversion which probably will be adapted in the upcoming JSF version.</p>
<p>Also <a title="Andy Bosch" href="http://jazoon.com/Conference/Thursday/Bosch" target="_blank">Andy Bosch</a>, another JSF guru, was attending my talk. He was impressed by the Live Class Reloading feature. Probably we&#8217;ll give together a JSF vs. Tapestry talk in the future. I believe that such a talk would be very funny. I would concentrate on Tapestry part and he would present JSF.</p>
<p>I also had a chance to meet <a title="Evgeni Kabanov" href="http://www.ekabanov.net/" target="_blank">Evgeni Kabanov</a>, the founder and CTO of <a title="ZeroTurnaround" href="http://www.zeroturnaround.com/" target="_blank">ZeroTurnaround</a>, who gave an amazing <a title="Did you really get classloaders?" href="http://jazoon.com/Conference/Tuesday/Kabanov" target="_blank">talk on class loaders</a>. I was interested in his talk and was not disappointed. We discovered Zurich together and had the pleasure to discuss the <a title="Live Class Reloading" href="http://tapestry.apache.org/tapestry5.1/guide/reload.html" target="_blank">Live Class Realoading</a> in Tapestry and <a title="JRebel" href="http://www.zeroturnaround.com/jrebel/" target="_blank">JRebel</a> during a dinner in a Japanese restaurant. By the way, if some of the readers is not using Tapestry but wants to be productive, you should give JRebel a try.</p>
<p>As summary of my talk I will publish a series of articles on JSF vs. Tapestry topic in order to share with you the result of my research.</p>
<p>Here are some pics which has been taken during my presentation.</p>
<p><a href="http://blog.tapestry5.de/wp-content/uploads/2010/06/jazoon1.jpg"><img class="aligncenter size-full wp-image-1353" title="jazoon1" src="http://blog.tapestry5.de/wp-content/uploads/2010/06/jazoon1.jpg" alt="" width="500" height="333" /></a></p>
<p><a href="http://blog.tapestry5.de/wp-content/uploads/2010/06/jazoon2.jpg"><img class="aligncenter size-full wp-image-1354" title="jazoon2" src="http://blog.tapestry5.de/wp-content/uploads/2010/06/jazoon2.jpg" alt="" width="500" height="333" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/06/04/first-impressions-from-jazoon/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Speaking slot at Jazoon 2010 changed</title>
		<link>http://blog.tapestry5.de/index.php/2010/05/30/speaking-slot-at-jazoon-2010-changed/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/05/30/speaking-slot-at-jazoon-2010-changed/#comments</comments>
		<pubDate>Sun, 30 May 2010 19:58:49 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1339</guid>
		<description><![CDATA[The Jazoon program committee moved the speaking slot for my talk JavaServer Faces 2.0 vs. Tapestry 5 from 13:30 t0 11:30. I&#8217;ll be speaking Thursday, 3 June 2010, 11:30-12:20 at Arena 7. More details can be found here. See you there!]]></description>
			<content:encoded><![CDATA[<p>The <a title="Jazoon" href="http://jazoon.com" target="_blank">Jazoon</a> program committee moved the speaking slot for my talk <a title="JSF 2.0 vs. Tapestry 5" href="http://blog.tapestry5.de/index.php/2010/03/30/jazoon-2010-talk-javaserver-faces-2-0-vs-tapestry-5/" target="_blank">JavaServer Faces 2.0 vs. Tapestry 5</a> from 13:30 t0 11:30. I&#8217;ll be speaking Thursday, 3 June 2010, 11:30-12:20 at Arena 7. More details can be found <a title="JSF 2.0 vs. Tapestry 5" href="http://jazoon.com/Conference/Thursday/Drobiazko" target="_blank">here</a>.</p>
<p>See you there!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/05/30/speaking-slot-at-jazoon-2010-changed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Remote Page Pool Management</title>
		<link>http://blog.tapestry5.de/index.php/2010/05/28/remote-page-pool-management/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/05/28/remote-page-pool-management/#comments</comments>
		<pubDate>Fri, 28 May 2010 17:02:19 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Tapestry]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1299</guid>
		<description><![CDATA[When talking about Tapestry I&#8217;m often asked about the proper page pool settings. It seems that a lot of Tapestry users bother their head about the proper settings. It&#8217;s hardly surprising me because you never know how many hits your application will be receiving. Thus my answer to the question is always: &#8220;It depends!&#8221;. As [...]]]></description>
			<content:encoded><![CDATA[<p>When talking about Tapestry I&#8217;m often asked about the proper page pool settings. It seems that a lot of Tapestry users bother their head about the proper settings. It&#8217;s hardly surprising me because you never know how many hits your application will be receiving. Thus my answer to the question is always: &#8220;It depends!&#8221;.</p>
<p>As of version 5.2 you don&#8217;t have to think about your page pool settings until your application is launched because you can modify these settings remotely. Tapestry registers a <a title="MBean" href="http://java.sun.com/docs/books/tutorial/jmx/mbeans/standard.html" target="_blank">managed bean (MBean)</a> with an MBean server. You can use <a title="JConsole" href="http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html" target="_blank">JConsole</a> to interact with the registered MBean. To enable the JMX agent for local access, you need to set the following system property when you start your web server:</p>
<pre class="brush: java;">-Dcom.sun.management.jmxremote</pre>
<p>When you start <a title="JConsole" href="http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html" target="_blank">JConsole</a> you will see an MBean registered by Tapestry.  This MBean has 4 writable properties:</p>
<ul>
<li><em>SoftLimit</em> corresponds to symbol <em>tapestry.page-pool.soft-limit</em></li>
<li><em>SoftWait</em> corresponds to symbol <em>tapestry.page-pool.soft-wait</em></li>
<li><em>HardLimit</em> corresponds to symbol <em>tapestry.page-pool.hard-limit</em></li>
<li><em>ActiveWindow</em> corresponds to symbol <em>tapestry.page-pool.active-window</em></li>
</ul>
<p style="text-align: center;"><a href="http://blog.tapestry5.de/wp-content/uploads/2010/05/remote_pool_management.png"><img class="aligncenter size-full wp-image-1298" title="remote_pool_management" src="http://blog.tapestry5.de/wp-content/uploads/2010/05/remote_pool_management.png" alt="" width="613" height="478" /></a></p>
<p>For more details about page pool settings read <a title="Page Pool Configuration" href="http://tapestry.apache.org/tapestry5.1/guide/lifecycle.html" target="_blank">here</a> and <a title="Configuring Tapestry" href="http://tapestry.apache.org/tapestry5.1/guide/conf.html" target="_blank">here</a>. Also note that symbol <em>tapestry.page-pool.hard-limit</em><em> </em>was deprecated in Tapestyr 5.2 because the number of request processing threads can also be configured by the servlet  container.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/05/28/remote-page-pool-management/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Project Management Committee Member</title>
		<link>http://blog.tapestry5.de/index.php/2010/05/26/project-management-committee-member/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/05/26/project-management-committee-member/#comments</comments>
		<pubDate>Wed, 26 May 2010 08:47:47 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Tapestry]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1205</guid>
		<description><![CDATA[I&#8217;ve been promoted to the Project Management Committee (PMC) role. At the Apache Software Foundation a PMC is the official managing body of a project and is responsible for the strategic direction and success of the project. One of my roles as PMC will be Tapestry marketing and evangelization. I&#8217;ll try to make Tapestry more [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been promoted to the <a title="PMC" href="http://www.apache.org/foundation/how-it-works.html#pmc" target="_blank">Project Management Committee (PMC)</a> role. At the Apache Software Foundation a PMC is the official managing body of a project and is responsible for the strategic direction and success of the project. One of my roles as PMC will be Tapestry marketing and evangelization. I&#8217;ll try to make Tapestry more popular in Europe, especially in Germany.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/05/26/project-management-committee-member/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Advanced Service Builders in Tapestry IoC: Strategy Pattern</title>
		<link>http://blog.tapestry5.de/index.php/2010/05/20/advanced-service-builders-in-tapestry-ioc-strategy-pattern/</link>
		<comments>http://blog.tapestry5.de/index.php/2010/05/20/advanced-service-builders-in-tapestry-ioc-strategy-pattern/#comments</comments>
		<pubDate>Thu, 20 May 2010 15:02:51 +0000</pubDate>
		<dc:creator>Igor Drobiazko</dc:creator>
				<category><![CDATA[Tapestry]]></category>

		<guid isPermaLink="false">http://blog.tapestry5.de/?p=1120</guid>
		<description><![CDATA[As you might probably know Tapestry IoC is the heart and sole of Tapestry.  Almost every Tapestry feature is the result of the architecture based on Tapestry IoC. This is why Tapestry is so exciting and cool. The ideas behind Tapestry IoC are so beautiful that I can&#8217;t live without them. In my daily job [...]]]></description>
			<content:encoded><![CDATA[<p>As you might probably know Tapestry IoC is the heart and sole of Tapestry.  Almost every Tapestry feature is the result of the architecture based on Tapestry IoC. This is why Tapestry is so exciting and cool.</p>
<p>The ideas behind Tapestry IoC are so beautiful that I can&#8217;t live without them. In my daily job I&#8217;m using Tapestry IoC in non-web applications as well as in Tapestry applications. Occasionally I&#8217;m browsing the source code of open source or commercial Tapestry-based applications and wonder that some developers don&#8217;t use the best features of Tapestry IoC. I guess it&#8217;s because they are not aware of these features. That&#8217;s why I&#8217;ll publish a series of articles on advanced techniques to build services. The series starts with the <em>Go4 Strategy Pattern</em>. Let&#8217;s start with a very easy example.</p>
<h2>Introduction to Strategy Pattern</h2>
<p>Suppose you are writing an online shop such as Amazon. All the products are stored in a storage (such as a database). When you display a product to a customer you need to show the price of the product. Now imagine you are located in a country that has different sales tax rates for different goods. For example Germany has a 19% sales tax for non-book-goods. The sales tax for books and newspapers is only 7%. As you can see in the following example we need ugly if-else-statements when determining the sales tax rate of an item.</p>
<pre class="brush: java;">public class SalesTaxRateSourceImpl implements SalesTaxRateSource {

   public Double getRate(Item item) {

      if(item instanceof Book || item instanceof Newspaper) {
         return 1.07;
      }

      return 1.19;
   }
}</pre>
<p>Let&#8217;s rewrite the implementation of <em>SalesTaxRateSource</em> service implementing the <em>Gang of Four Strategy Pattern</em>. The idea is to implement different strategies for calculation of sales tax rates. The strategies are:</p>
<ul>
<li> <em>DefaultSalesTaxRateSource</em>: provides the sales tax rate of 19%</li>
<li> <em>ReducedSalesTaxRateSource</em>: provides the reduced sales tax rate of 7%</li>
</ul>
<p>The implementations of the interfaces may look like follows.</p>
<pre class="brush: java;">public class DefaultSalesTaxRateSource implements SalesTaxRateSource{

   public Double getRate(Item item) {
      return 1.19;
   }
}</pre>
<pre class="brush: java;">public class ReducedSalesTaxRateSource implements SalesTaxRateSource{

   public Double getRate(Item item) {
      return 1.07;
   }
}</pre>
<p>Now we need to map these two implementations of the <em>SalesTaxRateSource</em> interface to certain implementations of the <em>Item</em> interface. This can be done in a contribute method for the <em>SalesTaxRateSource</em> service. Note that we map <em>Book</em> and <em>Newspaper</em> to <em>ReducedSalesTaxRateSource</em>. All the other implementations of <em>Item</em> are mapped to <em>DefaultSalesTaxRateSource</em>. This configuration is used to construct a strategy-based implementation of <em>SalesTaxRateSource</em> service.  For this purpose we create a <em>StrategyRegistry</em> from the contributed configuration inside the <em>buildSalesTaxRateSource() </em>method. The injected service <a title="StrategyBuilder" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/services/StrategyBuilder.html" target="_blank">StrategyBuilder</a> is used to create an implementation of <em>SalesTaxRateSource </em>from <em>StrategyRegistry </em>on-the-fly.</p>
<p>The <em>StrategyBuilder </em>service creates an implementation which uses all the configured strategies behind the scenes. It executes all the ugly if-else-statements for you. It analyzes the first parameter of each service method to select the appropriate strategy. In our case we have only one service method with a single parameter.</p>
<pre class="brush: java;">public class AppModule {

    public static void contributeSalesTaxRateSource(
          MappedConfiguration&lt;Class, SalesTaxRateSource&gt; config) {

        config.addInstance(Item.class,
                           DefaultSalesTaxRateSource.class);

        config.addInstance(Book.class,
                           ReducedSalesTaxRateSource.class);

        config.addInstance(Newspaper.class,
                           ReducedSalesTaxRateSource.class);

	}

    public static SalesTaxRateSource buildSalesTaxRateSource(
            Map&lt;Class, SalesTaxRateSource&gt; configuration,
            StrategyBuilder strategyBuilder) {

        StrategyRegistry&lt;SalesTaxRateSource&gt; registry
                = StrategyRegistry.newInstance(
                    SalesTaxRateSource.class, configuration);

        return strategyBuilder.build(registry);
    }

}</pre>
<p>You might ask yourself why you need this advanced service builder technique. You could manage different strategies in a simple map and just ask a strategy for a class. That&#8217;s almost correct but leaks one important feature <a title="StrategyRegistry" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/util/StrategyRegistry.html" target="_blank">StrategyRegistry</a> offers. The lookup of strategies inside <a title="StrategyRegistry" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/util/StrategyRegistry.html" target="_blank">StrategyRegistry</a> is based on an inheritance search. This is the reason why we mapped <em>Item</em> to <em>DefaultSalesTaxRateSource</em>. All <em>Item</em> implementations but <em>Book</em> and <em>Newspaper</em> are mapped to <em>DefaultSalesTaxRateSource</em>.</p>
<p>Now let me demonstrate the advantage of the inheritance-based strategy search. Imagine you extracted a common interface from <em>Book</em> and <em>Newspaper</em>: let&#8217;s say it is called <em>Readable</em>. Now the contribution can be simplified because you don&#8217;t need to map both <em>Book</em> and <em>Newspaper</em> to the same strategy. You only need to map their common interface:</p>
<pre class="brush: java;">public class AppModule {

    public static void contributeSalesTaxRateSource(
          MappedConfiguration&lt;Class, SalesTaxRateSource&gt; config) {

        config.addInstance(Item.class,
                           DefaultSalesTaxRateSource.class);

        config.addInstance(Readable.class,
                           ReducedSalesTaxRateSource.class);

	}
    ...
}</pre>
<h2>Real Life Example</h2>
<p>Now that you know how to use Strategy pattern with Tapestry IoC, let&#8217;s see how this pattern is used inside Tapestry. As you might know event handler methods may have different return types. The value returned from an event handler method determines how Tapestry will render a response. This is accomplished by the <a title="ComponentEventResultProcessor" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/services/ComponentEventResultProcessor.html" target="_blank">ComponentEventResultProcessor</a> service which is implemented as Strategy pattern. This service is built from a <a title="StrategyRegistry" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/ioc/util/StrategyRegistry.html" target="_blank">StrategyRegistry</a> which is responsible for matching up a given return type of an event handler method with a registered strategy for that type. When Tapestry handles an event it analyzes the return type of the  handler method and selects  a strategy to handle the returned type. The allowed return types are described <a title="Return Types" href="http://tapestry.apache.org/tapestry5.1/guide/pagenav.html" target="_blank">here</a>.</p>
<p>In the following example you can see a <em>Demo</em> page with two handler methods for the <em>action</em> event.</p>
<pre class="brush: java;">public class Demo {

    public Object onActionFromInternalLink() {
        return NextPage.class
    }

    public Object onActionFromExternalLink()
                throws MalformedURLException {
        return new URL("http://tapestry5.de/");
    }
}</pre>
<p>The method <em>onActionFromInternalLink()</em> handles the event <em>action</em> that was fired by the component with id <em>internalLink</em>. The value returned by this method is a class of a page named <em>NextPage</em>. When this method is invoked, Tapestry will lookup a strategy to handle the result type <em>java.lang.Class</em>.  The responsible strategy is the class <a title="ClassResultProcessor" href="http://tapestry.apache.org/tapestry5.1/apidocs/org/apache/tapestry5/internal/services/ClassResultProcessor.html" target="_blank">ClassResultProcessor</a> which just creates an internal link to a page and sends a redirect to that link. In case of method <em>onActionFromExternalLink()</em> Tapestry will find a  strategy which is responsible to send a redirect to a URL.</p>
<p>Here is the simplified extract from TapestryModule:</p>
<pre class="brush: java;">public class TapestryModule {

    public void contributeComponentEventResultProcessor(
        MappedConfiguration&lt;Class, ComponentEventResultProcessor&gt;
                     configuration){

        configuration.add(
            URL.class,
            new ComponentEventResultProcessor&lt;URL&gt;() {
                public void processResultValue(URL value)
                           throws IOException
                    response.sendRedirect(value.toExternalForm());
            }
        });

        configuration.addInstance(
            Class.class, ClassResultProcessor.class);
    }
}</pre>
<h2>Summary</h2>
<p>In this post I described how to implement <em>Strategy Pattern</em> using Tapestry IoC. Hopefully this post will help you to clean up your code by removing ugly if-else-statements. If you are not using Tapestry yet, you should give Tapestry IoC a try.</p>
<p>In the next post I&#8217;ll cover the <em>Gang of Four Chain of Responsibility Pattern</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tapestry5.de/index.php/2010/05/20/advanced-service-builders-in-tapestry-ioc-strategy-pattern/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
