<?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>spread the source &#187; tapestry</title>
	<atom:link href="http://spreadthesource.com/category/tapestry/feed/" rel="self" type="application/rss+xml" />
	<link>http://spreadthesource.com</link>
	<description>Web dev blog about Java, Tapestry and many others</description>
	<lastBuildDate>Mon, 08 Nov 2010 11:51:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Bringing realtime to your Java applications with WebSockets, NodeJS, Redis, Tapestry 5</title>
		<link>http://spreadthesource.com/2010/11/bringing-realtime-to-your-java-applications-with-websockets-nodejs-redis-tapestry-5/</link>
		<comments>http://spreadthesource.com/2010/11/bringing-realtime-to-your-java-applications-with-websockets-nodejs-redis-tapestry-5/#comments</comments>
		<pubDate>Mon, 08 Nov 2010 11:49:50 +0000</pubDate>
		<dc:creator>Robin Komiwes</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[tapestry]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=394</guid>
		<description><![CDATA[More than a decade ago, web pages were just statics. Some years ago, they were statics with some partial reloading. Now, users expect notifications, chats, events. Users expect you to provide realtime content. Fortunately, there is a new standard for that. Having a streaming channel between the server and the client can be done using [...]]]></description>
			<content:encoded><![CDATA[<p>More than a decade ago, web pages were just statics. Some years ago, they were statics with some partial reloading. Now, users expect notifications, chats, events.<strong> Users expect you to provide realtime content</strong>.</p>
<p>Fortunately, there is a new standard for that. Having a streaming channel between the server and the client can be done using the <a href="http://dev.w3.org/html5/websockets/">WebSocket API</a>.</p>
<p>Unfortunately, there is one major issue with realtime: scalability. Realtime means more connections, more data exchanges. Most web servers today are using threads to handle requests. Threads based networking doesn&#8217;t scale, as you will face <a href="http://www.kegel.com/c10k.html">performance and locking issues</a>. Java web servers like Jetty, Tomcat, Glassfish etc. are using threads.</p>
<p>In fact, most web frameworks today will make you create web sites that are going to be deployed on thread based web servers. There is a fundamental problem here if you want to provide realtime stuff. You have to look for others technologies, and the big challenger today is NodeJS.</p>
<p>I wanted since many weeks to try <a href="http://nodejs.org/">NodeJS</a>, especially in order to bring realtime through WebSockets to my applications. NodeJS&#8217; goal is to provide scalables network programs. Basically it&#8217;s JavaScript plus an I/O layer. You write in Javascript, and your code is executed using V8, the Google&#8217;s open source JavaScript engine, the one used by Google Chrome. NodeJS tends to be the solution to scalability problems.</p>
<p>That&#8217;s fine, but does it means that you have to stop using your favorite web framework in order to do only NodeJS? Nop. You can employ NodeJS to just handle the realtime aspects of your applications, like broadcasting notifications. What you need then is just a bridge between NodeJS and your favorite web framework.</p>
<p>As I&#8217;m starting my own business, I do some Ruby now, and I started to play with NodeJS and Ruby on Rails. I made the bridge between the two platforms with <a href="http://code.google.com/p/redis/">Redis</a>, using the <a href="http://www.slideshare.net/mbleigh/nodejs-and-ruby">publish/subscribe feature</a>. Redis is a lightweight and very fast advanced key-value datastore. Benchmarks show performances about &#8220;<em>110000 SETs/second, 81000 GETs/second in an entry level Linux box</em>&#8220;. In fact, Redis has been designed for performance. Since Redis 2.0, there is now a publish/subscribe feature, especially <a href="http://antirez.com/post/redis-weekly-update-3-publish-submit.html">designed to trap changes</a>. Redis is supported by tons of languages, as NodeJS, Ruby and Java.</p>
<p>So let&#8217;s summarize what could be the global architecture. Your base application will publish events using Redis. NodeJS will subscribe to this Redis channel and as soon as an event is caught, NodeJS will relay it to subscribed end users through WebSocket API.</p>
<p>I wanted to experiment the same technique with Java instead of Ruby. I used the Tapestry 5 Hotel Booking application to achieve that. And here is how.</p>
<p><span id="more-394"></span></p>
<h3>Overview</h3>
<p>The goal is to provide a monitor page that will display in realtime every booking made by users.</p>
<p>Code provided is an experiment, please don&#8217;t use it as it in production. It should be used only for testing purpose.</p>
<h3>The environment</h3>
<p>Get <a href="http://code.google.com/p/redis/">Redis </a>and <a href="http://nodejs.org/">NodeJS</a> for your platform. They are both designed to run on POSIX platforms, which basically means *not Windows*, but they are some binaries for Windows avaible for both <a href="http://code.google.com/p/servicestack/wiki/RedisWindowsDownload">here</a> and <a href="http://node-js.prcn.co.cc/">here</a>, and they should integrate your cygwin quite well (just make them available in your PATH).</p>
<p>Checkout the <a href="https://github.com/ccordenier/tapestry5-hotel-booking">Tapestry 5 Hotel Booking application</a>.</p>
<p>Edit <code>pom.xml</code> to add the <a href="https://github.com/xetorthio/jedis">Jedis</a> artifact which is a Java Redis client. There are some others distributions, but there are not all available as Maven artifacts. Some of them are respecting the JDBC standard, but JDBC was designed for relational databases, and Redis is not a relational one.</p>
<pre class="brush: xml;">
		&lt;dependency&gt;
			&lt;groupId&gt;redis.clients&lt;/groupId&gt;
			&lt;artifactId&gt;jedis&lt;/artifactId&gt;
			&lt;version&gt;1.3.0&lt;/version&gt;
			&lt;type&gt;jar&lt;/type&gt;
			&lt;scope&gt;compile&lt;/scope&gt;
		&lt;/dependency&gt;</pre>
<h3>Make Redis available in your application</h3>
<p>We want to have a service in our application that will makes it possible to publish messages on channels. Let&#8217;s define the service respecting the Tapestry way of things.</p>
<h4>RedisPublisher</h4>
<pre class="brush: java;">
package com.tap5.hotelbooking.services;

public interface RedisPublisher
{
    void publish(String channel, String message);
}
</pre>
<h4>RedisPublisherImpl</h4>
<pre class="brush: java;">
package com.tap5.hotelbooking.services;

import org.apache.tapestry5.ioc.ScopeConstants;
import org.apache.tapestry5.ioc.annotations.Scope;

import redis.clients.jedis.Jedis;

@Scope(value = ScopeConstants.PERTHREAD)
public class RedisPublisherImpl implements RedisPublisher
{
    private Jedis jedis;

    public RedisPublisherImpl()
    {
        this.jedis = new Jedis(&quot;localhost&quot;);
    }

    public void publish(String channel, String message)
    {
        jedis.publish(channel, message);
    }

}
</pre>
<p>Note that <code>@Scope(value = ScopeConstants.PERTHREAD)</code> is used here. It means that we are going to make one connection to Redis per request. That&#8217;s <a href="http://www.quora.com/What-are-the-best-practices-for-managing-connections-to-Redis-from-a-Django-app">a good balance</a> between a persistent connection and a connection for every Redis action.</p>
<p>Let&#8217;s add the service declaration in the application module. </p>
<h4>HotelBookingModule.java</h4>
<pre class="brush: java; highlight: [4];">
    public static void bind(ServiceBinder binder)
    {
        binder.bind(Authenticator.class, BasicAuthenticator.class);
        binder.bind(RedisPublisher.class, RedisPublisherImpl.class);
    }
</pre>
<p>Each time a booking is made, we want it to be published to Redis. Let&#8217;s edit the Book page.</p>
<h4>Book.java</h4>
<pre class="brush: java; highlight: [10];">
...
@OnEvent(value = EventConstants.SUCCESS, component = &quot;confirmForm&quot;)
    public Object confirm()
    {
        // Create
        dao.create(booking);

        userWorkspace.confirmCurrentBooking(booking);

        publisher.publish(&quot;booking:&quot; + booking.getId() + &quot;:hotel&quot;, booking.getHotel().getName());

        booking = null;

        // Return to search
        return Search.class;
    }
...
</pre>
<p>I suggest you to <a href="http://code.google.com/p/redis/wiki/index">learn Redis</a> if you want to understand the channel declaration <code>"booking:" + booking.getId() + ":hotel"</code></p>
<h3>The Monitor page</h3>
<p>This page is fairly simple. You just need to include some scripts. I used jquery, a simple websocket client and a custom script to display messages.</p>
<h4>Monitor.java</h4>
<pre class="brush: java;">
package com.tap5.hotelbooking.pages;

import org.apache.tapestry5.annotations.Import;

@Import(library =
{ &quot;context:/js/jquery.1.4.3.min.js&quot;, &quot;context:/js/ws.js&quot;,
        &quot;context:/js/scripts.js&quot; })
public class Monitor
{

}
</pre>
<h4>Monitor.tml</h4>
<pre class="brush: xml;">
&lt;html t:type=&quot;layout&quot; t:pageTitle=&quot;Hotel details&quot;
      xmlns:t=&quot;http://tapestry.apache.org/schema/tapestry_5_1_0.xsd&quot;
      xmlns:p=&quot;tapestry:parameter&quot;&gt;
        &lt;!-- Most of the page content, including &lt;head&gt;, &lt;body&gt;, etc. tags, comes from Layout.tml --&gt;

	&lt;h2&gt;Monitor booking... in realtime!&lt;/h2&gt;

	&lt;div id=&quot;log&quot;&gt;&lt;/div&gt;

	&lt;p:sidebar&gt;
        &lt;p&gt;
        	Tapestry has an existing set of components that will help you to quickly
        	handle common stuff. Displaying Javabean properties, generate form from Javabean,
        	display tabular datas... All of these to get a clean and efficient template's code.
        &lt;/p&gt;
	&lt;/p:sidebar&gt;

&lt;/html&gt;
</pre>
<h4>src/main/webapp/js/ws.js</h4>
<pre class="brush: jscript;">
var conn;
var connect;

(function($) {

connect = function() {
  if (window[&quot;WebSocket&quot;]) {
    conn = new WebSocket(&quot;ws://localhost:8000/test&quot;);
    conn.onmessage = function(evt) {
      $(window).trigger('WSmessage',evt.data);
    };
  }
};

})(jQuery);
</pre>
<h4>src/main/webapp/js/script.js</h4>
<pre class="brush: jscript;">
var $j = jQuery.noConflict();

(function($) {

	jQuery.fn.log = function(msg) {
		if (window.console != undefined)
			console.log(&quot;%s: %o&quot;, msg, this);
		return this;
	};

	$(window).load(function() {
		$(window).bind(&quot;WSmessage&quot;, function(e, data) {
			$(&quot;#log&quot;).append(data + &quot;&lt;br /&gt;&quot;);
		});

		if (!conn) {
			connect();
		}
	});

})(jQuery);
</pre>
<p>Don&#8217;t forget to get JQuery 1.4.3 from <a href="http://jquery.com/">the official website</a>, and put it in <code>src/main/webapp/js</code>.</p>
<h3>Server side JavaScript</h3>
<p>Finally, here comes the time to play with NodeJS!</p>
<p>I&#8217;ve put everything under <code>src/nodejs</code></p>
<p>First, let&#8217;s download some libraries. A <a href="https://github.com/miksago/node-websocket-server/tree/master/lib/">Websocket server implementation</a>, and a <a href="https://github.com/fictorial/redis-node-client/tree/master/lib/">Redis client</a>.<br />
Move <code>redis-client.js</code>, <code>ws.js</code> and <code>ws/</code> to <code>src/nodejs/lib</code></p>
<p>Let&#8217;s now create the NodeJS server itself in <code>src/nodejs</code>. Code is based on one of the examples distributed with the WebSocket server implementation repository.</p>
<h4>realtime-server.js</h4>
<pre class="brush: jscript; highlight: [13,14,15,16,17,18,19,20,21];">
var sys = require(&quot;sys&quot;),
 	fs = require(&quot;fs&quot;),
 	path = require(&quot;path&quot;),
 	http = require(&quot;http&quot;),
 	ws = require('./lib/ws'),
	redis = require(&quot;./lib/redis-client&quot;);;

var pubsub = redis.createClient();

var connect;

pubsub.stream.addListener('connect', function() {
	pubsub.subscribeTo('booking:*:hotel', function(channel, data) {
		var bid = channel.toString().split(':')[1];
		sys.debug(&quot;Publishing new booking : &quot; + bid);

		if (connect) {
			connect.write(data);
		}

	});
});

/*-----------------------------------------------
  logging:
-----------------------------------------------*/
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

function pad(n) {
  return n &lt; 10 ? '0' + n.toString(10) : n.toString(10);
}

function timestamp() {
  var d = new Date();
  return [
    d.getDate(),
    months[d.getMonth()],
    [ pad(d.getHours())
    , pad(d.getMinutes())
    , pad(d.getSeconds())
    , (d.getTime() + &quot;&quot;).substr( - 4, 4)
    ].join(':')
  ].join(' ');
};

function log(msg) {
  sys.puts(timestamp() + ' - ' + msg.toString());
};

function serveFile(req, res){};

/*-----------------------------------------------
  Spin up our server:
-----------------------------------------------*/
var httpServer = http.createServer(serveFile);

var server = ws.createServer({
  debug: true
}, httpServer);

server.addListener(&quot;listening&quot;, function(){
  log(&quot;Listening for connections.&quot;);
});

// Handle WebSocket Requests
server.addListener(&quot;connection&quot;, function(conn){
  log(&quot;opened connection: &quot;+conn.id);

  connect = conn;

  conn.broadcast(&quot;&lt;&quot;+conn.id+&quot;&gt; connected&quot;);

  conn.addListener(&quot;message&quot;, function(message){
    log(&quot;&lt;&quot;+conn.id+&quot;&gt; &quot;+message);
    conn.broadcast(message);
  });
});

server.addListener(&quot;close&quot;, function(conn){
  log(&quot;closed connection: &quot;+conn.id);
  conn.broadcast(&quot;&lt;&quot;+conn.id+&quot;&gt; disconnected&quot;);
});

server.listen(8000);
</pre>
<h3>Run everything and test!</h3>
<p>Run <code>redis-server</code></p>
<p>Run the Java application with <code>mvn jetty:run</code></p>
<p>Run the NodeJS server with <code>node realtime-server.js</code> in <code>src/nodejs</code></p>
<p>Open two browser windows (with a browser that support WebSocket of course, like Google Chrome). First window should go to <code>http://localhost:8080/tapestry5-hotel-booking/monitor</code>. Second window should search for an hotel and make a booking.</p>
<p>As the booking is confirmed, you should see it appearing in the first window.</p>
<h3>Get all the sources on Github</h3>
<p>If you just want to grab the code and run it, <a href="https://github.com/spreadthesource/tapestry5-hotel-booking/tree/tapestry5-realtime">I&#8217;ve put everything on Github</a>. </p>
<h3>Final thoughts</h3>
<p>I believe there is something to do here. What about a new Tapestry 5 contribution, including a service that facilitate publishing to Redis, and a component or a mixin with a JS file providing easy subscription to websockets? What do you think?</p>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/11/bringing-realtime-to-your-java-applications-with-websockets-nodejs-redis-tapestry-5/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Tapestry 5 Hotel Booking</title>
		<link>http://spreadthesource.com/2010/11/tapestry-5-hotel-booking/</link>
		<comments>http://spreadthesource.com/2010/11/tapestry-5-hotel-booking/#comments</comments>
		<pubDate>Tue, 02 Nov 2010 12:07:43 +0000</pubDate>
		<dc:creator>Christophe Cordenier</dc:creator>
				<category><![CDATA[other]]></category>
		<category><![CDATA[tapestry]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=389</guid>
		<description><![CDATA[Along the way with the Tapestry 5.2 release process, we have started to develop a demonstration application inspired from Seam Hotel Booking. The latest version 1.1 has been released, we think that it provides a solid basis for all Tapestry newcomers, it will provide all you need to start developing a *real* application Project configuration [...]]]></description>
			<content:encoded><![CDATA[<p>Along the way with the Tapestry 5.2 release process, we have started to develop a demonstration application inspired from Seam Hotel Booking. The latest version 1.1 has been released, we think that it provides a solid basis for all Tapestry newcomers, it will provide all you need to start developing a *real* application</p>
<ul>
<li>Project configuration</li>
<li>Layout and page design</li>
<li>CSS usage</li>
<li>Model design</li>
<li>Tapestry Hibernate contribution usage</li>
<li>Tapestry JSR-303 contribution usage</li>
<li>Working with form</li>
<li>Working with Ajax components</li>
<li>Working with Tabular datas</li>
<li>Optimize your database access when displaying Grid</li>
<li>Custom security design</li>
<li>Custom conversation design</li>
<li>Custom javascript component</li>
<li>&#8230; and many more topics to provide a complete overview</li>
</ul>
<p>Many thanks to <a href="http://github.com/karesti">Katia A.G.</a> for her great involvement in the project and thanks the community for its feedback. Next to come, other implementations based on third-party contributions and more advanced Tapestry stuff.</p>
<p>I encourage every Tapestry user to checkout the source code, comment, contribute, participate&#8230; at <a href="http://github.com/ccordenier/tapestry5-hotel-booking">github</a>. Note that the application is available <a href="http://tapestry.zones.apache.org:8180/tapestry5-hotel-booking/">online</a> on our official Tapestry website.</p>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/11/tapestry-5-hotel-booking/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Wooki 0.4 is out ! What&#8217;s next ?</title>
		<link>http://spreadthesource.com/2010/09/wooki-0-4-is-out-whats-next/</link>
		<comments>http://spreadthesource.com/2010/09/wooki-0-4-is-out-whats-next/#comments</comments>
		<pubDate>Mon, 20 Sep 2010 06:05:08 +0000</pubDate>
		<dc:creator>Christophe Cordenier</dc:creator>
				<category><![CDATA[tapestry]]></category>
		<category><![CDATA[wooki]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=383</guid>
		<description><![CDATA[Hi ! I am pleased to announce the last release of Wooki : 0.4 ! After almost one year of development, all the features we have initially imagined have been implemented, you can use Wooki to Collaborate with friends on a single book resource Turn Wiki technology into a more interactive tool with direct feedback [...]]]></description>
			<content:encoded><![CDATA[<p>Hi !</p>
<p>I am pleased to announce the last release of Wooki : 0.4 ! After almost one year of development, all the features we have initially imagined have been implemented, you can use Wooki to</p>
<ul>
<li>Collaborate with friends on a single book resource</li>
<li>Turn Wiki technology into a more interactive tool with direct feedback</li>
<li>Follow user&#8217;s activities via RSS</li>
<li>Get a printable version of your books via PDF generation</li>
<li>Edit your content in a clean XHTML code without knowing anything about XHTML</li>
<li>Get access to your action history and revert to a previous revision</li>
</ul>
<p><strong>So what&#8217;s next ?</strong></p>
<p>It&#8217;s time to use it and stabilize it ! As a first experiment, I want to give to Wooki a concrete project to feed, thus i am eager to create a full demonstration application for Tapestry 5. This application will be based on the <a href="http://www.redhat.com/docs/manuals/jboss/jboss-eap-4.2/doc/seam/Seam_Reference_Guide/A_complete_Seam_application_the_Hotel_Booking_example-Introduction.html">Seam Hotel Booking</a> application. Objective of the experiment is to</p>
<ol>
<li>Implement the application via <a href="http://github.com/ccordenier/tapestry5-hotel-booking">Github</a></li>
<li>Compile the Tapestry 5 user&#8217;s experience via <a href="http://wookicentral.com/demo/book/2">Wooki</a></li>
</ol>
<p><strong>Who wants to join ? </strong></p>
<p>This is an opportunity for us to validate the user experience on Wooki, but we need people to work with. So, if you want to join this exciting experiment, please send me your github and wooki&#8217;s ids so i can give you committer and author&#8217;s rights. Tapestry 5 Newbies as Advanced are very welcome ! We need at last 4 people.</p>
<p>Thanks for reading.</p>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/09/wooki-0-4-is-out-whats-next/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Start Spring application context for your Tapestry unit tests</title>
		<link>http://spreadthesource.com/2010/08/start-spring-application-context-for-your-tapestry-unit-tests/</link>
		<comments>http://spreadthesource.com/2010/08/start-spring-application-context-for-your-tapestry-unit-tests/#comments</comments>
		<pubDate>Sun, 01 Aug 2010 17:59:01 +0000</pubDate>
		<dc:creator>Christophe Cordenier</dc:creator>
				<category><![CDATA[tapestry]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=373</guid>
		<description><![CDATA[Tapestry has a powerful tool to unit test your pages and services, but how to deal with it when your pages and services use Spring beans ? Tapestry PageTester can be extended like the TapestryFilter to provide your own ServiceModuleDef classes.  The tapestry-spring contribution already provides the one needed to load a Spring application context. [...]]]></description>
			<content:encoded><![CDATA[<p>Tapestry has a powerful <a href="http://tapestry.apache.org/tapestry5/guide/unit-testing-pages.html">tool to unit test</a> your pages and services, but how to deal with it when your pages and services use Spring beans ?</p>
<p>Tapestry PageTester can be extended like the TapestryFilter to provide your own ServiceModuleDef classes.  The tapestry-spring contribution already provides the one needed to load a Spring application context. Then, loading Spring for your unit tests will be as simple as extended the existing PageTester and provide the Tapestry Spring Module Definition class.</p>
<p>Also, because this module definition uses the servlet application context to get the configuration files location, we will have to mock it. Let&#8217;s use Spring MockServletContext for this.</p>
<ul>
<li>Update your maven dependencies to add spring web mock objects</li>
</ul>
<pre class="brush: xml;">
  &lt;dependency&gt;
    &lt;groupId&gt;org.springframework&lt;/groupId&gt;
    &lt;artifactId&gt;spring-test&lt;/artifactId&gt;
    &lt;version&gt;${spring-version}&lt;/version&gt;
  &lt;/dependency&gt;
</pre>
<ul>
<li>Extend Tapestry PageTester, adapt the code below to your needs if you want to provide mock versions of your spring beans or make it more configurable</li>
</ul>
<pre class="brush: java;">
public class WookiPageTester extends PageTester
{

 private MockServletContext servletContext;

 public WookiPageTester(String appPackage, String appName, String contextPath,
 Class... moduleClasses)
 {
   super(appPackage, appName, contextPath, moduleClasses);
   Registry registry = this.getRegistry();
   // Set Tapestry registry in mock servlet context
   servletContext.setAttribute(TapestryFilter.REGISTRY_CONTEXT_NAME, registry);
 }

 public WookiPageTester(String appPackage, String appName)
 {
   super(appPackage, appName);
 }

 @Override
 protected ModuleDef[] provideExtraModuleDefs()
 {
   // Set spring configuration files location
   servletContext = new MockServletContext();
   servletContext.addInitParameter(&quot;contextConfigLocation&quot;, &quot;classpath*:mock-applicationContext.xml&quot;);
   return new ModuleDef[] { new SpringModuleDef(servletContext) };
 }

}
</pre>
<p>Thanks for reading !</p>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/08/start-spring-application-context-for-your-tapestry-unit-tests/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wooki 0.3 is out !</title>
		<link>http://spreadthesource.com/2010/07/wooki-0-3-is-out/</link>
		<comments>http://spreadthesource.com/2010/07/wooki-0-3-is-out/#comments</comments>
		<pubDate>Fri, 23 Jul 2010 17:12:13 +0000</pubDate>
		<dc:creator>Christophe Cordenier</dc:creator>
				<category><![CDATA[tapestry]]></category>
		<category><![CDATA[wooki]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=351</guid>
		<description><![CDATA[After a few months of hard work to extract re-usable components from Wooki, the version 0.3 is finally out ! Along with Wooki improvements, we have created three major spin-off contributions that put the basis for a strong architecture that will make Wooki evolutive and ready for production soon: tapestry5-spring-tx allows you to benefit from [...]]]></description>
			<content:encoded><![CDATA[<p>After a few months of hard work to extract re-usable components from Wooki, the version 0.3 is finally out !</p>
<p>Along with Wooki improvements, we have created three major spin-off contributions that put the basis for a strong architecture that will make Wooki evolutive and ready for production soon:</p>
<ul>
<li>tapestry5-spring-tx allows you to benefit from Spring Platform Transaction management inside Tapestry</li>
<li>tapestry5-installer provides a way to easily deploy and install tapestry 5 application</li>
<li>tapestry5-db-migration, inspired from rails migrations, allows you to get full control over your database schema through your Tapestry 5 application lifecycle</li>
</ul>
<p>All this work justifies this wooki version. It has been the opportunity to validate and polishing these different contributions in a real context.</p>
<p>Also the global code of Wooki has been reviewed to ease future evolutions and current features maintenance</p>
<ul>
<li>Move to Tapestry 5.2 that make development with Tapestry more and more confortable</li>
<li>Integration of spring-acl to handle authorization on wooki&#8217;s resources</li>
<li>Creation of an abstraction layer to handle DB query parameters like range, created since</li>
<li>Centralize activity lookup for RSS feeds and front display</li>
<li>Centralize application link management and improve the application security layer</li>
</ul>
<p>To conclude, one important news is that wooki has moved to <a href="http://github.com/spreadthesource/wooki">spreadthesource organization</a> on github</p>
<p>We hope you will find inspiration from all these as a user or a Tapestry developer ! <a href="http://wookicentral.com/demo/">Give it a try</a> !</p>
<p>Thanks for reading.</p>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/07/wooki-0-3-is-out/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Vox Wooki 2 : TapesTwitter, contributions and community news</title>
		<link>http://spreadthesource.com/2010/07/vox-wooki-2-tapestwitter-under-the-spotlights/</link>
		<comments>http://spreadthesource.com/2010/07/vox-wooki-2-tapestwitter-under-the-spotlights/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 17:00:15 +0000</pubDate>
		<dc:creator>Robin Komiwes</dc:creator>
				<category><![CDATA[tapestry]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=314</guid>
		<description><![CDATA[Its interesting to write this kind of posts about Tapestry community because it makes you realize that we&#8217;ve got a pretty active community. Vox Wooki 2 will especially focus on TapesTwitter: an open source clone of Twitter powered by Tapestry. TapesTwitter Some weeks ago, Laurent Guerin and Katia Aresti have silently published an application named [...]]]></description>
			<content:encoded><![CDATA[<p>Its interesting to write this kind of posts about Tapestry community because it makes you realize that we&#8217;ve got a pretty active community.</p>
<p>Vox Wooki 2 will especially focus on <a href="http://github.com/lguerin/tapestwitter">TapesTwitter</a>: an open source clone of Twitter powered by Tapestry.</p>
<p><span id="more-314"></span></p>
<h3>TapesTwitter</h3>
<p>Some weeks ago, Laurent Guerin and Katia Aresti have silently published an application named <a title="TapesTwitter" href="http://github.com/lguerin/tapestwitter">TapesTwitter</a> on Github.</p>
<p>We decided to download it and see what this application can do. TapesTwitter is a modest clone of Twitter powered by Tapestry. The stated goal is to provide a demonstration application to show what Tapestry is capable of. And that&#8217;s precisely what we liked about this application. A newcomer will find all necessary elements to get started with Tapestry : components and mixins, overrides of specific Tapestry behaviors like AJAX validators, integration of spring-security, i18n etc.</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-327" style="border: 1px solid black;" title="AJAX Validators" src="http://spreadthesource.com/wp-content/uploads/2010/07/screenshot_08-e1279194476870.jpg" alt="" width="681" height="188" /></p>
<p style="text-align: center;">Custom Ajax validators</p>
<p style="text-align: center;">
<p style="text-align: center;"><img class="aligncenter size-full wp-image-328" style="border: 1px solid black;" title="i18n" src="http://spreadthesource.com/wp-content/uploads/2010/07/screenshot_03-e1279194792125.jpg" alt="" width="339" height="201" /></p>
<p style="text-align: center;">Internationalisation</p>
<p style="text-align: center;">
<p style="text-align: center;"><img class="aligncenter size-full wp-image-331" style="border: 1px solid black;" title="screenshot_07" src="http://spreadthesource.com/wp-content/uploads/2010/07/screenshot_071-e1279195252746.jpg" alt="" width="681" height="201" /></p>
<p style="text-align: center;">One of their exclusives components: letters count system</p>
<p>Congratulations Laurent and Katia for your job, I&#8217;m convinced that it will be useful for a lot of people. I strongly encourage tapestry users to take a look at it.</p>
<h3>Contributions</h3>
<p>Geoff Callender continues to update <a title="Jumpstart" href="http://jumpstart.doublenegative.com.au/jumpstart/">Tapestry Jumpstart</a>. Not less than two releases of Jumpstart have been made since last Vox Wooki. Theses releases focus on validators and there is an interesting AJAX validator implementation. I always recommend people to bookmark Jumpstart when I give Tapestry trainings: this application is the best cookbook for Tapestry I know.</p>
<p>Kalle Korhonen from Tynamo also announced the availability of <a title="Tapestry security 0.2.0" href="http://docs.codehaus.org/display/TYNAMO/2010/07/01/Tapestry-security+0.2.0+released!">tapestry-security 0.2.0</a>. This contribution is an integration of <a title="Apache Shiro" href="http://incubator.apache.org/shiro/">Apache Shiro</a> security framework (previously known as JSecurity), which is, as far as I know, a pretty good tool!</p>
<h3>Other news from the community</h3>
<p>Igor Drobiazko announced that his german written book on Tapestry 5 <a href="http://blog.tapestry5.de/index.php/2010/06/11/manning-publications-translates-my-tapestry-5-book/">will be translated in English</a>. This is really great and I hope that the english edition will be revisited to cover the new Tapestry 5.2 API.</p>
<p>Finally, Tapestry official logo and website have both been redesigned.  I&#8217;m largely implicated on this but it&#8217;s also interesting to notice that these proposals have been discussed on tapestry developer mailing list. The community had the opportunity to be implicated by providing feedback, and I think it&#8217;s a good way of doing things.</p>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/07/vox-wooki-2-tapestwitter-under-the-spotlights/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Christophe Cordenier as an Apache Tapestry 5 committer</title>
		<link>http://spreadthesource.com/2010/07/christophe-as-an-apache-tapestry-5-committer/</link>
		<comments>http://spreadthesource.com/2010/07/christophe-as-an-apache-tapestry-5-committer/#comments</comments>
		<pubDate>Thu, 08 Jul 2010 11:00:41 +0000</pubDate>
		<dc:creator>Robin Komiwes</dc:creator>
				<category><![CDATA[tapestry]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=284</guid>
		<description><![CDATA[Hey, two weeks ago, Christophe Cordenier has been promoted as an Apache Tapestry 5 committer. Congratulations to him. This is definitely a great opportunity for &#8220;spread the source&#8221; to contribute to the Tapestry 5 framework. As far as I know, his first goal is to contribute to the documentation effort started by Ulrich Stärck. By [...]]]></description>
			<content:encoded><![CDATA[<p>Hey, two weeks ago, <a title="Follow on Github" href="http://github.com/users/follow?target=ccordenier">Christophe Cordenier</a> has been promoted as an Apache Tapestry 5 committer. Congratulations to him. This is definitely a great opportunity for &#8220;spread the source&#8221; to contribute to the Tapestry 5 framework.</p>
<p>As far as I know, his first goal is to contribute to the documentation effort started by Ulrich Stärck. By the way, Ulrich has been promoted as an Apache Tapestry 5 PMC member.</p>
<p>As a side news, <a title="wooki" href="http://wookicentral.com">wooki</a> 0.3 is almost finished. This will be a huge release in terms of refactoring and new features. We made some <a href="http://github.com/spreadthesource/tapestry5-installer">terrific</a> <a href="http://github.com/spreadthesource/tapestry5-db-migrations">things</a>.  Stay tuned, the announce will come in next few days.</p>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/07/christophe-as-an-apache-tapestry-5-committer/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Tapestry 5 Logo in Motion</title>
		<link>http://spreadthesource.com/2010/06/tapestry-5-logo-in-motion/</link>
		<comments>http://spreadthesource.com/2010/06/tapestry-5-logo-in-motion/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 17:00:47 +0000</pubDate>
		<dc:creator>Christophe Cordenier</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[tapestry]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=272</guid>
		<description><![CDATA[Thanks to my brother Matthieu co-founder of Kamélégraph, a french design agency specialized in 3D design for architects and thanks to the recent work made by Robin Komiwes on Tapestry 5 Logo We are pleased to suggest to the Tapestry 5 community a fun animation that should be used to start or conclude a Tapestry [...]]]></description>
			<content:encoded><![CDATA[<p>Thanks to my brother Matthieu co-founder of <a title="kamélégraph" href="http://www.kamelegraph.com/">Kamélégraph</a>, a french design agency specialized in 3D design for architects and thanks to the recent work made by Robin Komiwes on Tapestry 5 Logo</p>
<p>We are pleased to suggest to the Tapestry 5 community a fun animation that should be used to start or conclude a Tapestry 5 presentation</p>
<p>Here are the first two drafts of the current work, comments and suggestions are welcome !</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/0XY8VQG73Ms&amp;hl=en_US&amp;fs=1&amp;" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube.com/v/0XY8VQG73Ms&amp;hl=en_US&amp;fs=1&amp;" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/MyJlxWI48UM&amp;hl=en_US&amp;fs=1&amp;" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube.com/v/MyJlxWI48UM&amp;hl=en_US&amp;fs=1&amp;" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/06/tapestry-5-logo-in-motion/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Vox Wooki : A Tapestry Community News Feed</title>
		<link>http://spreadthesource.com/2010/06/vox-wooki-a-tapestry-community-news-feed/</link>
		<comments>http://spreadthesource.com/2010/06/vox-wooki-a-tapestry-community-news-feed/#comments</comments>
		<pubDate>Fri, 11 Jun 2010 06:42:28 +0000</pubDate>
		<dc:creator>Christophe Cordenier</dc:creator>
				<category><![CDATA[tapestry]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=239</guid>
		<description><![CDATA[Tapestry community has been quite active recently with many announcements. Here is a focus on what&#8217;s new since the last three months: Contributions Tynamo guys are very actives, they provided new releases for two of their contributions : tapestry-resteasy 0.2.0 offers a convenient way to use JBoss Resteasy inside a Tapestry application tapestry-model 0.0.2 for [...]]]></description>
			<content:encoded><![CDATA[<p>Tapestry community has been quite active recently with many announcements. Here is a focus on what&#8217;s new since the last three months:</p>
<h3>Contributions</h3>
<p>Tynamo guys are very actives, they provided new releases for two of their contributions :</p>
<ul>
<li><a href="http://tynamo.org/tapestry-resteasy+guide">tapestry-resteasy 0.2.0</a> offers a convenient way to use JBoss Resteasy inside a Tapestry application</li>
<li><a href="http://tynamo.org/tapestry-model+guide">tapestry-model 0.0.2</a> for CRUD application development</li>
</ul>
<p>&#8230; and a brand new module to send alerts via email &#8216;if something happens to your parent process&#8217;</p>
<ul>
<li><a href="http://tynamo.org/tapestry-watchdog+guide">tapestry-watchdog-0.0.1</a></li>
</ul>
<p>Two testing frameworks announced in new version :</p>
<ul>
<li>Spock Team has released a version 0.4 of <a href="http://spockframework.org">Spock Java/Groovy testing framework</a> with support for Tapestry Injection annotations</li>
<li><a href="http://tapestry.formos.com/projects/tapestry-testify/">Tapestry  Testify </a>is now available in version 1.0.2 and the related Tapestry  XPath project is now available in v1.0.1</li>
</ul>
<p>The complete and so useful <a href="http://jumpstart.doublenegative.com.au/home.html">Tapestry JumpStart</a> is now available in version 4.9</p>
<p>From our side, GOT5 a.k.a. &#8220;Gang Of Tapestry 5&#8243; , a new group of Tapestry developers where we (Christophe and Robin) belong too. In fact this group is the hat we are going to wear when we will publish Open Source content from work made for our employer. Anyway we released under GOT5 hat something really awesome:</p>
<ul>
<li><a href="http://github.com/got5/tapestry5-jquery">tapestry5-jquery</a> allows to get completely rid of prototype API and use jQuery instead, this project has started to be used by the community and we already have some feedback on it to improve and complete it</li>
</ul>
<p>Also, as you may have noticed, wooki has been completely refactored during the last two months. One main objective of this was to extract most of the reusable pieces of wooki into third-party contributions under spreadthesource account. Here is the list of libraries that has been extracted from wooki&#8217;s experience.</p>
<p>This two contributions are used for a while now on wooki and have been confirmed to be really useful with the experience.</p>
<ul>
<li><a href="http://github.com/spreadthesource/tapestry5-rome">tapestry5-rome</a></li>
<li><a href="http://github.com/spreadthesource/tapestry5-googleanalytics">tapestry5-googleanalytics</a></li>
</ul>
<p>One of the most important but still in progress is a tool that will allow to easily maintain your application database schema accross version of your application. It will provide a full API built on top of Hibernate tools to create/update your database schema, insert/delete datas&#8230;</p>
<ul>
<li><a href="http://github.com/spreadthesource/tapestry5-db-migrations">tapestry5-db-migration</a></li>
</ul>
<p>Finally we have a two-phase tapestry launcher and a contribution that allows tapestry-hibernate to work with Spring Hibernate Transaction Manager.</p>
<ul>
<li><a href="http://github.com/spreadthesource/tapestry5-installer">tapestry5-installer</a></li>
<li><a href="http://github.com/spreadthesource/tapestry5-spring-tx">tapestry5-spring-tx</a></li>
</ul>
<p>We expect to provide stable releases for all of these with the next wooki&#8217;s version.</p>
<p>Thanks for reading.</p>
<div style="overflow: hidden; width: 1px; height: 1px;"><a class="exlink mklink" rel="nofollow" href="http://tynamo.org/tapestry-watchdog+guide">http://tynamo.org/tapestry-watchdog+guide</a></div>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/06/vox-wooki-a-tapestry-community-news-feed/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Tapestry IOC : Implement Strategy Pattern with Enums</title>
		<link>http://spreadthesource.com/2010/05/tapestry-ioc-implement-strategy-pattern-with-enums/</link>
		<comments>http://spreadthesource.com/2010/05/tapestry-ioc-implement-strategy-pattern-with-enums/#comments</comments>
		<pubDate>Fri, 07 May 2010 11:58:15 +0000</pubDate>
		<dc:creator>Christophe Cordenier</dc:creator>
				<category><![CDATA[tapestry]]></category>

		<guid isPermaLink="false">http://spreadthesource.com/?p=225</guid>
		<description><![CDATA[Tapestry already have a StrategyBuilder that is really useful when you want to write a generic service interface and let Tapestry IOC decides which implementation to call in function of the type of the arguments. But how to do it when your strategy does not depend on a Java type but a Enum type ? [...]]]></description>
			<content:encoded><![CDATA[<p>Tapestry already have a <a href="http://tapestry.apache.org/tapestry5.1/tapestry-ioc/strategy.html">StrategyBuilder</a> that is really useful when you want to write a generic service interface and let Tapestry IOC decides which implementation to call in function of the type of the arguments. But how to do it when your strategy does not depend on a Java type but a Enum type ?</p>
<p>We&#8217;ll see in this article a concrete use case of this type of strategy and see how easy it is to implement with Tapestry.</p>
<h3>Use Case</h3>
<p>We have a component that displays the activity logs on our Web site. This component is in charge of getting the list of activities to display. These latter will depend on the user context, that means not every user will see the same activities type and list.</p>
<h3>ActivitySource</h3>
<p>To avoid having boilerplate code in the component that will identify which finder method to call depending on the context. We define a simple interface that will be called by the component to obtain the list of strategy to display.</p>
<pre class="brush: java;">
public interface ActivitySource {
 List&lt;Activity&gt; listActivities(Long... context);
}
</pre>
<p>Note the &#8216;context&#8217; parameters that consists in a list of ids that can be used by the implementation class to build its db query. Now we have the interface let&#8217;s create two implementations i.e. PublicActivitySource and AdminActivitySource that will list the activities in function of the logged user is a guest or a user with admin rights.</p>
<h3>ActivitySourceType</h3>
<p>This is the key concept of this article, now we have defined the interface and created two implementations classes, we will list all of these in a single Enum type called ActivitySourceType. Let&#8217;s see how it looks like :</p>
<pre class="brush: java;">
public enum ActivitySourceType {

 ADMIN_AS(AdminActivitySource.class),

 PUBLIC_AS(PublicActivitySource.class);

 private Class&lt;? extends ActivitySource&gt; sourceClass;

 private ActivitySourceType(Class&lt;? extends ActivitySource&gt; source) {
     this.sourceClass = source;
 }

 @SuppressWarnings(&quot;unchecked&quot;)
 public Class&lt;ActivitySource&gt; getSourceClass() {
     return (Class&lt;ActivitySource&gt;) sourceClass;
 }

}
</pre>
<p>We create on Enum type per activity source. Doing this we have a centralized lists of available sources, now let&#8217;s see how to bind all these implementation classes so we can use them in our application.</p>
<h3>Register your services</h3>
<p>Tapestry provides a convenient way to automatically bind service implementation via the ServiceBinder class. Each implementation must have a different id so we can distinguish them at runtime. Here is the code used to iterate through the list of existing implementations. This will be localized in your AppModule class.</p>
<pre class="brush: java;">
public static void bind(ServiceBinder binder) {
    for(ActivitySourceType type : ActivitySourceType.values()){
        binder.bind(ActivitySource.class, type.getSourceClass()).withId(type.toString());
    }
}
</pre>
<p>Now this is done, all the existing services has been registered and you can easily and dynamically retrieve a ActivitySource service reference in your Tapestry pages.</p>
<h3>Obtain the  service instance</h3>
<p>Use the Tapestry registry to dynamically access to the corresponding service in function of the context. i.e. You can see below how to get it work in a component using a dynamic parameter value of ActivitySourceType type.</p>
<pre class="brush: java;">
 @Parameter
 private ActivitySourceType type;

 @Inject
 private Context context;

 private ActivitySource source;

 ActivitySourceType defaultType() {
     return ActivitySourceType.PUBLIC_AS;
 }

 @SetupRender
 public void defineSource() {
     Registry reg = (Registry) context.getAttribute(TapestryFilter.REGISTRY_CONTEXT_NAME);
     this.source = reg.getService(type.toString(), ActivitySource.class);

     List&lt;Activity&gt; activities = source.listActivities();
     for (Activity a : activities) {
       System.out.println(a.getLog());
     }
 }
</pre>
<p>As you can see this is as simple as retrieving the service instance from the registry giving its interface and its id, and then call its &#8216;listActivities&#8217; method. Doing this, we can say that we have implemented a type-safe Strategy pattern that will avoid to use ugly switch/case statements.</p>
]]></content:encoded>
			<wfw:commentRss>http://spreadthesource.com/2010/05/tapestry-ioc-implement-strategy-pattern-with-enums/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

