<?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>Rob's world!</title>
	<atom:link href="http://tigrou.nl/feed/" rel="self" type="application/rss+xml" />
	<link>http://tigrou.nl</link>
	<description>Sofware engineering, music and general stuff</description>
	<lastBuildDate>Fri, 01 Jul 2011 15:56:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.4</generator>
		<item>
		<title>Simple Google Maps routeplanner</title>
		<link>http://tigrou.nl/2011/07/01/simple-google-maps-routeplanner/</link>
		<comments>http://tigrou.nl/2011/07/01/simple-google-maps-routeplanner/#comments</comments>
		<pubDate>Fri, 01 Jul 2011 15:56:36 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[maps]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=256</guid>
		<description><![CDATA[Last week I was googling for a simple implementation of a routeplanner based on Google maps. Weirdly enough I didn&#8217;t find a total solution or older ones based on the maps v2 API. So I decided to have a look at the API and In 15 minutes I had a working routeplanner. Which might explain [...]]]></description>
			<content:encoded><![CDATA[<p>Last week I was googling for a simple implementation of a routeplanner based on Google maps. Weirdly enough I didn&#8217;t find a total solution or older ones based on the maps v2 API. So I decided to have a look at the API and In 15 minutes I had a working routeplanner. Which might explain why I found that less examples on the internet <img src='http://tigrou.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . But for all other people who need a quick solution, I thought sharing would be good.</p>
<p>It&#8217;s a very plain example based on the Google Maps v3 and a bit of jQuery but that can easily be avoided.</p>
<p>First the necessary html:</p>
<pre class="brush: xml; title: ; notranslate">

&lt;script type=&quot;text/javascript&quot; src=&quot;http://maps.google.com/maps/api/js?sensor=true&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;

&lt;style&gt;
  #map_canvas {
    height:500px;
    width:600px;
 }
 #directions {
   width:600px;
 }
&lt;/style&gt;

&lt;div id=&quot;map_canvas&quot;&gt;&lt;/div&gt;
&lt;h2&gt;Plan your trip&lt;/h2&gt;
&lt;form id=&quot;routeform&quot;&gt;
  City or zipcode:
  &lt;input type=&quot;text&quot; name=&quot;routefrom&quot; id=&quot;routefrom&quot;/&gt;
  &lt;input type=&quot;submit&quot; value=&quot;calculate&quot;/&gt;
&lt;/form&gt;
&lt;div id=&quot;directions&quot;&gt;&lt;/div&gt;
</pre>
<p>And the Javascript:</p>
<pre class="brush: jscript; title: ; notranslate">
$(document).ready(function()
{
  initialize();

  $('#routeform').submit(function(e)
  {
    calcRoute();
    return false;
  });

});

var directionDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
var home = new google.maps.LatLng(52.0951, 5.109);

function initialize()
{
  directionsDisplay = new google.maps.DirectionsRenderer();

  var myOptions =
  {
    zoom:8,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    center: home
  }
  map = new google.maps.Map(document.getElementById(&quot;map_canvas&quot;), myOptions);
  directionsDisplay.setMap(map);
  directionsDisplay.setPanel(document.getElementById(&quot;directions&quot;));

  var myLatLng = new google.maps.LatLng(52.0951, 5.109);
  var beachMarker = new google.maps.Marker
  ({
      position: myLatLng,
      map: map
  });
}

function calcRoute()
{
  var start = document.getElementById(&quot;routefrom&quot;).value;

  var request =
  {
    origin:start,
    destination:home,
    travelMode: google.maps.DirectionsTravelMode.DRIVING
  };
  directionsService.route(request, function(response, status)
  {
    if (status == google.maps.DirectionsStatus.OK)
    {
      directionsDisplay.setDirections(response);
    }
  });
}
</pre>
<p>Which results in:</p>
<style>
#map_canvas {
    height:500px;
    width:600px;
}
 #directions {
    width:600px;
}
</style>
<p><script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script><br />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script></p>
<p><script type="text/javascript"> 
$(document).ready(function(){initialize();$('#routeform').submit(function(e)
{calcRoute();return false;});});var directionDisplay;var directionsService=new google.maps.DirectionsService();var map;var home=new google.maps.LatLng(52.0951,5.109);function initialize()
{directionsDisplay=new google.maps.DirectionsRenderer();var myOptions={zoom:8,mapTypeId:google.maps.MapTypeId.ROADMAP,center:home}
map=new google.maps.Map(document.getElementById("map_canvas"),myOptions);directionsDisplay.setMap(map);directionsDisplay.setPanel(document.getElementById("directions"));var myLatLng=new google.maps.LatLng(52.0951,5.109);var beachMarker=new google.maps.Marker
({position:myLatLng,map:map});}
function calcRoute()
{var start=document.getElementById("routefrom").value;var request={origin:start,destination:home,travelMode:google.maps.DirectionsTravelMode.DRIVING};directionsService.route(request,function(response,status)
{if(status==google.maps.DirectionsStatus.OK)
{directionsDisplay.setDirections(response);}});}
</script><br />
<br/></p>
<div id="map_canvas"></div>
<p><br/><br/></p>
<h2>Plan your trip</h2>
<form id="routeform">
  City or zipcode:</p>
