<?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>Kevin Webber</title>
	<atom:link href="http://kevinontheweb.com/feed" rel="self" type="application/rss+xml" />
	<link>http://kevinontheweb.com</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Sun, 05 Sep 2010 00:22:57 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>The future of software</title>
		<link>http://kevinontheweb.com/posts/357/the-future-of-software</link>
		<comments>http://kevinontheweb.com/posts/357/the-future-of-software#comments</comments>
		<pubDate>Sun, 05 Sep 2010 00:21:25 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[Software development]]></category>
		<category><![CDATA[architecture]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/?p=357</guid>
		<description><![CDATA[
A desire path is what a person wants rather than what an architect builds. The term desire path originated from landscape architecture, but it&#8217;s an increasingly important concept for software architects to grasp. If you understand desire paths, you understand the future of software development.
Large corporations are often slow to respond to change. In no space is [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://kevinontheweb.com/wp-content/uploads/2010/09/desire_path.jpg"><img class="size-full wp-image-358  alignnone" title="desire_path" src="http://kevinontheweb.com/wp-content/uploads/2010/09/desire_path.jpg" alt="" width="500" height="363" /></a></p>
<p>A <a href="http://findsubstance.com/2010/07/06/desire-paths/">desire path</a> is what a person wants rather than what an architect builds. The term <em>desire path </em>originated from landscape architecture, but it&#8217;s an increasingly important concept for software architects to grasp. If you understand desire paths, you understand the future of software development.</p>
<p>Large corporations are often slow to respond to change. In no space is this more evident than technology. If you&#8217;re a developer and have used both ClearCase <strong>and</strong> Git(Hub) for version control, you know exactly what I&#8217;m talking about. The big business version of source control is <strong><em>painful </em></strong>to use compared to the next generation of light and nimble apps crafted by small or open source development shops. Git and GitHub are a true pleasure to work with, while ClearCase is known to cause nightmares, paranoia, insomnia, dry mouth, anxiety attacks, and lethargy. (They should put a warning label on the box, just sayin&#8217;.)</p>
<p><span id="more-357"></span></p>
<p>This is a fairly accurate portrait of the future of software and software development; an increasingly polarized space where the next generation of software developers duke it out with their predecessors. A space where resting on your laurels may mean going out of business or watching your professional software development career come to an abrupt end. A space where developing crappy applications will get an organization or developer laughed out of the industry. A space where kids who grew up with a laptop in their baby crib become consumers (and even the heads of corporations) and have a completely different expectation of what software should do.</p>
<p>Yeah, that&#8217;s a bit general. Let&#8217;s get specific. Mobile computing will continue to have a profound impact on how users interact with apps. More users are turning to native applications: think Twitter, Facebook, etc. How many people use Twitter&#8217;s web UI? Hardly any. Most people use a native application instead. Desktop and laptop computers are slowly being outnumbered by PDAs, cell phones, tablets, and a variety of other gadgets, especially outside of North America where cost is a much bigger issue. Web-based user interfaces are becoming less important while APIs are becoming more important. Don&#8217;t get me wrong, web-based interfaces will be around for quite a long time, but users will depend on them less. <em>If software were fashion, APIs would be the new black.</em></p>
<p><strong>Integration</strong> and <strong>continuous improvement</strong> are becoming the two most important aspects of software development today, and will only increase in importance over the next decade. Simple, light, extensible, and integrated; big bang development may continue, but smart companies realize that there is no such thing as a finished application. Applications are no more finished than the people who build them! Think evolution rather than revolution. &#8220;Application oriented&#8221; development will replace &#8220;object oriented&#8221; development in terms of developer mindset.</p>
<p>The gap between the <em>haves</em> and the <em>have nots</em> will grow significantly. Organizations that fail to adapt will fall quickly behind their more adaptable competition and bleed market share.</p>
<p><span style="text-decoration: underline;">Flexibility is key.</span> Your architecture must be flexible enough to adapt to the changing whims of the marketplace in a moments notice. Flexibility has always been important, but five years from now, it could mean the difference between your organization being #1 or being out of business.</p>
<p>Don&#8217;t dictate to your users, listen to them, and let them guide your design, not the other way around. Anyone who keeps this in the back of their mind is already ahead of the curve and ready for the changing software landscape.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/357/the-future-of-software/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The greatest line of code ever</title>
		<link>http://kevinontheweb.com/posts/353/the-greatest-line-of-code-ever</link>
		<comments>http://kevinontheweb.com/posts/353/the-greatest-line-of-code-ever#comments</comments>
		<pubDate>Sun, 22 Aug 2010 05:42:56 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[Horror]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/?p=353</guid>
		<description><![CDATA[
if &#40;statusIsNotValid.compareTo&#40; Boolean.FALSE &#41; != 0&#41; skipValidation = false;

I don&#8217;t know what&#8217;s more shocking, that someone who calls themselves a professional programmer wrote that piece of&#8230; whatever&#8230; or that it wasn&#8217;t clubbed to death like a baby seal during a code review. If you ever find yourself working in a team that doesn&#8217;t see the [...]]]></description>
			<content:encoded><![CDATA[
<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>statusIsNotValid.<span style="color: #006633;">compareTo</span><span style="color: #009900;">&#40;</span> <span style="color: #003399;">Boolean</span>.<span style="color: #000066; font-weight: bold;">FALSE</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> skipValidation <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span></pre></div></div>

<p>I don&#8217;t know what&#8217;s more shocking, that someone who calls themselves a <em>professional </em>programmer wrote that piece of&#8230; whatever&#8230; or that it wasn&#8217;t clubbed to death like a baby seal during a code review. If you ever find yourself working in a team that doesn&#8217;t see the importance of code reviews, remind them that they could easily wind up with a few million lines of&#8230; <strong>that</strong>.</p>
<p>(Taken from <a href="http://thedailywtf.com/Articles/Boolean-Illogic.aspx" target="_blank">The Daily WTF</a>.)</p>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/353/the-greatest-line-of-code-ever/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Integrating Uploadify with Java using Apache Wicket</title>
		<link>http://kevinontheweb.com/posts/291/integrating-uploadify-with-java-using-apache-wicket</link>
		<comments>http://kevinontheweb.com/posts/291/integrating-uploadify-with-java-using-apache-wicket#comments</comments>
		<pubDate>Fri, 30 Apr 2010 06:12:32 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[Flash]]></category>
		<category><![CDATA[Software development]]></category>
		<category><![CDATA[Wicket]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/?p=291</guid>
		<description><![CDATA[One of the most requested features on any site that accepts file submissions is the ability to handle multiple uploads elegantly. The current HTML standard only permits one file upload at a time, which makes transferring a large number of files quite tedious.
This tutorial will show how to painlessly integrate Uploadify and Java using Apache [...]]]></description>
			<content:encoded><![CDATA[<p>One of the most requested features on any site that accepts file submissions is the ability to handle multiple uploads elegantly. The current HTML standard only permits one file upload at a time, which makes transferring a large number of files quite tedious.</p>
<p>This tutorial will show how to painlessly integrate Uploadify and Java using Apache Wicket. You should have at least beginner-level knowledge of Wicket before moving forward, but feel free to dive right in even if you&#8217;ve never used Wicket before. (If you haven&#8217;t used Wicket before, I can&#8217;t suggest it strongly enough for developing stateful Java-based web applications.)</p>
<p><span id="more-291"></span></p>
<p>A number of excellent Flash-based multiple file upload plugins are available, including the excellent <a href="http://www.uploadify.com/" target="_blank">Uploadify</a>. Uploadify is essentially a jQuery wrapper for <a href="http://www.swfupload.org/">SWFUpload</a>. I already use jQuery quite extensively so I chose Uploadify as my multiple upload plugin, but if you use a different JavaScript framework or simply prefer plain old JavaScript, SWFUpload might be a better choice.</p>
<p>The only catch is that most of these plugins are geared towards PHP developers/apps and not all that intuitive to integrate with Java-based solutions.</p>
<p><b><em>A few more things to consider:</em></b> Before jumping in with both feet, the use of Flash is a stopgap measure until HTML5 is more widely supported. HTML5 supports the attribute &#8220;multiple&#8221; in the input tag, offering true native multiple file upload support. Also, with Apple fully <a href="http://news.cnet.com/8301-30685_3-20003739-264.html" target="_blank">throwing its weight behind HTML5 and actively attacking Flash</a>, it&#8217;s only a matter of time before Flash-based solutions go the way of the bond market in Greece. </p>
<p>While HTML5 supports the attribute &#8220;multiple&#8221; in the input tag, browser support for HTML5 is far from ubiquitous. To make matters worse, <a href="http://www.webmonkey.com/2008/09/html_5_won_t_be_ready_until_2022dot_yes__2022dot/" target="_blank">the HTML5 standard won&#8217;t officially be signed off on until 2022</a>. Yes, 12 more years, and yes, it&#8217;s completely insane, but you know how design-by-committee works.</p>
<h2>Getting Started</h2>
<p>Preamble complete, let&#8217;s get down to business. Our strategy will be to create a re-usable Apache Wicket &#8220;multiple file upload&#8221; component. In our case, because we will be re-using both Java code and HTML, we&#8217;ll create a Wicket panel to do this.</p>
<h3>Step 1 &#8211; Dependencies</h3>
<p>We don&#8217;t need everything included in the Uploadify download. We&#8217;ll create new packages for the components, CSS, and scripts, and cherry-pick the Uploadify artifacts to copy to the new project. Depending on how you have Wicket configured, your scripts, CSS, and HTML files may be separate from Java source files. The default in Wicket is to place them together in the same package, so we&#8217;ll be using that paradigm for this tutorial. When you&#8217;re done with the tutorial, your package hierarchy will look something like below.</p>
<p><a href="http://kevinontheweb.com/wp-content/uploads/2010/04/Picture-61.png"><img class="alignnone size-full wp-image-296" title="Picture 6" src="http://kevinontheweb.com/wp-content/uploads/2010/04/Picture-61.png" alt="" width="370" height="290" /></a></p>
<h3>Step 2 &#8211; Re-usable HTML</h3>
<p>The next step is to create the HTML for our Panel. Create a new file called <strong>UploadifyPanel.html </strong>with the following source:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;wicket:panel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;fileQueue&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Click browse to select files for uploading.<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;em<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>To select more than one file, hold down control or shift.<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/em<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;input</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;file&quot;</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;uploadify&quot;</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;uploadify&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/wicket:panel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Most of what you see above is standard HTML and CSS. The only item of note is the input tag, which will be replaced with the Flash component by the Uploadify script. If the user does not have Flash installed, the above input tag will be used as-is without replacement, so make sure the tag is valid for graceful downgrading.</p>
<p>If you want to enhance the tutorial, you should use Wicket&#8217;s excellent localization support to add fully configurable dynamic text to the re-usable component.</p>
<h3>Step 3 &#8211; Java components for re-usable Panel</h3>
<h4>UploadifyPanel.java</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.rocketpages.wicket.component.uploadify</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.CSSPackageResource</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.JavascriptPackageResource</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.panel.Panel</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.util.template.TextTemplateHeaderContributor</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> UploadifyPanel <span style="color: #000000; font-weight: bold;">extends</span> <span style="color: #003399;">Panel</span> <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">long</span> serialVersionUID <span style="color: #339933;">=</span> 1L<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> UploadifyPanel<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> id, UploadifyPanelBehaviour behaviour<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	add<span style="color: #009900;">&#40;</span>JavascriptPackageResource.<span style="color: #006633;">getHeaderContribution</span><span style="color: #009900;">&#40;</span>UploadifyPanel.<span style="color: #000000; font-weight: bold;">class</span>, 
		<span style="color: #0000ff;">&quot;scripts/swfobject.js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
&nbsp;
	add<span style="color: #009900;">&#40;</span>JavascriptPackageResource.<span style="color: #006633;">getHeaderContribution</span><span style="color: #009900;">&#40;</span>UploadifyPanel.<span style="color: #000000; font-weight: bold;">class</span>, 
		<span style="color: #0000ff;">&quot;scripts/jquery.uploadify.v2.1.0.js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">/* TextTemplateHeaderContributor performs text substitution of values located
	 in multiupload.js with the values obtained from the behaviour, and
	 inserts the processed .js in the header. */</span>
	add<span style="color: #009900;">&#40;</span>TextTemplateHeaderContributor.<span style="color: #006633;">forJavaScript</span><span style="color: #009900;">&#40;</span>
		UploadifyPanel.<span style="color: #000000; font-weight: bold;">class</span>, <span style="color: #0000ff;">&quot;multiupload.js&quot;</span>, behaviour.<span style="color: #006633;">getVariables</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	add<span style="color: #009900;">&#40;</span>CSSPackageResource.<span style="color: #006633;">getHeaderContribution</span><span style="color: #009900;">&#40;</span>UploadifyPanel.<span style="color: #000000; font-weight: bold;">class</span>, 
		<span style="color: #0000ff;">&quot;css/uploadify.css&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>   
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>For those of you familiar with Wicket, most of this will look straightforward enough. We&#8217;re encapsulating all of our configuration variables in a behaviour, which keeps our code clean and generic. Of special interest is the call to <em>TextTemplateHeaderContributor.forJavaScript()</em>. This is a handy little method that allows you to pass in a Map of variables (key/value) and a reference to a JavaScript file. This results in token substitution in the JavaScript file based on the values in the Map. It&#8217;s much more simple than performing manual string concatenation to achieve the same result.</p>
<h4>UploadifyPanelBehaviour.java</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.rocketpages.wicket.component.uploadify</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.Serializable</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.HashMap</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.Map</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.RequestCycle</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.resources.CompressedResourceReference</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.model.AbstractReadOnlyModel</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.model.IModel</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> UploadifyPanelBehaviour <span style="color: #000000; font-weight: bold;">implements</span> <span style="color: #003399;">Serializable</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> fileExt <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> fileDesc <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> sizeLimit <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">//manditory</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span> formTokenId<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span> formSessionId<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> Class<span style="color: #339933;">&lt;?</span> <span style="color: #000000; font-weight: bold;">extends</span> UploadifyFileProcessPage<span style="color: #339933;">&gt;</span> fileProcessPageClass<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> UploadifyPanelBehaviour<span style="color: #009900;">&#40;</span>Class<span style="color: #339933;">&lt;?</span> <span style="color: #000000; font-weight: bold;">extends</span> UploadifyFileProcessPage<span style="color: #339933;">&gt;</span> fileProcessPageClass, <span style="color: #003399;">String</span> tokenId, <span style="color: #003399;">String</span> sessionId<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">fileProcessPageClass</span> <span style="color: #339933;">=</span> fileProcessPageClass<span style="color: #339933;">;</span>
	<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">formSessionId</span> <span style="color: #339933;">=</span> sessionId<span style="color: #339933;">;</span>
	<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">formTokenId</span> <span style="color: #339933;">=</span> tokenId<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #008000; font-style: italic; font-weight: bold;">/**
     * Sets the valid file extensions for the uploader.
     * 
     * Do not include leading or trailing quotes, only semi-colon
     * separated wildcards. 
     * 
     * Example usage:
     * *.doc;*.docx;*.pdf;*.jpg;*.png;*.zip
     * 
     * @param validExts
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setFileExt<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> validExts<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">fileExt</span> <span style="color: #339933;">=</span> validExts<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #008000; font-style: italic; font-weight: bold;">/**
     * Sets the message to be displayed when selecting files.
     * 
     * Example message:
     * Select files of type .doc, .pdf, .jpg, .png, or .zip
     * 
     * @param fileDesc
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setFileDesc<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> fileDesc<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">fileDesc</span> <span style="color: #339933;">=</span> fileDesc<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #008000; font-style: italic; font-weight: bold;">/**
     * Sets the size limit, in bytes.
     * 
     * Example: 3072000
     * 
     * @param sizeLimit
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setSizeLimit<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> sizeLimit<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">sizeLimit</span> <span style="color: #339933;">=</span> sizeLimit<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #008000; font-style: italic; font-weight: bold;">/**
     * Builds a variables model in order to perform text substitution
     * on values located in JavaScript (multiupload.js)
     * 
     * The key values in the Map must match the tokens in the .js file. 
     * 
     * @return
     */</span>
    <span style="color: #000000; font-weight: bold;">protected</span> IModel getVariables<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
	IModel variablesModel <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> AbstractReadOnlyModel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Map</span> getObject<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
		Map<span style="color: #339933;">&lt;</span>String, CharSequence<span style="color: #339933;">&gt;</span> variables <span style="color: #339933;">=</span> 
		    <span style="color: #000000; font-weight: bold;">new</span> HashMap<span style="color: #339933;">&lt;</span>String, CharSequence<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">//Mandatory configuration</span>
		variables.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;uploader&quot;</span>, RequestCycle.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">urlFor</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> CompressedResourceReference<span style="color: #009900;">&#40;</span>UploadifyPanel.<span style="color: #000000; font-weight: bold;">class</span>, <span style="color: #0000ff;">&quot;scripts/uploadify.swf&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		variables.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;cancelImg&quot;</span>, RequestCycle.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">urlFor</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> CompressedResourceReference<span style="color: #009900;">&#40;</span>UploadifyPanel.<span style="color: #000000; font-weight: bold;">class</span>, <span style="color: #0000ff;">&quot;cancel.png&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		variables.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;script&quot;</span>, <span style="color: #0000ff;">&quot;;jsessionid=&quot;</span> <span style="color: #339933;">+</span> formSessionId <span style="color: #339933;">+</span> RequestCycle.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">urlFor</span><span style="color: #009900;">&#40;</span>fileProcessPageClass, <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		variables.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;tokenId&quot;</span>, formTokenId<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">//Optional configuration</span>
		variables.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;fileExt&quot;</span>, fileExt<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		variables.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;fileDesc&quot;</span>, fileDesc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		variables.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sizeLimit&quot;</span>, sizeLimit<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">return</span> variables<span style="color: #339933;">;</span>
	    <span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">return</span> variablesModel<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>The behaviour captures configuration options, which correspond to the available options within Uploadify. You can add more configuration options (or remove some) depending on your specific requirements.</p>
<p>Another quirk to pay attention to is the token and session id values. This is a kludge we&#8217;ve added to avoid the messy problem of Flash <i>losing a reference to the HttpSession</i>. Because the end result of this script will be a call to a stateless page to process our uploads, we&#8217;ll need some way to retrieve the user&#8217;s session. Because of this, we need to include the session ID as a value in the JavaScript file and pass this as a parameter to our stateless file processing page.</p>
<p>Finally, make special note of the class we&#8217;re passing to our behaviour object. We do this because Wicket needs to &#8220;mount&#8221; our stateless file processing page so it can be accessed by the plugin. Wicket instantiates the page &#8220;just in time&#8221;, not before, otherwise it would hang around in memory doing nothing (kinda like a TTC collector). Note the call to RequestCycle.get().urlFor().</p>
<h4>UploadFileProcessPage.java</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.rocketpages.wicket.component.uploadify</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.Map</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.http.HttpServletRequest</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.PageParameters</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.RequestCycle</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.Session</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.WebPage</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.protocol.http.WebRequest</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.protocol.http.servlet.MultipartServletWebRequest</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.util.lang.Bytes</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.util.upload.FileItem</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.UserSession</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.data.pojo.user.User</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.services.impl.UserServiceImpl</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.wicket.component.security.FormToken</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">abstract</span> <span style="color: #000000; font-weight: bold;">class</span> UploadifyFileProcessPage <span style="color: #000000; font-weight: bold;">extends</span> WebPage <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">protected</span> User user<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> UploadifyFileProcessPage<span style="color: #009900;">&#40;</span>PageParameters params<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	HttpServletRequest r <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>WebRequest<span style="color: #009900;">&#41;</span> RequestCycle.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getHttpServletRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000000; font-weight: bold;">try</span>
	<span style="color: #009900;">&#123;</span>
	    MultipartServletWebRequest r2 <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MultipartServletWebRequest<span style="color: #009900;">&#40;</span>r, Bytes.<span style="color: #006633;">MAX</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	    <span style="color: #003399;">Map</span> paramMap <span style="color: #339933;">=</span> r2.<span style="color: #006633;">getParameterMap</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	    <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> tokenIdParms <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> paramMap.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;tokenId&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	    <span style="color: #003399;">String</span> tokenId <span style="color: #339933;">=</span> tokenIdParms<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
	    UserSession session <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>UserSession<span style="color: #009900;">&#41;</span> Session.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	    FormToken token <span style="color: #339933;">=</span> session.<span style="color: #006633;">getFormToken</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>token.<span style="color: #006633;">isValid</span><span style="color: #009900;">&#40;</span>tokenId, r.<span style="color: #006633;">getRemoteAddr</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
	    <span style="color: #009900;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">long</span> userId <span style="color: #339933;">=</span> session.<span style="color: #006633;">getUser</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		user <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> UserServiceImpl<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getUser</span><span style="color: #009900;">&#40;</span>userId<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>FileItem fi <span style="color: #339933;">:</span> r2.<span style="color: #006633;">getFiles</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">values</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
		    processFileItem<span style="color: #009900;">&#40;</span>fi<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		    fi.<span style="color: #006633;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	    <span style="color: #009900;">&#125;</span>
	    <span style="color: #000000; font-weight: bold;">else</span>
	    <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Exception</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Invalid token!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	    <span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
	    e.<span style="color: #006633;">printStackTrace</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">abstract</span> <span style="color: #000066; font-weight: bold;">void</span> processFileItem<span style="color: #009900;">&#40;</span>FileItem fileItem<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>In order to bridge our plugin with Java, we&#8217;re creating a stateless page by extending WebPage. This base code is fairly straightforward, pulling out the file data from the request, and passing it to the yet-to-be-defined abstract method <i>processFileItem()</i>. The only other thing to note is the <i>token</i> logic. This is simply an example/placeholder to draw your attention to security when dealing with <b>jsessionid</b> directly. This leaves a small window open for hackers to perform a session hijacking, so in our scenario, we associate a jsessionid with an IP address and an additional token value.</p>
<h4>multiupload.js</h4>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> 
	$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#uploadify'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">uploadify</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> 
		<span style="color: #3366CC;">'uploader'</span><span style="color: #339933;">:</span>  <span style="color: #3366CC;">'${uploader}'</span><span style="color: #339933;">,</span> 
		<span style="color: #3366CC;">'script'</span><span style="color: #339933;">:</span>	<span style="color: #3366CC;">'${script}'</span><span style="color: #339933;">,</span>
		<span style="color: #3366CC;">'scriptData'</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">'tokenId'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'${tokenId}'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> 
		<span style="color: #3366CC;">'folder'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'/var/photos/stuffahoy'</span><span style="color: #339933;">,</span> 
		<span style="color: #3366CC;">'cancelImg'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'${cancelImg}'</span><span style="color: #339933;">,</span>
		<span style="color: #3366CC;">'fileExt'</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">'${fileExt}'</span><span style="color: #339933;">,</span>
		<span style="color: #3366CC;">'fileDesc'</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">'${fileDesc}'</span><span style="color: #339933;">,</span>
		<span style="color: #3366CC;">'sizeLimit'</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">'${sizeLimit}'</span><span style="color: #339933;">,</span>
		<span style="color: #3366CC;">'auto'</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span>
		<span style="color: #3366CC;">'multi'</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span>
		onAllComplete<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #339933;">,</span> queueID<span style="color: #339933;">,</span> fileObj<span style="color: #339933;">,</span> response<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                    uploadCompleted<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
                <span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>If you&#8217;re familiar with JavaScript, you&#8217;ll see we&#8217;re essentially passing an object to the <i>uploadify()</i> method. The key values of the object correspond to the Uploadify options. The token values on the right correlate to our behaviour class and the key values we defined. Text substitution is done on these when we include the JavaScript file via the call to <i>TextTemplateHeaderContributor</i>.</p>
<h3>Step 4 &#8211; Business Logic</h3>
<h4>AddPhotosProcessingPage.java</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.stuffahoy.wicket.page.addstuff</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.PageParameters</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.form.upload.FileUpload</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.util.upload.FileItem</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.rocketpages.wicket.component.uploadify.UploadifyFileProcessPage</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.data.pojo.thing.Photo</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.services.PhotoService</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.services.impl.PhotoServiceImpl</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> AddPhotosProcessingPage <span style="color: #000000; font-weight: bold;">extends</span> UploadifyFileProcessPage <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> AddPhotosProcessingPage<span style="color: #009900;">&#40;</span>PageParameters params<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>params<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> processFileItem<span style="color: #009900;">&#40;</span>FileItem fileItem<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">//Wrap the Apache Commons FileItem type in a Wicket FileUpload type</span>
	FileUpload upload <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> FileUpload<span style="color: #009900;">&#40;</span>fileItem<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">//Get a service reference, store the photo, and create a new Photo record</span>
	PhotoService photoService <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PhotoServiceImpl<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	Photo photo <span style="color: #339933;">=</span> photoService.<span style="color: #006633;">saveUploadedPhoto</span><span style="color: #009900;">&#40;</span>upload, <span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	photo.<span style="color: #006633;">setUser</span><span style="color: #009900;">&#40;</span>user<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	photoService.<span style="color: #006633;">savePhoto</span><span style="color: #009900;">&#40;</span>photo<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>This is our actual stateless page that extends our more generic file processor. The code is an example of business logic you may execute on each file. In this case, we&#8217;re processing image files, so we pass the file reference to a service which in turn writes the file to disk (or Amazon S3, etc) and persists the information in our database.</p>
<h4>AddPhotosPage.java</h4>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.stuffahoy.wicket.page.addstuff</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.http.HttpServletRequest</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.PageParameters</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.RequestCycle</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.ResourceReference</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.Session</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.ajax.AbstractDefaultAjaxBehavior</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.ajax.AjaxRequestTarget</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.behavior.IBehavior</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.CSSPackageResource</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.IHeaderResponse</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.basic.Label</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.image.Image</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.protocol.http.WebRequest</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.rocketpages.wicket.component.uploadify.UploadifyPanel</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.rocketpages.wicket.component.uploadify.UploadifyPanelBehaviour</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.UserSession</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.pages.loggedin.UserRoleSuperPage</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.stuffahoy.wicket.component.photoselect.UnprocessedPhotosPanel</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> AddPhotosPage <span style="color: #000000; font-weight: bold;">extends</span> UserRoleSuperPage <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">long</span> serialVersionUID <span style="color: #339933;">=</span> 1L<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Label</span> noPhotosLabel<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> AddPhotosPage<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> PageParameters parameters<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">this</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> AddPhotosPage<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	add<span style="color: #009900;">&#40;</span>CSSPackageResource.<span style="color: #006633;">getHeaderContribution</span><span style="color: #009900;">&#40;</span>AddPhotosPage.<span style="color: #000000; font-weight: bold;">class</span>, 
		<span style="color: #0000ff;">&quot;css/AddPhotosPage.css&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	UserSession session <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>UserSession<span style="color: #009900;">&#41;</span> Session.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">long</span> userId <span style="color: #339933;">=</span> session.<span style="color: #006633;">getUser</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	HttpServletRequest r <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>WebRequest<span style="color: #009900;">&#41;</span> RequestCycle.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getHttpServletRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	session.<span style="color: #006633;">createFormToken</span><span style="color: #009900;">&#40;</span>r.<span style="color: #006633;">getRemoteAddr</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003399;">String</span> tokenId <span style="color: #339933;">=</span> session.<span style="color: #006633;">getFormToken</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getToken</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #003399;">String</span> sessionId <span style="color: #339933;">=</span> session.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// Configure the panel</span>
	UploadifyPanelBehaviour behaviour <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> UploadifyPanelBehaviour<span style="color: #009900;">&#40;</span>AddPhotosProcessingPage.<span style="color: #000000; font-weight: bold;">class</span>, tokenId,
		sessionId<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	behaviour.<span style="color: #006633;">setFileExt</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;*.jpg;*.jpeg;*.gif;*.png&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	behaviour.<span style="color: #006633;">setFileDesc</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Select files of type *.jpg, *.jpeg, *.gif, *.png&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	behaviour.<span style="color: #006633;">setSizeLimit</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;3000000&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	add<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> UploadifyPanel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;uploads&quot;</span>, behaviour<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">final</span> UnprocessedPhotosPanel unprocessedPanel<span style="color: #339933;">;</span>
	add<span style="color: #009900;">&#40;</span>unprocessedPanel <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> UnprocessedPhotosPanel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;unprocessedPhotos&quot;</span>, userId<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	unprocessedPanel.<span style="color: #006633;">setOutputMarkupId</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Label</span> noPhotosLabel<span style="color: #339933;">;</span>
	add<span style="color: #009900;">&#40;</span>noPhotosLabel <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Label</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;noPhotosLabel&quot;</span>, <span style="color: #0000ff;">&quot;You haven't uploaded any new photos!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	noPhotosLabel.<span style="color: #006633;">setOutputMarkupId</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>unprocessedPanel.<span style="color: #006633;">getUnprocessedPhotosCount</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    noPhotosLabel.<span style="color: #006633;">setVisible</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
	    noPhotosLabel.<span style="color: #006633;">setVisible</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">final</span> IBehavior repaintBehavior <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> AbstractDefaultAjaxBehavior<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    @Override
	    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> respond<span style="color: #009900;">&#40;</span>AjaxRequestTarget target<span style="color: #009900;">&#41;</span>
	    <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// this repaints the list view</span>
		<span style="color: #666666; font-style: italic;">// this requires your model to always get the most</span>
		<span style="color: #666666; font-style: italic;">// up-to-date list</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>unprocessedPanel.<span style="color: #006633;">getUnprocessedPhotosCount</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		    noPhotosLabel.<span style="color: #006633;">setVisible</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
		    noPhotosLabel.<span style="color: #006633;">setVisible</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		target.<span style="color: #006633;">addComponent</span><span style="color: #009900;">&#40;</span>noPhotosLabel<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		target.<span style="color: #006633;">addComponent</span><span style="color: #009900;">&#40;</span>unprocessedPanel<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	    <span style="color: #009900;">&#125;</span>
&nbsp;
	    @Override
	    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> renderHead<span style="color: #009900;">&#40;</span>IHeaderResponse response<span style="color: #009900;">&#41;</span>
	    <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">super</span>.<span style="color: #006633;">renderHead</span><span style="color: #009900;">&#40;</span>response<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		CharSequence callback <span style="color: #339933;">=</span> getCallbackScript<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		response.<span style="color: #006633;">renderJavascript</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;function uploadCompleted() { &quot;</span> <span style="color: #339933;">+</span> callback <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;}&quot;</span>, <span style="color: #0000ff;">&quot;customUploadCompleted&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	    <span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
	add<span style="color: #009900;">&#40;</span>repaintBehavior<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	add<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Image</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;easy&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> ResourceReference<span style="color: #009900;">&#40;</span>AddPhotosPage.<span style="color: #000000; font-weight: bold;">class</span>, <span style="color: #0000ff;">&quot;easy.png&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>This example is a little long-winded, but it ties everything together and shows a few key concepts. Most interesting is our ability to asynchronously invoke a piece of code when all uploads are complete by using Wicket&#8217;s fantastic built in Ajax support. We do this by creating a new repaintBehaviour object and overriding both respond (which contains the actual code we want to invoke asynchronously) and renderHead (which injects this callback method inside our HTML).</p>
<p>Other than that, most things are quite straightforward. We tie everything together by configuring our behaviour object and instantiating the processing page. </p>
<h2>Conclusion</h2>
<p>Enabling true multiple upload support is fairly straightforward with the Flash plugins readily available. Uploadify is my favourite, but there are a ton to choose from. Integrating with Apache Wicket is a piece of cake, and as always, Wicket just makes life a little easier for Java developers. <img src='http://kevinontheweb.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/291/integrating-uploadify-with-java-using-apache-wicket/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Eating steak with a dull knife</title>
		<link>http://kevinontheweb.com/posts/223/eating-steak-with-a-dull-knife</link>
		<comments>http://kevinontheweb.com/posts/223/eating-steak-with-a-dull-knife#comments</comments>
		<pubDate>Fri, 12 Mar 2010 19:13:08 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[Customer]]></category>
		<category><![CDATA[Software development]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<category><![CDATA[Usability]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/?p=223</guid>
		<description><![CDATA[What do people expect from your brand on the internet?
In the past, companies relied on putting out a solid product or offering a quality service. Their internet presence may have been a little clumsy and unreliable, but customers were willing to forgive a painful online experience. After all, doing business on the internet was something [...]]]></description>
			<content:encoded><![CDATA[<p>What do people expect from your brand on the internet?</p>
<p>In the past, companies relied on putting out a solid product or offering a quality service. Their internet presence may have been a little clumsy and unreliable, but customers were willing to forgive a painful online experience. After all, doing business on the internet was something that very few companies were doing perfectly. There was a time when a mediocre online presence was better than no online presence at all.</p>
<p><span id="more-223"></span></p>
<p>Times have changed. Customers have high expectations of web applications, and especially web applications that <span style="text-decoration: underline;">take their money</span>. A failed transaction on the internet is no less frustrating than a failed transaction at a brick and mortar store.</p>
<p><em>The entire end-to-end customer experience surrounding a product or service is just as important as the product or service itself.</em></p>
<p>An interesting quote that comes to mind about this subject is from <strong>Gordon Ramsey</strong>, who waxes poetically about quality in his own special way:</p>
<p style="padding-left: 30px;"><em>“It doesn’t matter how amazing the steak is, if it’s served on a cold plate it’s crap. If it’s served with a dull knife it’s crap. If the gravy isn’t piping hot, it’s crap. If you’re eating it on an uncomfortable chair, it’s crap. If it’s served by an ugly waiter who just came in from a smoke break, it’s crap. Because I care about the steak, I have to care about everything around it.“</em></p>
<p>We take for granted how seamless doing business on the internet <em>usually</em> is. I&#8217;ve been buying and selling online since Amazon first opened their doors. In them old days (less than 10 years ago), things were pretty sketchy. Transactions failed routinely and websites often provided a frustrating customer experience. <strong>Things have changed significantly since then.</strong> Now when I do business online it almost <strong>always</strong> just <span style="text-decoration: underline;">works</span>. But once in awhile a company does the equivalent of serving a beautiful steak on a cold plate, with a dull knife, by a waiter who ashed all over my gravy.</p>
<h2>A real life example</h2>
<p>I recently tried to buy a product from <a href="http://www.native-instruments.com/#/en/" target="_blank">Native Instruments</a> via their online shop. I downloaded a trial version of Guitar Rig 4 Pro, used it, and loved it enough that I decided that I wanted to give them $199 USD of my hard earned money. They obviously spent a lot of time producing a nice demo to entice a purchase, but they dropped the ball on a crucial aspect of the <span style="text-decoration: underline;">purchase chain</span>; their online shop. I wanted to start <em>rocking out, </em>immediately. I wanted to pay them.</p>
<p><strong>Convincing a customer to give you money is the hard part. </strong></p>
<p><strong><em><span style="font-weight: normal;">Taking it should be easy.</span></em></strong></p>
<p>I&#8217;ve bought a number of excellent music-related products over the internet from wonderful companies including <a href="http://www.xlnaudio.com/" target="_blank">XLN Audio</a>, <a href="http://www.izotope.com/" target="_blank">iZotope</a>, <a href="http://www.ableton.com/" target="_blank">Ableton</a>, and the list goes on. Software companies are, generally speaking, remarkably good at making sure customers have no problem giving them money. They <strong>are </strong>software companies, after all, it&#8217;s their bread and butter. Their web-based software should be of the same quality as the rest of the software they produce and sell.</p>
<h2>Trying out the demo version</h2>
<p>First off, Guitar Rig 4 Pro <span style="text-decoration: underline;">rocks</span>. I wanted to give my money to Native Instruments so I could party like it was 1999. I took the demo version for a spin and fell in love. The demo version clearly explains how to go about becoming a paid customer:</p>
<p><a href="http://kevinontheweb.com/wp-content/uploads/2010/03/Picture-11.png"><img class="alignnone size-full wp-image-228" title="Picture 1" src="http://kevinontheweb.com/wp-content/uploads/2010/03/Picture-11.png" alt="" width="518" height="347" /></a></p>
<p>So far, so good. The dialog clearly communicates the ordering options. I can either go to the store (reseller), or grab a copy from the online shop. Obviously, I decide on the online shop. I want to rock out, <strong>now</strong>! I&#8217;m figuring it&#8217;s a simple credit card transaction before I can click on that nice little <em>Activate </em>button and be well on my way to playing arenas!</p>
<h2>Spending money</h2>
<p>I click <em>Buy, </em>and instead of being taken to a page specifically related to purchasing Guitar Rig 4, I was taken to <a href="http://www.native-instruments.com/index.php#/en/?content=1113" target="_blank">their main site</a>. Interesting. They&#8217;ve just put multiple steps in between their customer and their customer&#8217;s money. This is always a bad idea from a usability perspective. If you&#8217;re selling a product or service online, repeat after me: <strong>taking money should be easy</strong>. <em>As few clicks as possible. Keep it simple.</em> Regardless, I find what I&#8217;m looking for quick enough, the download version of Guitar Rig 4 Pro.</p>
<p><a href="http://kevinontheweb.com/wp-content/uploads/2010/03/Picture-2.png"><img class="alignnone size-full wp-image-229" title="Picture 2" src="http://kevinontheweb.com/wp-content/uploads/2010/03/Picture-2.png" alt="" width="351" height="209" /></a></p>
<p>I make my selection and attempt to check out. I enter all of my personal details, my credit card information, and complete the multi-step check out process. I anxiously await a serial number, or at least the promise of a serial number. I&#8217;m mere moments away from rocking out!</p>
<p><strong>Instead, catastrophe!</strong> I&#8217;m redirected to an error page that instructs me to contact order support. I don&#8217;t receive any kind of e-mail notification of the error, or even a helpful phone number to call. Not even a <em>link</em> to an order support contact form! Just a cryptic sentence, <em>&#8220;contact order support.&#8221;</em></p>
<p>At this point I have no idea what stage of the transaction failed. Was the error related to processing my credit card? Was the transaction itself successful but an error occurred during acknowledgment? Did something go horribly wrong and they&#8217;re shipping a boxed version to me instead? At this point I simply want to cancel the entire transaction and go buy a boxed version from a retail outlet, but I don&#8217;t want to wind up owning two copies of Guitar Rig 4 Pro, as much as I like it. I obediently fill out the support form to enquire about the error. I anxiously await a response. Here&#8217;s part of the automated response letter I receive a few moments later:</p>
<p style="padding-left: 30px;"><em>&#8220;Dear Customer,</em></p>
<p><em> </em></p>
<p style="padding-left: 30px;"><em>thanks for your e-mail. A new ticket has been created for your request. We will reply to your request as soon as possible.<br />
We are currently reorganizing our whole Order Management System in order to provide you with an even better and improved service. Due to the complex technical migration, delays in delivery and billing can emerge in individual cases.<br />
We are working intensely on the fluent implementation of the new system, and we would like to apologize for possible inconveniences.&#8221;</em></p>
<p>This response brings up a few interesting points concerning the end-to-end customer experience of an e-commerce site:</p>
<ul>
<li><strong>Always provide a clear timeframe for a human response.</strong> Expectations count. Will a response arrive within an hour? 24 hours? A business day? 48 hours? A month?<em> &#8220;As soon as possible&#8221; </em>is about the same as <em>&#8220;whenever we feel like it&#8221;.</em></li>
<li><strong>Technical debt is evil.</strong> Native Instruments incurred technical debt with their existing ordering system and are &#8220;working intensely on the fluent implementation of the new system&#8221;. Their technical debt is bad enough that they communicate it to all customers that request support. Decisions like this are organizational, and can always be avoided. There&#8217;s no need to ever be in a position that a major overhaul of any system is required to simply keep the lights on.</li>
<li><strong>Be like Oz.</strong> Sometimes it&#8217;s better for the wizard to hide behind the curtain. It&#8217;s perfectly alright not to tell your customers everything about your internal systems. Then again, customers don&#8217;t care what lurks behind the curtain when your systems actually <span style="text-decoration: underline;">work</span>.</li>
<li><strong>Simple things should be simple. </strong>We&#8217;ve been accepting payments over the interweb for well over a decade. This is trivial stuff. Don&#8217;t focus so intensely on the difficult aspects of your business (such as developing a guitar amp simulator) that you&#8217;re forced to neglect the easy stuff (providing prompt responses to support enquires).</li>
<li><strong>Don&#8217;t make <span style="text-decoration: underline;">your</span></strong><strong> problems your customer&#8217;s problems. </strong>Native Instruments is obviously having issues with their payment system. The technical migration of their online system is <span style="text-decoration: underline;">complex</span>. They told me all about it! All of a sudden their complex technical migration became my problem. <em>Fix problems, don&#8217;t explain them. </em>Obviously, nothing is perfect, and once in awhile issues crop up that demand solutions. Having spent over a decade developing web-applications for banks, I&#8217;ve dealt with my share of technical issues that required immediate solutions. If a &#8220;payment system&#8221; was so broken that we felt compelled to offer an explanation in an auto-response e-mail, we would have simply shut it down until the problem was resolved. And trust me, we would have been working rotating 24/7 shifts to get the payment system back to full health.</li>
</ul>
<p>At the bottom of the auto-responder e-mail I received is a phone number, so I decided to call it.</p>
<p style="padding-left: 30px;"><em>&#8220;Native Instruments North America, Inc.<br />
5631 Hollywood Blvd.<br />
Los Angeles, CA 90028<br />
USA<br />
</em><a href="http://www.native-instruments.com/"><em>http://www.native-instruments.com</em></a><em> </em></p>
<p style="padding-left: 30px;"><em> </em></p>
<p style="padding-left: 30px;"><em>Tel +1.866.556.6487<br />
Fax +1.866.556.6490&#8243;</em></p>
<p>Unfortunately, no go. I&#8217;m from Canada. That 1-866 number they sent me is only reachable from the USA. Even though I entered my location information on their support contact form, they still provide me with a support number that I&#8217;m unable to reach.</p>
<ul>
<li><strong>Make sure the entire experience of your site is custom tailored to your customers.</strong><em> </em>If you ask for personal details, use them. <em>Small details count. </em>If you ask for someone&#8217;s full name, use it in all your communications with them, including auto-response e-mails.</li>
<li><em> </em><strong>Localization counts. </strong>The world is a small place. It&#8217;s not USA-centric. It should be easy and clear for customers to contact you no matter where they live. If your 1-800 number only works in the USA, but your customer lives in South America, make sure to provide them with a number they can actually call.</li>
</ul>
<h2>Doing it right</h2>
<p>Companies like <a href="http://www.rackspace.com/index.php" target="_blank">Rackspace</a> get customer service right. They go even further than providing prompt e-mail and phone support; they provide live, 24/7, human-to-human text chat via their site with guaranteed response times. These types of services are available for next to nothing for <strong>any site</strong> and are a great way to boost customer satisfaction. <a href="http://getsatisfaction.com/" target="_blank">Get Satisfaction</a> is another company whose entire purpose is customer support, or more accurately, customer-centric support.</p>
<h2>Doing it wrong</h2>
<p>After digging around on the Native Instruments site a little while longer, I found a local Los Angeles number to call for support. I dialed them up and dug through the menu options, finally to be told that &#8220;all available operators are busy&#8221; and that if I&#8217;m calling during regular business hours to &#8220;try again later&#8221;.</p>
<p><em>No thanks.</em> I&#8217;m at the point where it&#8217;s easier to deal with the credit card company if anything funky shows up on my statement.</p>
<p><strong>Moral of the story?</strong> Pay attention to the <strong>entire</strong> customer experience. Every single detail that surrounds the product or service you offer is <span style="text-decoration: underline;">just as important as the product or service itself</span>. You usually only get one shot to take someone&#8217;s money. <em>The hard part is convincing them to give it to you to in the first place.</em> <strong>Don&#8217;t refuse to accept it.</strong></p>
<p>Don&#8217;t get me wrong. Native Instruments produces some wonderful software. Guitar Rig 4 Pro is awesome, which is why I wanted to buy it in the first place. I just wish the plate they served it on was warmer, the chair was more comfortable, and the waiter didn&#8217;t ash all over my gravy.</p>
<h2>The outcome</h2>
<p>I sent the e-mail to order support over a week ago and still haven&#8217;t heard back from Native Instruments. The great thing about the internet is that a competing product is never far away&#8230;</p>
<p>Luckily for me, <a href="www.ikmultimedia.com" target="_blank">IK Multimedia</a> recently released <a href="http://www.ikmultimedia.com/amplitube/features/" target="_blank">AmpliTube 3</a>. I hadn&#8217;t tried the demo out before I attempted my Guitar Rig purchase, but holy f#!@, am I glad I found this thing! <strong>I&#8217;ve never heard tone like it, it&#8217;s amazing!</strong> The box shot sums up exactly how I feel right now&#8230; <img src='http://kevinontheweb.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><a href="http://kevinontheweb.com/wp-content/uploads/2010/03/Picture-3.png"><img class="alignnone size-medium wp-image-266" title="King of Tone" src="http://kevinontheweb.com/wp-content/uploads/2010/03/Picture-3-300x150.png" alt="" width="300" height="150" /></a></p>
<p>Sometimes you only get one chance to make a sale. Sometimes you get a second chance. If you screw both up, remember that there&#8217;s <strong>always</strong> a competing company ready to take your customer&#8217;s money.</p>
<p>Also remember that no matter how good your product is, the entire experience <strong>surrounding</strong> the purchase and ongoing use of a product is just as important as the product itself. <span style="text-decoration: underline;">Coffee shops manage to get this right</span>, otherwise we&#8217;d all be drinking 25 cent coffee at home. <img src='http://kevinontheweb.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/223/eating-steak-with-a-dull-knife/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Be a revolutionary</title>
		<link>http://kevinontheweb.com/posts/127/be-a-revolutionary</link>
		<comments>http://kevinontheweb.com/posts/127/be-a-revolutionary#comments</comments>
		<pubDate>Tue, 23 Feb 2010 18:11:15 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[Career]]></category>
		<category><![CDATA[Software development]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/?p=127</guid>
		<description><![CDATA[Good developers always strive to become better. We spend time searching for the perfect language, the perfect framework, the perfect IDE, the perfect testing tool, the perfect methodology.
Building great software requires all of these things, albeit nothing is perfect. There is no perfect methodology, language, or tool. At times we focus so much on the [...]]]></description>
			<content:encoded><![CDATA[<p>Good developers always strive to become <em>better</em>. We spend time searching for the perfect language, the perfect framework, the perfect IDE, the perfect testing tool, the perfect methodology.</p>
<p>Building great software requires all of these things, albeit nothing is perfect. There is no perfect methodology, language, or tool. At times we focus so much on the most complex things that we forget how to do the most simple things, like designing software that people actually <em>enjoy</em> using. In some large organizations it can feel like a single line of code is a million miles away from the person using the application. In some large organizations it can feel like everyone is more interested in delivering <em>projects</em> than <em>applications,</em> meeting <em>targets</em> rather than delivering an amazing <em>user experience</em>.</p>
<p>Good developers always try to deliver amazing software in spite of these obstacles. The perfect methodology for our team may not integrate well with the rest of the organization. The perfect programming language may be unknown to most developers on the team. The perfect architecture may require three months to develop but the deadline is three weeks away. Eventually we discover a harmonious balance between pragmatism and idealism, or we struggle to produce quality software. How does a team who is forced to compromise eventually triumph and deliver software that is reliable, easy to maintain, and a pleasure to use?</p>
<p><strong>Morale.</strong></p>
<p><span id="more-127"></span></p>
<p>I recently watched the movie <strong>Che </strong>by Steven Soderbergh<strong>.</strong> I&#8217;m trying to avoid writing a lame analogy that compares software development to war, I&#8217;ve heard them before; I worked with a guy that served in the military briefly, or at least dreamt that he did. He endlessly compared software development to building an aircraft, taking off in an aircraft, piloting an aircraft, dropping bombs from an aircraft, eating a snack in an aircraft, and landing an aircraft. I never did quite figure out what he was talking about, but I assure you I&#8217;m not going to compare software to a plane. Or a bomb. Or snacks.</p>
<p>That being said, a specific quote from the movie Che caught my attention:</p>
<p><em>&#8220;In War and Peace, Tolstoy remarks that military science assumes that the bigger the army, the stronger it is. On the other hand, only vaguely do they recognize that during military combat the final strength of an army is also its true physical capacity multiplied by one unknown </em><strong><em>x</em></strong><em>. This </em><strong><em>x</em></strong><em> is none other than the spirit of the troops measured as the greater or lesser desire to fight and confront danger. Men with the desire to fight, who also understand why they are fighting, regardless of who they are fighting, whether under the command of military geniuses or those of normal intelligence, fighting with clubs or with machine guns that fire thirty rounds a minute, these men will put themselves under the most advantageous conditions for fighting and they will triumph.&#8221;</em></p>
<p>The effect morale has on team performance is staggering.</p>
<p>I once worked on a project that was practically doomed to failure from the very beginning. The design had been bounced around and re-assigned from developer to developer like a hot potato. It was underfunded, underestimated, and practically written off by upper management. All of a sudden the client had to have it delivered <strong>yesterday</strong>. By the time our team took over, it resembled a stray cat that had been sleeping in an alley for five years. The team was feeling low, real low, but we had one previously unknown <em><strong>x</strong></em> on our side. <strong>Our manager.</strong> For the next eight weeks, he refused to go home if a member of the development team was still at work. He brought us dinner, checked to see if we needed coffee, offered unrelenting encouragement, and stood up for us when upper management wondered why it hadn&#8217;t been completed <em>ten days before we even started</em>. <span style="text-decoration: underline;">A number of small gestures added up to become something much larger.</span> He understood the constraints we were under, but more importantly, <strong>we</strong> <strong>knew </strong>that<strong> </strong>he understood. He didn&#8217;t just understand from an ivory tower perspective, he understood from a human perspective. He understood the toll the project took on our time with our families, on our hobbies, and on our sleep. He reminded us that there was a light at the end of the tunnel. We did our absolute best under some fairly dismal circumstances, and we eventually succeeded as a team.</p>
<p>Obviously, it&#8217;s impossible to work under these conditions forever. But working with a great team, with a great manager, and on projects you believe in will give you the motivation to push through some fairly insane obstacles; even the corporate-imposed inertia variety.</p>
<p>Another quote from the movie Che:</p>
<p><em>&#8220;A real revolutionary goes where he is needed. It may not be direct combat. Sometimes it&#8217;s about doing other tasks; finding food, dressing wounds, carrying comrades for miles, and then taking care of them until they can take care of themselves.&#8221;</em></p>
<p>A real developer feels the same way. So does a real architect, and a real manager. Sometimes it&#8217;s not about the task of writing code, but the task of helping others. When I was first starting out in development, I came to work feeling under the weather. I didn&#8217;t want to miss a day and burden the team. It was brutal cold outside, so my manager brought me lunch without even asking if I needed anything; she remembered that I always went across the street to buy it. She refused to take my money when I offered to pay her back. She also reminded me that I was part of a team, and that coming to work sick was counterproductive. If everyone else became sick, we would be far worse off than if I had taken some time off to get better. I never forgot those small gestures. Eventually she was promoted higher up the corporate hierarchy, and trust me, I did everything in my power to help along the way. From that day forward I was her <em>code ninja assassin</em>. Moral of the story? <strong>Morale.</strong> It&#8217;s no different than a developer staying late to help out another developer, a tester learning how to automate regression tests, or an architect digging into code if the team is behind schedule. Teams with high morale do all of this. Teams with low morale, regardless of any technological or process advantages, do none of this. Teams with low morale stick to job titles and commuter schedules. High performing teams recognize and foster a culture of support rather than rewarding the heroic efforts of any one individual superstar.</p>
<p>I don&#8217;t think there is a one-size fits all approach to boosting morale. There are some universal, common sense things that everyone should do, like treating people with respect, asking questions instead of pointing fingers when things go wrong, and making sure to acknowledge people when they lend you a helping hand. But everyone has a different agenda at work, so something that boosts my morale may have the opposite effect on someone else. Some folks only write code for the paycheque, while others are passionate about development and really want to make great software. As a manager, I think it&#8217;s critical to identify who is who and assign them to the right roles. Empower the people with passion and they will constantly strive to make the organization <em>better. </em>Assign the paycheque developers to tasks that need to get done but aren&#8217;t very challenging or interesting (assuming you can&#8217;t simply <em>replace</em> them, which is easier said than done). As a developer, you can do great things if you work with a great team, a great manager, and on projects you believe in. Cut yourself loose if all three of these conditions aren&#8217;t met, otherwise you&#8217;re just wasting time.</p>
<p>Motivated people with high morale will always put themselves under the most advantageous conditions to succeed, regardless of the challenges they face.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/127/be-a-revolutionary/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Apache Aries: OSGi for the Enterprise</title>
		<link>http://kevinontheweb.com/posts/44/apache-aries-osgi-for-the-enterprise</link>
		<comments>http://kevinontheweb.com/posts/44/apache-aries-osgi-for-the-enterprise#comments</comments>
		<pubDate>Wed, 18 Nov 2009 03:18:00 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[OSGi]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/posts/17/apache-aries-osgi-for-the-enterprise</guid>
		<description><![CDATA[A brief overview of Apache Aries, an OSGi container.]]></description>
			<content:encoded><![CDATA[<p>I recently came across a <a href="http://ianrobinson.blogspot.com/2009/09/osgi-in-enterprise-apache-aries.html" target="_blank">blog posting</a> about an Apache project called Aries, currently in incubator status. You can <a href="http://wiki.apache.org/incubator/AriesProposal" target="_blank">check out the details here</a>. It looks like enterprise developers are in for a real treat: the missing secret sauce (programming model) that allows enterprise application developers to harness the goodness of OSGi.</p>
<p><span id="more-44"></span></p>
<p><em>&#8220;Aries will offer an enterprise OSGi application programming model that enables applications to leverage Java EE and other enterprise technologies and to benefit from the modularity, dynamism and versioning capabilities of OSGi.&#8221;</em></p>
<p>This is fantastic news! OSGi is quite an amazing technology, but even though mature, lacks support in the enterprise world due to a lack of application server support. The support for enterprise OSGi looks to be increasing, especially when you see the organizations represented in the committer list: LinkedIn, IBM, SAP, etc. One of the issues affecting the adoption rate of OSGi is the lack of commercial app server support; in other words, the inability to hot-deploy an OSGi bundle in your favourite app server.</p>
<p>A few more noteworthy highlights:</p>
<ul>
<li>&#8220;<em>A significant feature of Aries will be a container for OSGi Blueprint components &#8211; an implementation of the new OSGi v4.2 Blueprint component model that defines a standard dependency injection mechanism for Java components, which is derived from the Spring framework and extended for OSGi to declaratively register component interfaces as services in the OSGi service registry.&#8221;</em></li>
</ul>
<ul>
<li style="list-style-image: initial; list-style-position: initial; list-style-type: none;">
<ul>
<li><em><span style="font-style: normal;">It looks like the functionality provided by Spring DM (Dynamic Modules) is part of the official spec now. This is nice, because one of the challenges with plain old OSGi is managing the availability and injection of service references. The interesting thing is that this functionality will be offered by the <strong>container</strong> in a standard way (for portability between runtimes). &lt;MrBurns&gt;Excellent&#8230;&lt;/MrBurns&gt;</span></em></li>
</ul>
</li>
</ul>
<ul>
<li>&#8220;<em>Message-driven Blueprint components.&#8221;</em></li>
</ul>
<ul>
<li style="list-style-image: initial; list-style-position: initial; list-style-type: none;">
<ul>
<li>This is very interesting, because one of the challenges with OSGi is the dynamic nature of services. Dealing with dynamic services synchronously with no guarantee a bundle is running can be challenging. Even with Spring as a proxy to the real OSGi service, there&#8217;s always the dilemma of how long is a reasonable amount of time to wait for an unavailable service. For operations that aren&#8217;t critical, handling them asynchronously is the way to go; fire, forget, call me back later.</li>
</ul>
</li>
</ul>
<ul>
<li><em>&#8220;Federation of lookup mechanisms between local JNDI and the OSGi service registry.&#8221;</em></li>
</ul>
<ul>
<li style="list-style-image: initial; list-style-position: initial; list-style-type: none;">
<ul>
<li>Either I&#8217;m misinterpreting what they mean by federation, or it sounds like they&#8217;re building a layer of abstraction on top of the OSGi service registry and the JNDI registry. What I&#8217;m not quite clear on is if they&#8217;re providing a new API, or if OSGi lookups will be done via the JNDI API. I&#8217;m hoping it&#8217;s the latter.</li>
</ul>
</li>
</ul>
<ul>
<li><em>&#8220;the Geronimo blueprint sandbox .. contains an implementation of the OSGi Blueprint container which will be moved to Aries..&#8221;</em></li>
</ul>
<ul>
<li style="list-style-image: initial; list-style-position: initial; list-style-type: none;">
<ul>
<li>The OSGi Blueprint container being moved from Geronimo to Aries is significant in the fact that, theoretically, Aries can be run on any Java EE app server. This would be huge and take away a major roadblack to OSGi adoption for most people. Simply put, deploying OSGi applications to productive is either too complicated (if you want to embed and make use of Java EE features), or too limiting (running natively and losing out on EE + container managed <em>everything</em>).</li>
</ul>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/44/apache-aries-osgi-for-the-enterprise/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wicket, OSGi, and Spring DM</title>
		<link>http://kevinontheweb.com/posts/36/wicket-osgi-and-spring-dm</link>
		<comments>http://kevinontheweb.com/posts/36/wicket-osgi-and-spring-dm#comments</comments>
		<pubDate>Thu, 12 Nov 2009 02:13:00 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[OSGi]]></category>
		<category><![CDATA[Spring DM]]></category>
		<category><![CDATA[Wicket]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/posts/16/wicket-osgi-and-spring-dm</guid>
		<description><![CDATA[You’ve probably heard of both OSGi and Apache Wicket. If you haven’t, holy doodle… you’re missing out on a wonderful world of Java goodness! I’m not kidding. Wicket and OSGi are two very exciting technologies.
In this tutorial we&#8217;re going to set up an OSGi container, create a sample OSGi bundle that uses the Wicket framework, [...]]]></description>
			<content:encoded><![CDATA[<p style="clear: both;">You’ve probably heard of both OSGi and Apache Wicket. If you haven’t, <em>holy doodle</em>… you’re missing out on a wonderful world of Java goodness! I’m not kidding. Wicket and OSGi are two very exciting technologies.</p>
<p style="clear: both;">In this tutorial we&#8217;re going to set up an OSGi container, create a sample OSGi bundle that uses the Wicket framework, and deploy the bundle to our container.</p>
<p><span id="more-36"></span></p>
<h2>Hello, OSGi</h2>
<p style="clear: both;">As modular as your code is at compile and build time using super-creative archiving and package-naming cleverness, all your objects wind up in the same bowl of runtime soup. <em>It’s kind of like taking the time to cook a wonderful meal, only to throw it in a blender before serving it.</em> Sure, creating modular Java applications is possible without OSGi by creating a physical or logical separation between components; packaging classes in different EARs/WARs, and/or the tried-and-true “common artifact” bundle. Sounds great, but the logical separation achieved by the common artefact strategy dissolves at runtime. Creating a true physical separation via distributed communications (WS, REST, etc) cleanly separates entities at runtime, but comes with a performance penalty. Also, the latter strategy only works for webapps; embedded or desktop apps can’t make use of distributed communications. Imagine if all the Eclipse plugins you have installed needed to communicate via WS* or REST?</p>
<p style="clear: both;">All we <em>really</em> need is a way to modularize our runtime environment in the same way we do with our build artifacts.</p>
<p style="clear: both;">Enter the dragon: OSGi.</p>
<p style="clear: both;">Cleanly separated bundles. Hidden internal classes. Explicitly defined inter-bundle dependencies. I’m so happy! It’s like plain old Java, but <strong>zen</strong>. I hear WebSphere, JBoss, et al. are built on top of OSGi containers now. How about I go ahead, create an OSGi bundle, deploy it to my most favourite-ist enterprise app server, and celebrate with some Doritos and Cherry Coke!</p>
<p style="clear: both;">Wait… there’s a catch.</p>
<p style="clear: both;">At the present time, OSGi doesn’t have the tooling and app server support as of now to make it a reasonable solution for most enterprise web development projects. There, I said it. :p</p>
<p style="clear: both;">One of the interesting facts about the current generation of app servers is that while most vendors have spent a huge amount of effort and resources refactoring their offerings and building them on OSGi containers, the developers <strong>using</strong> said app servers cannot take advantage of all this internal vendor OSGi goodness. At the time of this writing, the only enterprise app server ready to gobble up your OSGi bundles is the <a href="http://www.springsource.com/products/dmserver">SpringSource dm Server</a>. It supports both complete OSGi bundle support (RFC-124) and also OSGi web bundles (RFC-66). The folks at IBM and Oracle (BEA) haven’t bothered to pass on all the OSGi goodness to mere mortals like myself who actually develop and deploy functional web applications for a living.</p>
<p style="clear: both;">So… if you work at a massively-massive corporation like I do, you’re probably using an app server from one of the big-boys (WebSphere, Weblogic, or something equally enterprise-y). Introducing a new app server to your production environment isn’t going to happen for technological reasons. Unless you’re lucky and have more flexibility than most of us (or work at a small company), I recommend looking at OSGi in terms of long-term strategic planning rather than a short-term tactical decision. So, why am I spending time with OSGi then? As soon as the major app server vendors start to fully support OSGi, the shift towards this technology will be fast and totally rational (in my humble opinion). In other words…</p>
<p style="clear: both;"><strong>OSGi is fantastic!</strong></p>
<p style="clear: both;">The lack of server support is the only thing holding back the OSGi adoption rate. I highly recommend learning and using OSGi for specific projects; just be careful not to commit “design-by-buzzword” and clobber together a half-baked OSGi solution into your enterprise ecosystem.</p>
<p style="clear: both;">With that said, building an OSGi-fied “Hello World” Wicket app seems like a good first step towards OSGi nirvana!</p>
<p style="clear: both;"><strong>Word of warning:</strong> Most of this tutorial relies on the magic provided by Spring DM. My understanding is that as of version 2.0, Spring DM will deprecate support for web bundles and Tomcat / Jetty integration in favour of supporting official OSGi standards. Basically, this means that Spring DM will expect your OSGi container to provide these services (RFC-66 specifically). Make sure to use Spring DM 1.2.x or above, <strong>but not</strong> 2.x.</p>
<h2><strong>Apache Wicket</strong></h2>
<p style="clear: both;">Wicket makes it cool to be a Java developer again, seriously! Apache Wicket is simply the most fun and productive UI framework I’ve ever worked with. Yes, that’s a strong statement, but it’s true! I wish Wicket happened a decade ago. Until now Java developers have been burdened with overly complex view technologies (like JSF) that almost guaranteed the success of lightweight frameworks like RoR and Grails.</p>
<p style="clear: both;">Beyond the cool factor, Wicket finally gives us Java-heads an opportunity to take a deep breath and harness the epic (and underutilized) powers of our tasty Java + OOA/D knowledge… and we can wield these powers on the <em>UI</em> now. <em>Holy doodle!</em></p>
<h2>Tutorial (On with the show!)</h2>
<p style="clear: both;">Before we go much further, I assume you have a working-level knowledge of both OSGi and Wicket and are looking to wire them together without using any magic. If you’re completely new to OSGi, I recommend reading <a href="http://www.javaworld.com/javaworld/jw-03-2008/jw-03-osgi1.html" target="_blank">this article</a>.</p>
<p>And don&#8217;t forget to check out <a href="http://wicket.apache.org/" target="_blank">the Wicket site</a> if you’re new to Wicket.</p>
<h3><strong>Step 1: Get your OSGi container Tomcat-ified</strong></h3>
<p style="clear: both;">We’re going to make a few assumptions. The first is that you’re going to use <a href="http://wiki.ops4j.org/display/paxconstruct/Pax+Construct">Pax Construct</a> rather than create OSGi bindings and configuration files by hand, the second is that you’re going to use Apache Felix as your OSGi container, and the third is that you’re going to use Tomcat as your Java/JSP container.</p>
<p style="clear: both;">Pax Construct is like the Yoda of OSGi development. It simply does <em>stuff</em>. Epic stuff. Learn it, know it, love it. There <em>is also</em> a project called <a href="http://www.ops4j.org/projects/pax/wicket/">Pax Wicket</a> that you may want to check out. It accomplishes a different goal that what I’m going for, which is simply trying to decide if A) Wicket would even <em>work</em> in an OSGi container, and B) If it was worth the effort to explore deeper. The answer is yes, and yes!</p>
<h3><strong>Step 2: Creating a new OSGi project</strong></h3>
<p style="clear: both;">Okay, so enough with the preamble. Let’s get rolling.</p>
<ul style="clear: both;">
<li>Download and install the latest version of <a href="http://wiki.ops4j.org/display/paxconstruct/Pax+Construct">Pax Construct</a> from <a href="http://wiki.ops4j.org/display/paxconstruct/Download">here</a>. At the time of writing, the latest version is 1.4.</li>
<li>Make sure you have <a href="http://maven.apache.org/">Maven</a> installed and configured properly.</li>
<li>Execute the following at your command line to create your OSGi project:

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pax-create-project <span style="color: #660033;">-g</span> org.itypeincaps <span style="color: #660033;">-a</span> osgilywicket <span style="color: #660033;">-v</span> <span style="color: #000000;">1.0</span>-SNAPSHOT</pre></div></div>

</li>
<li>Add Java 1.5 support to your Maven POM. Edit the <code>pom.xml</code> file in osgilywicket root and add:

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.maven.plugins<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>maven-compiler-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
     <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;source<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1.5<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/source<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
     <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;target<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1.5<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/target<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
</ul>
<h3><strong>Step 3: Add the SpringSource OSGi bundle repository</strong></h3>
<p style="clear: both;">A significant number — the majority — of dependencies are not distributed as proper OSGi bundles. However, <a href="http://www.springsource.com/repository/app/">SpringSource has a repository</a> with a number of OSGi bundles.</p>
<p style="clear: both;">Check to see if the version of your dependency exists in the SpringSource repository first. For instance, if you want to use version 1.4.3 of Wicket, check SpringSource first. If it exists, <strong>fantastic</strong>. If it doesn’t, you’ll need to use Pax Construct to <em>wrap</em> the non-OSGi JAR obtained from the original source. Before we worry about wrapping JARs, we need to make a few changes to our Maven build file to locate the proper repositories.</p>
<ul style="clear: both;">
<li>Cut and paste (or use the pax-add-repository command) to add the following repositories to the <strong>pom.xml</strong> file in your main project folder:

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;repositories<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;repository<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>com.springsource.repository.bundles.external<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>SpringSource Enterprise Bundle Repository - External Bundle Releases<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://repository.springsource.com/maven/bundles/external<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/repository<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;repository<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>com.springsource.repository.bundles.release<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://repository.springsource.com/maven/bundles/release<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/repository<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;repository<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>spring-osgi<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://s3.amazonaws.com/maven.springframework.org/osgi<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/repository<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/repositories<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li>Execute the following four commands at the command line:

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pax-import-bundle <span style="color: #660033;">-g</span> org.apache.commons <span style="color: #660033;">-a</span> com.springsource.org.apache.commons.logging <span style="color: #660033;">-v</span> 1.1.1
pax-import-bundle <span style="color: #660033;">-g</span> org.springframework.osgi <span style="color: #660033;">-a</span> catalina.osgi <span style="color: #660033;">-v</span> 6.0.16-SNAPSHOT
pax-import-bundle <span style="color: #660033;">-g</span> org.springframework.osgi <span style="color: #660033;">-a</span> catalina.start.osgi <span style="color: #660033;">-v</span> 1.0.0
pax-import-bundle <span style="color: #660033;">-g</span> org.springframework.osgi <span style="color: #660033;">-a</span> servlet-api.osgi <span style="color: #660033;">-v</span> <span style="color: #000000;">2.5</span>-SNAPSHOT</pre></div></div>

</li>
<li>Now you should have a functioning Tomcat instance running in your OSGi container. To test:

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">mvn pax:provision</pre></div></div>

</li>
<li>Point a browser at http://localhost:8080 and you should get a blank page. If you do, you’re ready to move forward. <strong>The blank page is good.</strong> If you get anything other than a blank page, uh-oh! <strong>Game over?</strong> Not quite, inspect your console output.</li>
</ul>
<h3><strong>Step 4: Wicket up that container!</strong></h3>
<p style="clear: both;">If you take a look in the SpringSource OSGi repository, you’ll notice a version of Wicket exists. Unfortunately, it’s <strong>old</strong>. Real old. 1.3.3 to be exact. So the real question is how do you bundle the latest version of Wicket so it works properly in OSGi-land?</p>
<p style="clear: both;">We need to build our own OSGi-fied Wicket bundle, of course!</p>
<p style="clear: both;">We’ll use Pax Construct to help us get off on the right foot. <strong>pax-wrap-jar</strong> is a handy feature that allows us to <em>wrap</em> a regular JAR as an OSGi JAR by properly creating an OSGi manifest. Luckily, Pax Construct does this for us (or at the very least gets us off on the right foot).</p>
<ul style="clear: both;">
<li>Wrap the latest version of Wicket (which is 1.4.3 at the moment of this writing):

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pax-wrap-jar <span style="color: #660033;">-g</span> org.apache.wicket <span style="color: #660033;">-a</span> wicket <span style="color: #660033;">-v</span> 1.4.3</pre></div></div>

</li>
<li>We’ll need to make some changes though. The manifest that pax-wrap-jar creates is virtually empty and not quite what we’ll need for Wicket to properly work as a bundle. <strong>maven-bundle-plugin</strong> to the rescue! If you want to learn more <a href="http://wso2.org/library/tutorials/develop-osgi-bundles-using-maven-bundle-plugin" target="_blank">read this article</a>. Otherwise, let’s proceed to <em>wrapping a JAR</em>.</li>
</ul>
<h3><strong>Step 5: Wrapping a JAR</strong></h3>
<p style="clear: both;">Most of the time executing <strong>pax-wrap-jar</strong> is sufficient for getting a regular JAR ready to be dropped into your OSGi container. But I always like to understand the library I’m using, and most importantly figure out what packages it needs to import and export. It’s possible Wicket will work fine without the next steps, but I recommend doing this simply as a learning exercise.</p>
<p style="clear: both;">Instead of starting from scratch, we’ll take a look at the manifest in the <a href="http://www.springsource.com/repository/app/bundle/version/detail?name=com.springsource.org.apache.wicket&amp;version=1.3.3" target="_blank">OSGi-fied Wicket JAR at SpringSource</a>.<span style="text-decoration: underline;"><br />
</span></p>
<p style="clear: both;">The next three steps are optional. If you want to fast-track, skip them and proceed to editing your pom.xml.</p>
<ul style="clear: both;">
<li>Download the binary version and extract it.</li>
<li>Take a look at the manifest, it will give us a very good idea about what imports need to be done. Don’t worry about exports, because the maven-bundle-plugin will help us take care of that.</li>
<li>If you try copying the list of imports as-is, it will fail. So we’ll need to add sun.misc and sun.reflect to the imports. We’ll make these optional, because the sun.* packages are only available on Sun JDKs, and I like to keep things vendor agnostic whenever possible.</li>
</ul>
<p style="clear: both;">If you hack around on your own, you’ll probably wind up with a maven-build-plugin configuration like below. This will go inside the pom.xml created inside the wrapped JAR folder.</p>
<ul style="clear: both;">
<li>When you wrapped the jar, it created a new folder called org.apache.wicket in your OSGi project root. This folder contains a pom.xml file.</li>
<li>Copy the plugin config below to the pom.xml file:

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;build<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugins<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.felix<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>maven-bundle-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1.4.0<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;extensions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/extensions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;instructions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Bundle-SymbolicName<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${pom.groupId}.${pom.artifactId}
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Bundle-SymbolicName<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Bundle-Name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${pom.name}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Bundle-Name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Bundle-Version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${pom.version}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Bundle-Version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Bundle-ClassPath<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>.<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Bundle-ClassPath<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Import-Package<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>sun.misc;resolution:=optional,
            sun.reflect;resolution:=optional,
            javax.crypto,javax.crypto.spec,javax.imageio,
            javax.portlet;resolution:=optional,javax.servlet;version=&quot;[2.5.0,
            3.0.0)&quot;, javax.servlet.http;version=&quot;[2.5.0, 3.0.0)&quot;,
            javax.swing.event,javax.swing.text,javax.swing.tree,
            javax.xml.parsers,javax.xml.transform,javax.xml.transform.stream,
            junit.framework;version=&quot;[3.8.2, 4.0.0)&quot;;resolution:=optional,
            org.slf4j;version=&quot;[1.5.0, 2.0.0)&quot;,org.w3c.dom,org.xml.sax
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Import-Package<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/instructions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugins<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/build<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li>Try an <strong>mvn install</strong> from the wrapped JAR folder (org.apache.wicket). If everything goes smoothly, execute an mvn pax:provision from the project root folder. Ensure the bundle starts up successfully and the Wicket bundle is <em>active</em>.</li>
</ul>
<p style="clear: both;">We’ll need to resolve some runtime issues before going much further. If you fire up your OSGi container, it looks like slf4j is going to be an issue, so let’s add it. If you take a look at the import package instructions, it appears that Wicket depends on 1.5.0. Lucky, there’s an already OSGi-fied version at SpringSource.</p>
<ul style="clear: both;">
<li>Execute the following command:

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pax-import-bundle <span style="color: #660033;">-g</span> org.slf4j <span style="color: #660033;">-a</span> com.springsource.slf4j.jcl <span style="color: #660033;">-v</span> 1.5.0 <span style="color: #660033;">--</span> <span style="color: #660033;">-DimportTransitive</span> <span style="color: #660033;">-DwidenScope</span></pre></div></div>

</li>
<li><em>It’s very important that you don’t import two different slf4j bindings at the same time, otherwise you’ll receive a nasty StackOverflowError surprise. Check out <a href="http://www.slf4j.org/manual.html" target="_blank">the slf4j manual</a></em><em> for more info.</em></li>
<li>Now if you run mvn pax:provision, everything should start up nicely.</li>
<li>We also need to make sure Tomcat can handle JSP, as Wicket requires this. Execute the following two statements on the command line:

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pax-import-bundle <span style="color: #660033;">-g</span> org.springframework.osgi <span style="color: #660033;">-a</span> jasper.osgi <span style="color: #660033;">-v</span> 6.0.16-SNAPSHOT
pax-import-bundle <span style="color: #660033;">-g</span> org.mortbay.jetty <span style="color: #660033;">-a</span> jsp-api-<span style="color: #000000;">2.1</span> <span style="color: #660033;">-v</span> 6.1.14</pre></div></div>

</li>
</ul>
<h3><strong>Step 6: Install Spring DM</strong></h3>
<p style="clear: both;">If we just try to go ahead and fire up our webapp without Spring DM, nothing very exciting will happen. We need to install the Spring DM web extender; that’s where the real magic happens. To make a long story short, the Spring DM web extender checks for WAR bundles deployed to your OSGi container and automatically deploys them to embedded Tomcat or Jetty instance. It’s the glue that ties your WAR bundle to your JSP/Servlet container in the world of OSGi. An OSGi standard does exist so in the future containers will take care of this themselves, but for now, Apache Felix does not support this automatically. Just remember that it doesn’t matter if your app does not using the Spring framework, you still need Spring DM.</p>
<ul style="clear: both;">
<li>First, install the Spring DM Web Extender with the Maven switch to pull in all dependencies. We’ll also install the Spring Web bundle.

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pax-import-bundle <span style="color: #660033;">-g</span> org.springframework.osgi <span style="color: #660033;">-a</span> spring-osgi-web-extender <span style="color: #660033;">-v</span> 1.2.0 <span style="color: #660033;">--</span> <span style="color: #660033;">-DimportTransitive</span> <span style="color: #660033;">-DwidenScope</span>
pax-import-bundle <span style="color: #660033;">-g</span> javax.el <span style="color: #660033;">-a</span> com.springsource.javax.el <span style="color: #660033;">-v</span> 1.0.0
pax-import-bundle <span style="color: #660033;">-g</span> org.springframework <span style="color: #660033;">-a</span> org.springframework.web <span style="color: #660033;">-v</span> 2.5.6.A</pre></div></div>

</li>
</ul>
<h3><strong>Step 7: Creating our Hello World bundle!</strong></h3>
<p style="clear: both;">Now we’re going to create a new WAR bundle. We’ll create our Hello World OSGi bundle using Pax Construct. But we’ll need to modify the automatically generated Maven build settings in order to properly package our OSGi bundle as a WAR file instead of the default JAR file. Luckily, there is a Maven plugin available that makes this task fairly trivial.</p>
<ul style="clear: both;">
<li>Execute the following command to create a new Wicket Hello World project:

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pax-create-bundle <span style="color: #660033;">-p</span> osgilywicket.web <span style="color: #660033;">-n</span> wicket-helloworld.war <span style="color: #660033;">-g</span> org.itypeincaps <span style="color: #660033;">-v</span> <span style="color: #000000;">1.0</span>-SNAPSHOT</pre></div></div>

</li>
<li><em>Spring DM used to rely on the project name ending with .war in order for it to pick up and deploy it properly. You may be able to name it something else, but I can’t guarantee this will work. If anyone can verify if this is no longer the case, please leave a comment. <img src='http://kevinontheweb.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </em></li>
<li>Next we’ll make the necessary modifications for WAR packaging. The main thing to understand is how to package your bundle as a war file. <em>If you’d like more details about this, <a href="http://wiki.ops4j.org/display/ops4j/Getting+the+benefits+of+maven-bundle-plugin+in+other+project+types" target="_blank">check out this article</a></em><em>.</em></li>
<li>Add the following to the pom.xml file in the your Hello World bundle root folder:

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;build<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugins<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.felix<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>maven-bundle-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>bundle-manifest<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>process-classes<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>manifest<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;supportedProjectTypes<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;supportedProjectType<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>jar<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/supportedProjectType<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;supportedProjectType<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>bundle<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/supportedProjectType<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;supportedProjectType<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>war<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/supportedProjectType<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/supportedProjectTypes<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;instructions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Bundle-SymbolicName<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${bundle.symbolicName}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Bundle-SymbolicName<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Bundle-Version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${pom.version}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Bundle-Version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Export-Package<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${bundle.namespace}.*;version=&quot;${pom.version}&quot;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Export-Package<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;_include<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>-osgi.bnd<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/_include<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/instructions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>maven-war-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;archive<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;manifestFile<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${project.build.outputDirectory}/META-INF/MANIFEST.MF<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/manifestfile<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/archive<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugins<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/build<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li>Change the packaging type from <em>bundle</em> to <em>war</em> in pom.xml:

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;packaging<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>war<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/packaging<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li>Make Wicket available to the webapp by adding this to the pom.xml:

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.wicket<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>wicket<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1.4.3<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>provided<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li>Create the following web.xml under src/main/webapp/WEB-INF:

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;ISO-8859-1&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;web-app</span> <span style="color: #000066;">xsi:schemalocation</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/xml/ns/j2ee</span>
<span style="color: #009900;">    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd&quot;</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;2.4&quot;</span></span>
<span style="color: #009900;">    <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span>
<span style="color: #009900;">    <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/xml/ns/j2ee&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;display-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>HelloWorld<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/display-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;context-param<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>contextClass<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/param-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param-value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/param-value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/context-param<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;listener<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;listener-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.springframework.web.context.ContextLoaderListener<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/listener-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/listener<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>wicket.wicketTest<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.wicket.protocol.http.WicketFilter<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;init-param<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>applicationClassName<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/param-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param-value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.itypeincaps.osgilywicket.WicketApplication<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/param-value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/init-param<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>wicket.wicketTest<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/*<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/web-app<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li>Create the following applicationContext.xml under src/main/webapp/WEB-INF. For some reason I was having a hell of a time with XSD validation (more on this later), so I grabbed this from one of Matt Riable’s excellent demos as a sanity check just to make sure I wasn’t losing my mind. <img src='http://kevinontheweb.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;beans</span> <span style="color: #000066;">xsi:schemalocation</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans</span>
<span style="color: #009900;">    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd</span>
<span style="color: #009900;">    http://www.springframework.org/schema/osgi</span>
<span style="color: #009900;">    http://www.springframework.org/schema/osgi/spring-osgi.xsd&quot;</span> <span style="color: #000066;">xmlns:osgi</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/osgi&quot;</span> <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
    <span style="color: #808080; font-style: italic;">&lt;!--osgi:reference id=&quot;jobsBPS&quot;</span>
<span style="color: #808080; font-style: italic;">        interface=&quot;org.appfuse.bps.api.MyBPS&quot; timeout=&quot;10000&quot; cardinality=&quot;0..1&quot;/--&gt;</span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/beans<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li>Edit osgi.bnd to import all necessary packages. In order for our XML config files to pass XSD validation we need to make the factory package available:

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">Bundle-ClassPath: .,WEB-INF/classes
Import-Package: *,org.springframework.web.context,\
org.springframework.osgi.web.context.support,\
org.springframework.beans.factory.xml
Web-ContextPath: osgi</pre></div></div>

</li>
<li><em>Optional step.</em> Take note of <strong>line 4</strong> above. For those of us behind a proxy or without a connection to the internet, a strange anomaly exists with Spring that makes it impossible for the applicationContext schema to validate. This package may not be required for everyone, but I’m going to put it here for the heck of it. Plus, I really dislike the idea of relying out external resources simply to fire up my app, so this ensures we keep all validation dependencies local. Just keep in mind as you build your app, you should include the package names of your XSD files required by any Spring XML configuration files. If you don’t, your container will connect to the net during XSD validation, which may significantly increase the amount of time required during app startup. Keep in mind that for those of us behind a proxy, your OSGi container will need to be properly configured to support your proxy settings. For those using Apache Felix, take a look at <a href="http://felix.apache.org/site/apache-felix-usage-documentation.html" target="_blank">the Apache Felix usage documentation</a>.</li>
<li><em>Optional step.</em> As above, an error exists when trying to validate schemas with no web connection available. Those of us behind a proxy are the most likely to notice the problem. The workaround is to extract spring.handlers and spring.schemas and place them in the src/main/webapp/META-INF folder of your bundle. This is a particularly distasteful kludge, so hopefully the issue is resolved and this step is unnecessary by the time you’re reading this. <img src='http://kevinontheweb.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ul>
<p style="clear: both;">Now we need to create the standard Wicket stuff in order for our page to actually do anything. This step will seem fairly trivial compared to everything we’ve done so far. We’ll create three new files in the source folder of our project using the package name <em>org.itypeincaps.osgilywicket.</em> We’ll need our main Wicket application file (WicketApplication.java), and our component Java/HTML pair (Index.java and Index.html).</p>
<ul style="clear: both;">
<li>WicketApplication.java

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.itypeincaps.osgilywicket</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.Page</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.protocol.http.WebApplication</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> WicketApplication <span style="color: #000000; font-weight: bold;">extends</span> WebApplication <span style="color: #009900;">&#123;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> Class<span style="color: #339933;">&lt;?</span> <span style="color: #000000; font-weight: bold;">extends</span> Page<span style="color: #339933;">&gt;</span> getHomePage<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> Index.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</li>
<li>Index.java

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.itypeincaps.osgilywicket</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.WebPage</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.wicket.markup.html.basic.Label</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Index <span style="color: #000000; font-weight: bold;">extends</span> WebPage <span style="color: #009900;">&#123;</span>
    <span style="color: #008000; font-style: italic; font-weight: bold;">/**
     * Constructor
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> Index<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        add<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Label</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;message&quot;</span>, <span style="color: #0000ff;">&quot;Hello OSGi-land!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</li>
<li>Index.html

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;Wickety OSGi!&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;p wicket:id=&quot;message&quot;&gt;replace me&lt;/p&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre></div></div>

</li>
</ul>
<p style="clear: both;">The moment of truth has arrived. Execute an <strong>mvn install</strong> in your bundle folder, execute another <strong>mvn install</strong> in your OSGi (root) project folder, execute an <strong>mvn pax:provision</strong> to fire up your container, and see if it works. Fingers crossed!</p>
<h3><strong>Step 8: Fire it up!</strong></h3>
<p style="clear: both;">It looks like we’re finished! Go ahead and launch your OSGi container, open your browser, and point to http://localhost:8080/osgi. If you see Hello World!, that means our great success journey has come to a successful conclusion. If not, download the full working example, peer review at your convenience, and let me know if I forget a step somewhere along the way.</p>
<p style="clear: both;">I used TextMate as my editor when writing this tutorial. If you’d like to use Eclipse, execute the following command to create your project files. Then you can simply import your Hello World bundle as an existing project.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">mvn pax:eclipse <span style="color: #660033;">-DdownloadSources</span>=<span style="color: #c20cb9; font-weight: bold;">true</span> <span style="color: #660033;">-DdownloadJavadocs</span>=<span style="color: #c20cb9; font-weight: bold;">true</span></pre></div></div>

<h2><strong>Final thoughts on OSGi and Wicket</strong></h2>
<p style="clear: both;">If you made it this far, congratulations. <img src='http://kevinontheweb.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  You may also be wondering if this “stack” is ready for prime-time, enterprise, mission critical production applications. The short answer is <strong>no</strong>. The long answer is <em>not quite yet</em>.</p>
<p style="clear: both;">OSGi does a number of things amazingly. I won’t go into the benefits of OSGi, because I assume if you got this far you already know what they are. :p The problem isn’t with OSGi as a technology, the problem is with the adoption rate of vendors. If the big commercial app server vendors — mainly IBM and Oracle (BEA) — would provide world-class OSGi support in their products for developers, I think a lot of us would jump <strong>all over</strong> OSGi. As you may have figured out from this tutorial, putting together a functional OSGi stack with your favourite UI framework is a bit of a hassle. And we’ve only tackled a development stack. Putting something like this into production would be a disaster without some major securing and planning for load + availability. The other option of embedding OSGi <strong>inside</strong> your webapp (which is the complete opposite of what we did here) is also simply too kludge-y for most organizations to greenlight.</p>
<p style="clear: both;">With all of that being said, I wouldn’t hesitate to use a Wicket/Spring/OSGi stack for complex internal applications. (For trivial internal applications, OSGi is overkill; use PHP or RoR or Grails or&#8230; something else!)</p>
<p style="clear: both;">Moving into 2010, <em>dynamic Java </em>is going to play a major role in new enterprise development. Even though we have to do a lot more work than we should to get our environment ready, the benefits of OSGi are enormous, and the configuration tedium will slowly die down as tooling and server support become more mature.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/36/wicket-osgi-and-spring-dm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Don&#039;t forget team structure</title>
		<link>http://kevinontheweb.com/posts/35/dont-forget-team-structure-2</link>
		<comments>http://kevinontheweb.com/posts/35/dont-forget-team-structure-2#comments</comments>
		<pubDate>Fri, 23 Oct 2009 14:52:00 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[SOA]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/posts/15/dont-forget-team-structure</guid>
		<description><![CDATA[In the summer I blogged about SOA, and wondered out loud if true SOA was impossible to implement in some organizations due to the organizational structure itself.
Janie Chang at Microsoft Research wrote an excellent article recently that touched on the same subject. (A Mac-owning Java developer reading a Microsoft Research blog? Seriously!)


To quote Janie, &#8220;the [...]]]></description>
			<content:encoded><![CDATA[<p>In the summer I blogged about SOA, and wondered out loud if true SOA was impossible to implement in some organizations due to the organizational structure itself.</p>
<p>Janie Chang at Microsoft Research <a href="http://research.microsoft.com/en-us/news/features/nagappan-100609.aspx">wrote an excellent article</a> recently that touched on the same subject. <em>(A Mac-owning Java developer reading a Microsoft Research blog? Seriously!)<br />
</em></p>
<p><span id="more-35"></span></p>
<p>To quote Janie, <em>&#8220;the system will resemble the organization building the system&#8221;</em>. I agree with this assertion completely. Team culture and structure can vary widely even within the same organization. Over the past ten years I&#8217;ve worked in a variety of teams, some that were incredibly flexible and passionate (a strong focus on best practices, evolving processes, geographically distributed workforce, engaged developers), and others that are quite reluctant &#8212; or unable &#8212; to change (Waterfall to the core, local workforce, no telecommuting or flex-hours, rigid processes owned at a high-level of the organization, disengaged developers). In my experience I&#8217;ve always noticed that flexible and adaptable organizations produce flexible and adaptable applications. Rigid and inflexible organizations tend to produce rigid and inflexible applications. Co-incidence?</p>
<p>Another interesting observation Janie made is how the geographical distance of team members affects software quality.</p>
<p>I&#8217;ve worked in teams that have varying opinions on this. One team in particular stressed telecommuting as the norm; if you didn&#8217;t have a face-to-face meeting, you were encouraged to work wherever you felt you&#8217;d be the most productive that day. For me, telecommuting isn&#8217;t that big of a deal; I live and work downtown, so I usually walk to work. But rolling out telecommuting had a noticeable, positive impact on my co-workers. They seemed much less stressed and much more engaged. As one put it, <em>&#8220;I could spend three hours in the car, or an extra hour coding and two extra hours with my kids&#8221;</em>. My own experience in this team was extraordinarily positive. Instead of measuring success by the number of hours spent at a desk, the team measured success by <strong>results</strong>. Communication was a highly-valued skill and team members tended to communicate heavily &#8212; via Skype, instant messaging, and the regular old telephone. Actually, the team tended to communicate with each other more when they were out of the office than when they were in the office. I still can&#8217;t explain this one, but Janie mentioned the same phenomenon, <em>&#8220;Most people preferred to talk to someone from <strong>their own</strong> organization 4,000 miles away rather than someone only five doors down the hall but from a <strong>different</strong> organization. <strong>Organizational cohesiveness</strong> played a bigger role than geographical distance.&#8221;</em> The days that everyone spent together at the office together simply re-enforced the overall cohesiveness of the team.</p>
<p>On the flip side, I&#8217;ve worked in a team where the motto was, <em>&#8220;If your job could be done from home, your job could be done from India&#8221;</em>. Needless to say the organizational structure was rigid, and so were the applications they produced; not necessarily the fault of the developers, they were just completely disengaged due to an old-school mentality towards software development. It&#8217;s essentially the difference between an industrial age management style versus an information age management style. Time versus results.</p>
<p>This leads me to believe that while the technology itself is a critical aspect of a project, organizations that fail to innovate structurally and culturally as well as technically are failing to see the big picture.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/35/dont-forget-team-structure-2/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Is the SOA hype doomed?</title>
		<link>http://kevinontheweb.com/posts/34/is-the-soa-hype-doomed</link>
		<comments>http://kevinontheweb.com/posts/34/is-the-soa-hype-doomed#comments</comments>
		<pubDate>Mon, 10 Aug 2009 05:27:00 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[SOA]]></category>
		<category><![CDATA[architecture]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/posts/14/is-the-soa-hype-doomed</guid>
		<description><![CDATA[Don&#8217;t get me wrong, I think the spirit of SOA is fantastic. Adaptable, flexible, maintainable, loosely-coupled applications supported by open governance, strong relationships between business and technology folks, and co-operation across all silos and levels of an organization. What&#8217;s not to love?
SOA has become one of the most commonly-heard buzzwords around the water-cooler over the [...]]]></description>
			<content:encoded><![CDATA[<p>Don&#8217;t get me wrong, I think the <em>spirit</em> of SOA is fantastic. Adaptable, flexible, maintainable, loosely-coupled applications supported by open governance, strong relationships between business and technology folks, and co-operation across all silos and levels of an organization. What&#8217;s not to love?</p>
<p>SOA has become one of the most commonly-heard buzzwords around the water-cooler over the past few years. It seems like everyone is talking about SOA these days. Architects, developers, business folks, management, non-management, and everyone in-between. I hear about SOA more than I hear about AJAX and Web 2.0 put together. I wouldn&#8217;t be surprised if my Dad calls me up out of the blue to chat about SOA &#8212; and he sells shopping carts; the real ones made of metal, not the e-ones!</p>
<p><span id="more-34"></span></p>
<p>I love nothing more than applying an elegant solution to a difficult problem, but I&#8217;m concerned when a misunderstood solution is applied to an unknown problem.</p>
<p>At the root of SOA are some extremely useful technologies. An average SOA stack includes: services, a service registry, some form of orchestration, data transportation and transformation (whether done with an ESB or not), persistence, authentication and authorization, administration, event notification, business intelligence, and governance.</p>
<p>You may disagree with my above list. &#8220;<em>Are you kidding, ESB <strong>is</strong> <span style="font-style: normal;"><em>SOA! Why didn&#8217;t you mention Quality of Service? Are you sure you mean orchestration, or do you mean choreography?&#8221;</em> Those are potentially valid points. The thing is, I&#8217;m not really all that concerned about what <strong>true</strong> SOA <strong>should</strong> be, but whether or not SOA, pieces of SOA, or something entirely different is the most appropriate technical solution to a business opportunity.</span></em></p>
<p>I&#8217;m by no means an SOA expert. I&#8217;ve been involved in a number of WS initiatives, and one project with the SOA label applied to it. I also spent a month attending training sessions provided by <a href="http://www.softwareag.com/corporate/default.asp">Software AG</a> on their <a href="http://www.softwareag.com/corporate/products/wm/default.asp">webMethods</a> product. Recently I&#8217;ve attended a number of strategy sessions to come up with an SOA migration path for our department.</p>
<p>To me, this is what SOA is not: a silver bullet, an easy way to pay off years of accumulated technical debt, the answer to all your prayers, a way to double your business in 24 hours, a way to get rich quick, the magic diet that will help you lose weight but still allow you to eat as much pie as you want, something you <strong>have</strong> to deliver. Yet, when I speak to friends and colleagues about SOA, this is how it&#8217;s being communicated. Interestingly enough, in some cases it&#8217;s being pushed by business rather than the technical staff. At first glance this may sound reasonable; after all, it&#8217;s a good thing for a business case to exist when spending millions of dollars. But the scary thing is the <em>way</em> it&#8217;s being marketed. &#8220;Company X just unveiled their SOA solution, we need one to stay competitive&#8230;&#8221;</p>
<p>If you take a look at the technology stack I listed above, none of the concepts or technologies are particularly complex or difficult. But wiring them together to accomplish a specific business objective is complicated, especially when crossing organizational boundaries. From my (albeit limited) SOA experience, the most difficult aspect of an SOA project is governance, and one that I&#8217;m shocked to see so overlooked.</p>
<p>Is true SOA simply too ambitious for most companies to deliver? Is it a clash of paradigms? Most organizations undertaking SOA initiatives are, at their heart, stove-piped; siloed departments with siloed applications and processes. Can an architecture whose goal is to promote rapid adaptation to changing business conditions and flexibility work in an organization whose entire structure is reluctant to adapt and inflexible by nature? These are questions I can&#8217;t answer, but questions I&#8217;m surprised more people aren&#8217;t asking.</p>
<p>My opinion is this: unless the stakeholders of an SOA initiative can provide clear and reasonable ROI estimates at specific milestones of an SOA migration, the project is most likely doomed to failure. If I bought a bus ticket and the destination read &#8220;You&#8217;ll know when you get there&#8221;, I&#8217;d ask for a refund.</p>
<p>Unfortunately, SOA itself will be blamed for the failure of SOA initiatives. Until the SOA buzzword became so hot, I&#8217;d never heard of a project funded without specific business objectives: reduce support costs; prepare for increased usage; provide a new business feature that would generate X number of new customers; generate X amount of new revenue per customer, and so forth. On the flip side, I&#8217;ve chatted with a number of friends who are involved in SOA projects, and most of them can&#8217;t figure out what the actual, concrete, measurable goals of their SOA initiatives are.</p>
<p>I think SOA will become a bad word sooner or later. Next time someone mentions SOA, focus less on the acronym and more on the spirit of what you&#8217;re trying to accomplish. Paying attention to the latest and greatest buzz is important, but just be careful not to commit &#8220;design by buzzword&#8221;.</p>
<p>Oh, and if you think an ESB is going to solve all your problems, I&#8217;ve got some magic beans to sell you. <img src='http://kevinontheweb.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/34/is-the-soa-hype-doomed/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Free OSGi book!</title>
		<link>http://kevinontheweb.com/posts/33/free-osgi-book</link>
		<comments>http://kevinontheweb.com/posts/33/free-osgi-book#comments</comments>
		<pubDate>Thu, 16 Jul 2009 05:48:00 +0000</pubDate>
		<dc:creator>Kevin Webber</dc:creator>
				<category><![CDATA[OSGi]]></category>

		<guid isPermaLink="false">http://kevinontheweb.com/posts/13/free-osgi-book</guid>
		<description><![CDATA[I recently came across a free book on OSGi the other day:
http://neilbartlett.name/blog/osgibook/
I&#8217;m about half-way through so far, a fantastic read. It&#8217;s great to see self-published books like this. Maybe one day I&#8217;ll move to a log cabin and work on my own masterpiece.  
]]></description>
			<content:encoded><![CDATA[<p>I recently came across a free book on OSGi the other day:</p>
<p><a href="http://neilbartlett.name/blog/osgibook/">http://neilbartlett.name/blog/osgibook/</a></p>
<p>I&#8217;m about half-way through so far, a fantastic read. It&#8217;s great to see self-published books like this. Maybe one day I&#8217;ll move to a log cabin and work on my own masterpiece. <img src='http://kevinontheweb.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://kevinontheweb.com/posts/33/free-osgi-book/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