<input type="text" name="routefrom" id="routefrom"/>
<input type="submit" value="calculate"/>
</form>
<p><br/><br/></p>
<div id="directions"></div>
<p><br/><br/></p>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2011/07/01/simple-google-maps-routeplanner/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cached credentials in http basic authentication</title>
		<link>http://tigrou.nl/2011/06/11/cached-credentials-in-http-basic-authentication/</link>
		<comments>http://tigrou.nl/2011/06/11/cached-credentials-in-http-basic-authentication/#comments</comments>
		<pubDate>Sat, 11 Jun 2011 09:50:34 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[LinkedIn]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=249</guid>
		<description><![CDATA[After some radio silence, it&#8217;s time for a short post. Being busy with Duchenne Heroes last year and some weeks of snowboarding I&#8217;m posting a new blog about Java&#8217;s AuthCache to avoid breaking other people&#8217;s head as it broke mine. Two weeks ago I was working on a connection with a common webservice which authentication [...]]]></description>
			<content:encoded><![CDATA[<p>After some radio silence, it&#8217;s time for a short post. Being busy with <a href="http://www.duchenneheroes.nl" target="_blank">Duchenne Heroes</a> last year and some weeks of snowboarding I&#8217;m posting a new blog about Java&#8217;s AuthCache to avoid breaking other people&#8217;s head as it broke mine.</p>
<p>Two weeks ago I was working on a connection with a common webservice which authentication was based on plain http basic authentication. I used <a href="http://cxf.apache.org/" target="_blank">CXF</a> as a client library to handle the plumbing for me, the basic code looked like this:</p>
<pre class="brush: java; title: ; notranslate">
JaxWsProxyFactoryBean clientFactory = new JaxWsProxyFactoryBean();
clientFactory.setAddress(&quot;http://webservice.url.com&quot;);
clientFactory.setServiceClass(MyLocalInterface.class);
clientFactory.setUsername(&quot;rob&quot;);
clientFactory.setPassword(&quot;secret&quot;);
fundaSoap = clientFactory.create(MyLocalInterface.class);
</pre>
<p>From the start this worked great and simple, till the moment that I set up another connection based on the same url but other credentials&#8230;&#8230; That&#8217;s where the problem began. Connection nr 2 was now messed up with the credentials of connection nr 1 and as I never heard of this behavior, I refused to believe it either. But after diving into server logs, I couldn&#8217;t deny it anymore. My client code was screwed up. After some googling I found the problem, the JDK is caching credentials based on the url and port of your http request. And resetting that cache by calling the Authenticator class doesn&#8217;t help you due to this bug:</p>
<p><a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6626700" target="_blank">http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6626700</a></p>
<p>So there&#8217;s just one way to avoid this bug and that&#8217;s fooling the JDK that you&#8217;ve used the credentials before:</p>
<pre class="brush: java; title: ; notranslate">
AuthCacheValue.setAuthCache(new AuthCache()
{
  @Override
  public void remove(String arg0, AuthCacheValue arg1) { }

  @Override
  public void put(String arg0, AuthCacheValue arg1) { }

  @Override
  public AuthCacheValue get(String arg0, String arg1)
  {
    return null;
  }
});
</pre>
<p>I hope my post will help other people with the same kind of issues as this took me some time to figure out what was happening and I don&#8217;t want that somebody else spoils his or her time on this.</p>
<p>Apart from this post, I&#8217;m really happy with the CXF library (based on the old XFire project) and I&#8217;ll try to publish more on that later.</p>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2011/06/11/cached-credentials-in-http-basic-authentication/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Finally did my SCJP6 exam!</title>
		<link>http://tigrou.nl/2010/05/11/finally-did-my-scjp6-exam/</link>
		<comments>http://tigrou.nl/2010/05/11/finally-did-my-scjp6-exam/#comments</comments>
		<pubDate>Tue, 11 May 2010 17:42:34 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[LinkedIn]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=243</guid>
		<description><![CDATA[Long time no blog, the explanation is here. After three years of having the good intention, I finally motivated myself to take the SCJP exam. From the moment I started working after my study, I told myself many times that I should for some Java certification. Just to prove that I understand what I&#8217;m doing. [...]]]></description>
			<content:encoded><![CDATA[<p>Long time no blog, the explanation is here.</p>
<p>After three years of having the good intention, I finally motivated myself to take the SCJP exam. From the moment I started working after my study, I told myself many times that I should for some Java certification. Just to prove that I understand what I&#8217;m doing. So I started reading in the SCJP 5 study guide (the Sierra and Bates book), and started several times&#8230;..</p>
<p>A lot of information was pretty interesting but on the other hand I couldn&#8217;t really motivate myself to learn on exotic facts which I never use in practice. Due that fact, I quit learning on SCJP5. Last year I finally picked it up again by buying the Java 6 version of the Sierra and Bates book. Again fighting with the same contradicting facts of useful and useless knowledge but now determined to finish it!</p>
<p>I&#8217;ll give a short summary of how I studied. Started with reading the book and making notes for every chapter. After each chapter, I made the test questions and reviewed them. I added the best practices to the notes and learned from my mistakes which were for 50% just silly and stupid ones. After finishing the book, I never opened it again. From that moment I started practicing by just writing several small test applications to get a feeling with several subjects. And doing different mock tests. I would like to mention and recommend the <a href="http://examlab.tk/" target="_blank">examlab software</a> from Devaka Cooray, it&#8217;s free and is really approaching the real exam.</p>
<p>So that&#8217;s it for now. I&#8217;m currently working on bookmarkeable ajax urls and back button support for ajax urls in php based on CodeIgniter and JQuery. I&#8217;ll definitely post my solution here once it&#8217;s a bit finished. And not unimportant, I&#8217;m about to leave for a trip to India (for work), maybe I&#8217;ll write something about that as well.</p>
<p>Oh but now the most important, the result of my exam:</p>
<h2><span style="color: #99cc00;"><span style="color: #37e31b;"><strong>PASSED with a 85% score!!!</strong></span><br />
</span></h2>
<p>What&#8217;s next:</p>
<ul>
<li>Training and collecting for <a href="http://tigrou.nl/2009/11/12/duchenne-heroes-2010/" target="_self">our goal</a> this year</li>
<li>Then thinking about another certification</li>
<li>Drinking a beer to celebrate my score <img src='http://tigrou.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ul>
<p>Tips:</p>
<ul>
<li>Be very secure!! Most of my mistakes were not noticing minor, non-head braking things.</li>
<li>Read a good book, make notes, re-read those notes several times</li>
<li>Practice as much as you can on mock tests (for example examlab.tk)</li>
<li>Visit the Javaranch SCJP forum, contains a lot of useful information</li>
<li>Have fun!</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2010/05/11/finally-did-my-scjp6-exam/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Filtering your duplicate feedbackmessages in Wicket</title>
		<link>http://tigrou.nl/2010/02/06/filtering-your-duplicate-feedbackmessages-in-wicket/</link>
		<comments>http://tigrou.nl/2010/02/06/filtering-your-duplicate-feedbackmessages-in-wicket/#comments</comments>
		<pubDate>Sat, 06 Feb 2010 10:11:00 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[wicket]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=235</guid>
		<description><![CDATA[Last week I noticed that in some of my webapps written in Wicket, messages appear multiple times in a FeedbackPanel (Wicket component). That happens since multiple parts of the same page do different kind of validation which might occur in the same error/warning messages. Not a big problem but duplicate messages look a bit weird [...]]]></description>
			<content:encoded><![CDATA[<p>Last week I noticed that in some of my webapps written in Wicket, messages appear multiple times in a FeedbackPanel (Wicket component). That happens since multiple parts of the same page do different kind of validation which might occur in the same error/warning messages. Not a big problem but duplicate messages look a bit weird to your visitor. It&#8217;s easy to fix and probably no rocket science to you but I post it anyway <img src='http://tigrou.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>The solution contains two parts, a custom FeedbackPanel and an implementation of the IFeedbackMessageFilter.</p>
<p>Custom FeedbackPanel:</p>
<pre class="brush: java; title: ; notranslate">
private class UniqueMessagesFeedbackPanel extends FeedbackPanel
  {
    private UniqueMessageFilter filter = new UniqueMessageFilter();

    @Override
    protected void onBeforeRender()
    {
      super.onBeforeRender();
      // clear old messages
      filter.clearMessages();
    }

    public UniqueMessagesFeedbackPanel(String id)
    {
      super(id);
      setFilter(filter);
    }
  }
</pre>
<p>And the filter class:</pre>
<pre class="brush: java; title: ; notranslate">
public class UniqueMessageFilter implements IFeedbackMessageFilter
  {
    List&lt;FeedbackMessage&gt; messages = new ArrayList&lt;FeedbackMessage&gt;();

    public void clearMessages()
    {
      messages.clear();
    }

    @Override
    public boolean accept(FeedbackMessage currentMessage)
    {
      // too bad that FeedbackMessage doesnt have an equals implementation
      for(FeedbackMessage message: messages)
        if(message.getMessage().toString().equals(currentMessage.getMessage().toString()))
          return false;
      messages.add(currentMessage);
      return true;
    }
  }
</pre>
<p>I'm looking for a a more beautiful way to cleanup the messages but it seems impossible since the FeedbackMessage class does not implement an own equals version. And if it was implemented, it propably checks on too much properties, like the component which throws the message and that still results in duplicate messages.</pre>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2010/02/06/filtering-your-duplicate-feedbackmessages-in-wicket/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Context based urls with Apache Wicket</title>
		<link>http://tigrou.nl/2010/01/02/context-based-urls-with-apache-wicket/</link>
		<comments>http://tigrou.nl/2010/01/02/context-based-urls-with-apache-wicket/#comments</comments>
		<pubDate>Sat, 02 Jan 2010 15:47:07 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[wicket]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=225</guid>
		<description><![CDATA[It&#8217;s been a while that I wrote something technical on my blog. The last ones were mainly about biking which is taking a lot of my spare time these days. I haven&#8217;t blogged about Wicket before but that doesn&#8217;t mean that I use it a lot. For the last 2 years, I&#8217;m using it at [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been a while that I wrote something technical on my blog. The last ones were mainly about biking which is taking a lot of my spare time these days. I haven&#8217;t blogged about Wicket before but that doesn&#8217;t mean that I use it a lot. For the last 2 years, I&#8217;m using it at my work at <a href="http://www.maxxton.com" target="_blank">Maxxton</a> for developing rich content websites. In one of the usecases a month ago, we needed something for storing parameters in the urls which would never get lost after clicking around. After a little googling on the web, I found an example on the <a href="http://cwiki.apache.org/WICKET/wicket-and-localized-urls.html" target="_blank">Wicket wiki </a>which allowed you to add the locale in the url. I&#8217;ve re-used that example and made it a bit more generic by allowing key-value pairs instead of one hardcoded string.</p>
<p>The used keys are defined by a simple enum:</p>
<pre class="brush: java; title: ; notranslate">

private enum Param {
LANGUAGE(&quot;lan&quot;), THEME(&quot;theme&quot;);

private final String value;

Param(String value) {
this.value = value;
}

public String getValue() {
return value;
}
};
</pre>
<p>
In this example I used two different params which can be used in combination with eachother or separated. I won&#8217;t add all the Java code in long listings over here because of the amount of code but you can download my Eclipse project at the end of this blogpost.
</p>
<p>
There are actually two important spots, a custom RequestCodingStrategy and the registration of that class in the WebApplication. But before I show that code, let&#8217;s give some examples of the urls which will be created/working:</p>
<ul>
<li>http://localhost:8080/urlexample<strong>/theme/red/lan/nl</strong>/home</li>
<li>http://localhost:8080/urlexample<strong>/lan/nl</strong>/home</li>
<li>http://localhost:8080/urlexample<strong>/theme/red/</strong>home</li>
<li>http://localhost:8080/urlexample<strong>/</strong>home</li>
</ul>
<p>All of these urls are pointing to the homepage mounted at &#8220;home&#8221;. The bold parts are the key-value pairs which are read in our RequestCodingStrategy and stored in the session for later use. The beauty of this solution is that every generated url, will still contain these values. So in my example, I created a link to another page called &#8220;end&#8221; and that url will be something like http://localhost:8080/urlexample<strong>/theme/red/lan/nl</strong>/end.
</p>
<p>
So how does that look like, lets start with the 2 overridden methods in my WebApplication:
</p>
<pre class="brush: java; title: ; notranslate">

@Override
protected IRequestCycleProcessor newRequestCycleProcessor() {
return new WebRequestCycleProcessor() {
@Override
protected IRequestCodingStrategy newRequestCodingStrategy() {
return new ParamUrlCodingStrategy(super
.newRequestCodingStrategy());
}
};
}

@Override
public Session newSession(Request request, Response response) {
return new CustomSession(request);
}
</pre>
<p>
The newRequestCycleProcessor() returns the custom RequestCodingStrategy instead of the default one. and the newSession() returns our custom session for storing the values. Nothing special.
</p>
<p>
Lets take a look now to our custom RequestCodingStrategy where most of the magics happens. I only show a stripped version of the one in the example project:
</p>
<pre class="brush: java; title: ; notranslate">

public class ParamUrlCodingStrategy extends RequestCodingStrategy {

public ParamUrlCodingStrategy(final IRequestCodingStrategy defaultStrategy) {
super(defaultStrategy);
}

@Override
public RequestParameters decode(final Request request) {
final String requestLanguage = getParamValue(request.getPath(),
Param.LANGUAGE);
final String requestTheme = getParamValue(request.getPath(),
Param.THEME);

// for example, use a custom session object to store your values
if (requestLanguage != null) {
((CustomSession) Session.get()).setLanguage(requestLanguage);
}
if (requestTheme != null) {
((CustomSession) Session.get()).setTheme(requestTheme);
}

String url = request.decodeURL(request.getURL());

// remove params from request
for (Param param : Param.values()) {
url = stripParamFromPath(url, param);
}
final String urlWithoutParams = url;

// use decorator for decoding
return getDecoratedStrategy().decode(new RequestDecorator(request) {
@Override
public String getURL() {
return urlWithoutParams;
}

@Override
public String getPath() {
return urlWithoutParams;
}
});
}

@Override
public CharSequence encode(final RequestCycle requestCycle,
final IRequestTarget requestTarget) {
String url = getDecoratedStrategy().encode(requestCycle, requestTarget)
.toString();

// rewrite only requests for pages &amp;amp;amp; links
if (requestTarget instanceof IBookmarkablePageRequestTarget
|| requestTarget instanceof IPageRequestTarget) {

String theme = ((CustomSession) Session.get()).getTheme();
String language = ((CustomSession) Session.get()).getLanguage();

// language
if (language != null &amp;amp;amp;&amp;amp;amp; !language.isEmpty()) {
if (url.startsWith(&quot;../&quot;)) {
final int lastIndex = url.lastIndexOf(&quot;../&quot;) + 3;
final String remainingUrl = url.substring(lastIndex);
if (!remainingUrl.isEmpty()) {
url = url.substring(0, lastIndex)
+ Param.LANGUAGE.getValue() + &quot;/&quot; + language
+ &quot;/&quot; + remainingUrl;
}
}
// if starts with . -&amp;gt; skip
else if (!url.startsWith(&quot;.&quot;)) {
url = Param.LANGUAGE.getValue() + &quot;/&quot; + language + &quot;/&quot;
+ url;
}
}
// and theme
if (theme != null &amp;amp;amp;&amp;amp;amp; !theme.isEmpty()) {
if (url.startsWith(&quot;../&quot;)) {
final int lastIndex = url.lastIndexOf(&quot;../&quot;) + 3;
final String remainingUrl = url.substring(lastIndex);
if (!remainingUrl.isEmpty()) {
url = url.substring(0, lastIndex)
+ Param.THEME.getValue() + &quot;/&quot; + theme + &quot;/&quot;
+ remainingUrl;
}
}
// if starts with . -&amp;gt; skip
else if (!url.startsWith(&quot;.&quot;)) {
url = Param.THEME.getValue() + &quot;/&quot; + theme + &quot;/&quot; + url;
}
}
return url;
}
return url;
}

private String getParamValue(final String path, Param param) {
int index = path.indexOf(param.getValue());
if (index &amp;gt;= 0) {
int indexOfNextSlash = path.indexOf(&quot;/&quot;, index
+ param.getValue().length() + 1);
String paramValue = path.substring(index
+ param.getValue().length() + 1, indexOfNextSlash);
return paramValue;
}
return null;
}

private String stripParamFromPath(final String path, Param param) {
String paramValue = getParamValue(path, param);

return path.replace(param.getValue() + &quot;/&quot; + paramValue + &quot;/&quot;, &quot;&quot;);
}

@Override
public IRequestTarget targetForRequest(
final RequestParameters requestParameters) {
// delegate call to decorated codingStrategy, but with params removed
String newPath = requestParameters.getPath();
for (Param param : Param.values()) {
newPath = stripParamFromPath(newPath, param);
}

requestParameters.setPath(newPath);
return super.targetForRequest(requestParameters);
}

@Override
public IRequestTargetUrlCodingStrategy urlCodingStrategyForPath(
final String path) {
String newPath = path;
for (Param param : Param.values()) {
newPath = stripParamFromPath(newPath, param);
}

if (newPath != null &amp;amp;amp;&amp;amp;amp; !newPath.isEmpty()) {
// treat this kind of situation by returning some not null
// codingStrategy,
// to let this kind of request treated by wicket
return new PassThroughUrlCodingStrategy(newPath);
}
return super.urlCodingStrategyForPath(newPath);
}

}
</pre>
<p>
As you can see, the encode() and decode() methods do most of the processing. It&#8217;s actually nothing more then adding and removing/reading the parameters. The reason that I liked it, is that it&#8217;s always executed, no matter what code is used inside the pages. That&#8217;s a secure way of adding parameters and not loosing them and as a little dessert, Google likes them as well! Urls are indexed including state in Google which allows you to create language based urls for example.
</p>
<p>
So that&#8217;s it for now. The post only shows the keyfactors of my example. If you&#8217;re more interested, you should download my example project and dive into the code.
</p>
<p>
<a href="http://tigrou.nl/wp-content/uploads/2010/01/urlexample.zip">Download my example Eclipse project</a></p>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2010/01/02/context-based-urls-with-apache-wicket/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NLJug J-Fall 2010</title>
		<link>http://tigrou.nl/2009/11/18/nljug-j-fall-2010/</link>
		<comments>http://tigrou.nl/2009/11/18/nljug-j-fall-2010/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 21:07:05 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[nljug]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=209</guid>
		<description><![CDATA[Wednesday the 11th of november I visited JFall for the second time. This is the yearly event of the Dutch Java usergroup next to the JSpring in april. I attended on several sessions targetting especially new Java developments. For example the big improvements in JDK 7 where I was interested in. Keynote &#8211; Enterprise 2.0: [...]]]></description>
			<content:encoded><![CDATA[<p>Wednesday the 11th of november I visited JFall for the second time. This is the yearly event of the Dutch Java usergroup next to the JSpring in april. I attended on several sessions targetting especially new Java developments. For example the big improvements in JDK 7 where I was interested in.</p>
<ul>
<li>Keynote &#8211; Enterprise 2.0: New Technologies, Innovations and Communities (Reginald Hutcherson)</li>
<li>Speed up your applications with Java SE 7 (Jeroen Borgers)</li>
<li>Scaling Out with Hadoop and NoSql (Age Mooij)</li>
<li>Keynote &#8211; Adobe Systems (Christophe Coenraets)</li>
<li>The Quest for Parallelism: How To &#8216;upgrade&#8217; Your Application (Jan-Hendrik Kuperus)</li>
<li>JDK 7, What&#8217;s in it and what&#8217;s not (Simon Ritter)</li>
<li>Google Wave: what is it, and how does it work? (Jos Dirksen)</li>
</ul>
<p>(I translated some of the subjects to English)</p>
<p>Three of them had a lot in common, the speeding up, the parallelism and the jdk7 where the most interesting ones. The other sessions where more informative and for fun.</p>
<p>The subjects I was really excited about, are the new concurrency features in Java. Being this more and more important with the current multicore cpus and the cloud computing hype we can&#8217;t ignore it! And it&#8217;s not only faster, it&#8217;s also very cool and not even hard to give it a try as a normal programmer. I even think that this new stuff makes our live easier then the old fashioned threading stuff in Java 5 and earlier (a lot of new stuff in Java 7 is already available through Java 6 in the updates but often not enabled by default).</p>
<p>Some cool and nice features are:</p>
<ul>
<li>Fork join framework (next step in parallelism, helps you execute task based procedures)</li>
<li>Escape analysis (improvement in allocating memory for objects based on the scope of the object)</li>
<li>Project jigsaw (module management)</li>
<li>Compressed 64 bit pointers (store 64 bit pointers in 32 bit)</li>
<li>Garbage first collector (new algorithm for garbage collecting)</li>
</ul>
<p>That&#8217;s it for now, I didn&#8217;t have the time to start playing around with the new Beta of jdk7. Hope to get started soon!</p>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2009/11/18/nljug-j-fall-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Duchenne Heroes 2010</title>
		<link>http://tigrou.nl/2009/11/12/duchenne-heroes-2010/</link>
		<comments>http://tigrou.nl/2009/11/12/duchenne-heroes-2010/#comments</comments>
		<pubDate>Thu, 12 Nov 2009 21:27:29 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Biking]]></category>
		<category><![CDATA[gps]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[mtb]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=210</guid>
		<description><![CDATA[This time no technical kind of thing, the last months I&#8217;ve been working on an update of a website which I voluntary manage for my athletics club (www.av56.nl). I rewrote my simple own MVC framework to the well know CodeIgniter framework. And except that, I&#8217;ve been biking quite a lot too. Especially since I bought [...]]]></description>
			<content:encoded><![CDATA[<p>This time no technical kind of thing, the last months I&#8217;ve been working on an update of a website which I voluntary manage for my athletics club (<a href="http://www.av56.nl" target="_blank">www.av56.nl</a>). I rewrote my simple own MVC framework to the well know <a href="http://www.codeigniter.com" target="_blank">CodeIgniter</a> framework. And except that, I&#8217;ve been biking quite a lot too. Especially since I bought a road bike (Giant TCR Advanced 2) next to my mountainbike (Cube Reaction).</p>
<p>That biking crazyness has now been changed into a new adventure called <a href="http://2010.duchenneheroes.nl/" target="_blank">Duchenne Heroes</a>. In short some facts:</p>
<ul>
<li>7 days of mountainbiking</li>
<li>100 km each day</li>
<li>10.000 altimeters</li>
<li>4 countries</li>
<li>4 people per team</li>
</ul>
<p>And that all with just one main goal, collecting money for the<strong> Duchenne foundation</strong>. A good description can be read on <a href="http://en.wikipedia.org/wiki/Duchenne_muscular_dystrophy" target="_blank">wikipedia</a> about what Duchenne is. The idea came up after a few beers (always the guilty one <img src='http://tigrou.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ) with some friends and since last saturday, our team of four people is a fact! We started creating a website this week but there&#8217;s  a lot of work left: <a href="http://www.clubjegoes.nl" target="_blank">clubjegoes.nl</a></p>
<p>So, keep an eye on our website if you&#8217;re interested or even better, donate money to our team. We need 10.000 euro in total. We&#8217;re now busy thinking about how to create special sponsor packages. And not unimportant, start training since this is one of the toughest tours in the Benelux.</p>
<p>My next will soon be published, it&#8217;s about the Dutch NLJUG day called JFall which I attended last wednesday. It&#8217;s a conference of the Dutch Java user group. I&#8217;ll briefly describe the subjects I followed and try to dig into them later. Especially the new Java 7 improvements have my attention, awesome new stuff designed for multi core processors and cloud computing!</p>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2009/11/12/duchenne-heroes-2010/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using a custom Oracle collection type with iBatis</title>
		<link>http://tigrou.nl/2009/09/17/using-a-custom-oracle-collection-type-with-ibatis/</link>
		<comments>http://tigrou.nl/2009/09/17/using-a-custom-oracle-collection-type-with-ibatis/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 18:28:24 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[iBatis]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[LinkedIn]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=162</guid>
		<description><![CDATA[Some months ago I came across a problem with the more complex custom Oracle types in combination with iBatis. I thought that it would be nice to share it with you. In my case I had to link a list of objects in Java to an array of structs in SQL (Oracle). The biggest part [...]]]></description>
			<content:encoded><![CDATA[<p>Some months ago I came across a problem with the more complex custom Oracle types in combination with iBatis. I thought that it would be nice to share it with you. In my case I had to link a list of objects in Java to an array of structs in SQL (Oracle). </p>
<p>The biggest part of the trick is inside a custom type handler, which is actually a helper class with two important methods, the setParameter and the getResult. setParameter if for mapping parameters before firing the query and the getResult is for processing the result (if you use a custom type as an OUT parameter). For the example I used a Quantity class which has two properties, id and quantity. My Oracle types are a struct (Quantity) and a table of that struct (QuantityList)</p>
<p>The code will show you the rest, because once you know how to deal with this, other cases are quite easy.</p>
<pre class="brush: java; title: ; notranslate">
package nl.tigrou.test;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import java.util.List;
import oracle.jdbc.driver.OracleTypes;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;

import org.springframework.jdbc.support.nativejdbc.C3P0NativeJdbcExtractor;
import org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor;

import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
import com.ibatis.sqlmap.engine.type.JdbcTypeRegistry;
import com.mchange.v2.c3p0.impl.NewProxyConnection;

public class QuantityListTypeHandler implements TypeHandlerCallback
{

  private static final String QUANTITY = &quot;QUANTITY&quot;;
  private static final String QUANTITYLIST = &quot;QUANTITYLIST&quot;;

  static
  {
    JdbcTypeRegistry.setType(QUANTITY, OracleTypes.STRUCT);
    JdbcTypeRegistry.setType(QUANTITYLIST, OracleTypes.ARRAY);
  };  

  public void setParameter(ParameterSetter setter, Object parameter) throws SQLException
  {
    try
    {
      List&lt;Quantity&gt; quantities = (List&lt;Quantity&gt;) parameter;

      Connection conn = setter. getPreparedStatement(). getConnection();
      if(conn instanceof NewProxyConnection)
      conn = new C3P0NativeJdbcExtractorImpl().getNativeConnection(conn);

      StructDescriptor quantityStruct = StructDescriptor.createDescriptor(QUANTITY, conn);
      ArrayDescriptor quantityList = ArrayDescriptor.createDescriptor(QUANTITYLIST, conn);

      STRUCT[] elements = new STRUCT[quantities == null ? 0 : quantities.size()];

      for (int count = 0; count &lt; elements.length; count++)
      {
        Quantity quantity = quantities.get(count);

        elements[count] = new STRUCT(quantityStruct, conn, new Object[] { quantity.getId(), quantity.getQuantity() });
      }

      ARRAY array = new ARRAY(quantityList, conn, elements);

      setter.setArray(array);
    } catch (SQLException sqle)
    {
      throw sqle;
    }
  }

  private class C3P0NativeJdbcExtractorImpl extends C3P0NativeJdbcExtractor
  {
    public Connection getNativeConnection(Connection con) throws SQLException
    {
      return doGetNativeConnection(con);
    }
  }

  public Object getResult(ResultGetter getter) throws SQLException
  {
    ARRAY array = (oracle.sql.ARRAY) getter.getArray();
    ResultSet rs = array.getResultSet();
    List&lt;Quantity&gt; quantities = new ArrayList&lt;Quantity&gt;();
    while (rs != null &amp;amp;amp;amp;&amp;amp;amp;amp; rs.next())
    {
     STRUCT struct = (STRUCT) rs.getObject(2);
     Object[] attribs = struct.getAttributes();
     Quantity quantity = new Quantity();
     quantity.setId(((java.math.BigDecimal) attribs[0]).longValue());
     quantity.setQuantity(((java.math.BigDecimal) attribs[1]).intValue());
     quantities.add(quantity);
    }
    return quantities;
  }

  public Object valueOf(String value)
  {
    if (value == null)
      return new ArrayList&lt;Quantity&gt;();
    return value;
  }
}
</pre>
<p>And the corresponding query in one of your xml mapping files. The magic is all inside the inline parameter.</p>
<pre class="brush: sql; title: ; notranslate">
SELECT * FROM sometable x
LEFT JOIN TABLE (
  CAST
  (
    #quantities,handler=quantityListTypeHandler,jdbcType=STRUCT,javaType=Quantity# AS QuantityList
  )
) s ON (s.identifier = x.id)
</pre>
<p><strong>BTW, if you haven&#8217;t noticed it yet, <a href="http://ibatis.apache.org/">iBatis 3</a> is about to release. Check out the release candidates because they did an awesome job!</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2009/09/17/using-a-custom-oracle-collection-type-with-ibatis/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>First Garmin Edge 705 experiences</title>
		<link>http://tigrou.nl/2009/07/11/first-garmin-edge-705-experiences/</link>
		<comments>http://tigrou.nl/2009/07/11/first-garmin-edge-705-experiences/#comments</comments>
		<pubDate>Sat, 11 Jul 2009 17:53:09 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Biking]]></category>
		<category><![CDATA[gps]]></category>
		<category><![CDATA[mtb]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=164</guid>
		<description><![CDATA[Some weeks ago I bought the Garmin Edge 705. It&#8217;s THE gps device for biking. It&#8217;s waterproof, has a heart rate and cadence monitor. You can compare it with a TomTom but with a lot more features specialized for biking. More info here: Garmin. Example picture: The only thing I didnt like, where the maps [...]]]></description>
			<content:encoded><![CDATA[<p>Some weeks ago I bought the Garmin Edge 705. It&#8217;s THE gps device for biking. It&#8217;s waterproof, has a heart rate and cadence monitor. You can compare it with a TomTom but with a lot more features specialized for biking. More info here: <a href="https://buy.garmin.com/shop/shop.do?cID=160&amp;pID=10885" target="_blank">Garmin</a>.</p>
<p>Example picture:</p>
<p style="text-align: left;"><a href="http://tigrou.nl/wp-content/uploads/2009/07/garmin-edge-705_.450x450.jpg"><img class="size-full wp-image-187 aligncenter" title="garmin-edge-705_.450x450" src="http://tigrou.nl/wp-content/uploads/2009/07/garmin-edge-705_.450x450.jpg" alt="garmin-edge-705_.450x450" width="450" height="450" /></a>The only thing I didnt like, where the maps which you need to actually use the gps. For example, a map for the Netherlands costs you around 130 Euro. But there&#8217;s also a free alternative which is even better but you&#8217;ll have to do some research and reading. One of the sites which helped me a lot is <a href="http://openmtbmap.org/" target="_blank">openmtbmaps.org</a>, this is based on the openstreetmaps which are free maps maintained by you and me (I really like that, just like Open Source Software). Openmtbmaps is more dedicated to mountainbiking, meaning other rendering of the map and extra info like difficulty.</p>
<p style="text-align: left;">
<p style="text-align: left;">Enough about the gps system and maps, now the results! Two weeks ago I went for a holiday to the Black Forest in the southern part of Germany. I uploaded maps to my edge 705 and included some tracks from <a href="gpsies.com" target="_blank">gpsies.com</a> (amazing site too). Once there, I also bought an old fashioned paper based map including some routes at the local store.</p>
<p style="text-align: left;">I have biked several tracks but a nice (and heavy) one I would like to use as an example. It was a track over 60 kilometers and more then a thousand meters of climbing. I&#8217;m still experiencing with all the software and converting of thousand standards in maps world (gpx, kml, kmz, tcx etc), so there are some strange details in the charts below. Like the straight lines in google maps and the max speed of 20 km/h in the last chart. Yes, I&#8217;m sure that I biked harder <img src='http://tigrou.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . With a max of 55 km/h.</p>
<p style="text-align: left;">So the experiencing is still not over and my Edge 705 has a lot of unused features. Time to go biking again!</p>
<p style="text-align: left;">
<div  style="text-align: left;"  class="xmlgmdiv" id="xmlgmdiv_10"><iframe class="xmlgm" id="xmlgm_10" src="http://tigrou.nl/wp-content/plugins/xml-google-maps/xmlgooglemaps_show.php?gpxid=10" style="border: 0px; width: 665px; height: 400px;" name="Google_Gpx_Maps" frameborder="0"></iframe></div>
<p><img class="xmlgmele" id="xmlgmele_10"  style="text-align: left; margin: 0px; padding: 0px; max-width: 100%;"  alt="Elevation Profile" src="http://chart.apis.google.com/chart?cht=lc&#038;chls=5,0,0&#038;chf=c,ls,90,CCCCCC,0.16666666666667,FFFFFF,0.16666666666667&#038;chxt=x,y&#038;chxl=0:|0 km|20.3 km|40.5 km|60.8 km|81 km|1:|800 m|900 m|1000 m|1100 m|1200 m|1300 m|1400 m&#038;chd=s:IJJMPKJJJIJJLOVeonr3355wsqrossqkpkdXQQQPQTTSYYTVII&#038;chs=665x200&#038;chco=0000FF&#038;chtt=Elevation+Profile&#038;chts=555555,12" /><br /><img class="xmlgmspeed" id="xmlgmspeed_10"  style="text-align: left; margin: 0px; padding: 0px; max-width: 100%;"  alt="Speed Profile" src="http://chart.apis.google.com/chart?cht=lc&#038;chls=5,0,0&#038;chf=c,ls,90,CCCCCC,0.2,FFFFFF,0.2&#038;chxt=x,y&#038;chxl=0:|0 km|20.3 km|40.5 km|60.8 km|81 km|1:|0 km/h|4 km/h|8 km/h|12 km/h|16 km/h|20 km/h&#038;chd=s:66666H95166666666677x7626676B761766666666666766767&#038;chs=665x200&#038;chco=0000FF&#038;chtt=Speed+Profile&#038;chts=555555,12" /></p>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2009/07/11/first-garmin-edge-705-experiences/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AOP Advices and Aspect combinations</title>
		<link>http://tigrou.nl/2009/06/14/aop-advices-and-aspect-combinations/</link>
		<comments>http://tigrou.nl/2009/06/14/aop-advices-and-aspect-combinations/#comments</comments>
		<pubDate>Sun, 14 Jun 2009 18:37:18 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[AOP]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://tigrou.nl/?p=153</guid>
		<description><![CDATA[It&#8217;s about a month ago that I was completely stucked with a Spring AOP configuration. While working on a better transaction management (see older post), I kept struggling in a circle of either a non functioning transaction system or broken AOP aspects. It really drove me nuts so I decided to avoid that pain for [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s about a month ago that I was completely stucked with a Spring AOP configuration. While working on a better transaction management (see older post), I kept struggling in a circle of either a non functioning transaction system or broken AOP aspects. It really drove me nuts so I decided to avoid that pain for somebody else. No examples and code this time, just a simple pointer to the Spring documentation (which clearly took too much time to find <img src='http://tigrou.nl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ).</p>
<p>Let&#8217;s start with the note in the documentation:</p>
<p><strong><em>Advising aspects</em></strong></p>
<p><strong><em>In Spring AOP, it is not possible to have aspects themselves be the target of advice from other aspects. The @Aspect annotation on a class marks it as an aspect, and hence excludes it from auto-proxying.</em></strong></p>
<p>(<a href="http://static.springframework.org/spring/docs/2.5.x/reference/aop.html#aop-at-aspectj" target="_blank">Source</a> &#8211; Spring reference docs)</p>
<p>After searching a bit more information, since the text above not really explains why they&#8217;re excluded, I found the following 2 &#8220;rules&#8221;:</p>
<ul>
<li>Classes with annotations <em>@AspectJ</em> and classes that implement or extend any other AOP component are excluded from the autoproxy. This is because they aren&#8217;t target classes, and they perform tasks in Spring AOP infrastructure.</li>
<li>Proxy is not applied to beans that implement the interfaces <em>BeanPostProcessor</em> or <em>BeanFactoryPostProcessor</em>. The class <em>AnnotationAwareAspectJAutoProxyCreator</em> implements the interface <em>BeanPostProcessor</em>, which allows the class to modify the life cycle of beans on which a proxy must be created and applied.</li>
</ul>
<p>The first point here explains why Aspects are not proxied. The second point names another condition.</p>
<p>So, conclusion:</p>
<p><strong>Never use Aspects (@Apects) and proxy based transaction management on the same bean! </strong></p>
<p>It&#8217;s simple to avoid by creating a separate Aspect which advices other beans. Something like this:</p>
<pre class="brush: java; title: ; notranslate">
@Aspect
public class TestAspect
{

  @Before(&quot;execution(* someThing) &quot;)
  public void doSomethingElse()
  {

  }
}
</pre>
<p>That&#8217;s it! At the moment I&#8217;m working on the website of my local athletics club, with <a href="http://www.codeigniter.com" target="_blank">CodeIgniter</a> I&#8217;m finally enjoying PHP programming again.</p>
]]></content:encoded>
			<wfw:commentRss>http://tigrou.nl/2009/06/14/aop-advices-and-aspect-combinations/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

