<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-29883675</id><updated>2009-03-03T02:37:35.149-08:00</updated><title type='text'>The morning after</title><subtitle type='html'>As a Java developer I will be posting Java-related topics most of the time
&lt;a id="feed" href="http://draftdog.blogspot.com/atom.xml" title="Subscribe to this blog (Atom feed)"&gt;&lt;img src="http://www.mozilla.org/images/livemarks16.png" alt="Atom feed"/&gt;&lt;/a&gt;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-29883675.post-6693449291345218585</id><published>2007-12-29T13:47:00.000-08:00</published><updated>2007-12-29T13:56:33.443-08:00</updated><title type='text'>Piclens</title><content type='html'>I just stumbled upon a nifty cool plugin for Firefox, it's called &lt;a href="http://www.piclens.com/"&gt;Piclens&lt;/a&gt; and it gives you a great way of browsing photo albums as found on Google, Picasa, Flickr, Yahoo, Facebook, etc...&lt;br /&gt;I recommend visiting their website, unfortunately there currently isn't a plugin for Firefox on Linux yet, but Apple and Windows users should have no problem installing it, including Internet Explorer and Safari!&lt;br /&gt;&lt;br /&gt;Here's a small video I found on Youtube, it features the CoolIris guys: &lt;embed src="http://www.youtube.com/v/qE_aapBJJBw" type="application/x-shockwave-flash" wmode="transparent" height="350" width="425"&gt;&lt;/embed&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-6693449291345218585?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/6693449291345218585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=6693449291345218585' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/6693449291345218585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/6693449291345218585'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2007/12/piclens.html' title='Piclens'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29883675.post-1416248718788307016</id><published>2007-12-25T09:05:00.000-08:00</published><updated>2007-12-25T09:22:56.291-08:00</updated><title type='text'>Recovering Ubuntu after a Windows installation</title><content type='html'>what follows is a small step-by-step guide on how to recover the ability to boot your Ubuntu partition after a new Windows installation&lt;br /&gt;&lt;br /&gt;problem: Windows overwrites the Master Boot Record (MBR), effectively destroying any LILO or GRUB setup you might have had; contrary to what several websites claim: &lt;span style="font-style: italic;"&gt;just setting the proper partition active will NOT fix the problem&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;why: I've had this problem several times in the past and I've used different ways of being able to recover my dual-boot capability, I Googled for a solution each time again, this time I hope to win some time by keeping track of what I did the last time&lt;br /&gt;&lt;br /&gt;solution: reinstall LILO or GRUB&lt;br /&gt;&lt;br /&gt;how: we'll be reinstalling GRUB so that the original boot screen is shown again at startup&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;pop-in your Ubuntu Live CD and wait for Ubuntu to have loaded&lt;/li&gt;&lt;li&gt;open a terminal&lt;/li&gt;&lt;li&gt;type &lt;span style="font-family: courier new; color: rgb(0, 153, 0);"&gt;sudo grub&lt;/span&gt; and hit enter, this will open a new interactive context within your terminal&lt;/li&gt;&lt;li&gt;now type &lt;span style="font-family: courier new; color: rgb(0, 153, 0);"&gt;find /boot/grub/stage1&lt;/span&gt; and hit enter, this will print a string in the console, in my case it printed&lt;span style="font-family: courier new;"&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;(hd0,2)&lt;/span&gt;&lt;/span&gt;, we'll be using this string in the following steps .. if something else is printed in your console then substitute my string in what follows&lt;br /&gt;&lt;/li&gt;&lt;li style="font-family: trebuchet ms;"&gt;type &lt;span style="font-family: courier new; color: rgb(0, 153, 0);"&gt;root (hd0,2)&lt;/span&gt; and hit enter&lt;/li&gt;&lt;li style="font-family: trebuchet ms;"&gt;type &lt;span style="font-family: courier new; color: rgb(0, 153, 0);"&gt;setup (hd0)&lt;/span&gt; and hit enter again&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: courier new;"&gt;&lt;span style="font-family: trebuchet ms;"&gt;finally type &lt;span style="font-family: courier new; color: rgb(0, 153, 0);"&gt;quit&lt;/span&gt; and hit enter to exit the GRUB console&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;at this point the GRUB information should have been written to the proper partition (just as it was before the Windows installation), restart your system and make sure the Ubuntu Live CD is ejected before the system actually reboots&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;I had to reboot twice for everything to properly work, for some reason Ubuntu presented a black screen with a blinking cursor the first time&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-1416248718788307016?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/1416248718788307016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=1416248718788307016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/1416248718788307016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/1416248718788307016'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2007/12/recovering-ubuntu-after-windows.html' title='Recovering Ubuntu after a Windows installation'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29883675.post-116601929839263037</id><published>2006-12-13T05:40:00.000-08:00</published><updated>2006-12-13T06:20:56.156-08:00</updated><title type='text'>mvn site:deploy and SSH</title><content type='html'>Recently I've been going in deep at work using the Maven2 release plugin, I have to say this plugin does the job really well, updating all pom.xml files with the new version references, including the SCM urls and dependencies, there's even excellent SVN integration in that it knows about trunk/tags/branches when updating to the next release .. taking care of this manually would quickly become very cumbersome.&lt;br /&gt;&lt;br /&gt;Anyway, I got stuck actually deploying the new release to the server, this is done by calling release:perform by executing the deploy:deploy and site:deploy goals. The former goal works fine, although it's slow as heck, but the latter one simply does not work.&lt;br /&gt;&lt;br /&gt;I was able to trace it back to issue &lt;a href="http://jira.codehaus.org/browse/MDEPLOY-9?rc=1"&gt;MDEPLOY-9&lt;/a&gt;, which is supposed to be fixed in the next stable release (which is going to be 2.0). So I tried to build the 2.0-SNAPSHOT myself (the ones found &lt;a href="http://people.apache.org/repo/m2-snapshot-repository/org/apache/maven/plugins/maven-site-plugin/2.0-SNAPSHOT/"&gt;here&lt;/a&gt; are way too old so they had the same problem), without success .. apparently it requires Maven 2.1-SNAPSHOT, but if you disable this requirement the build will fail on the maven reporting api (again version 2.1-SNAPSHOT is needed, which you would need to build yourself too).&lt;br /&gt;&lt;br /&gt;So I abandoned this and went looking for another solution, and I found one, an easy one which will help me in other areas too: ssh-agent. The problem was that deploy:site is attempting to call &lt;span style="font-weight:bold;"&gt;ssh&lt;/span&gt; in batch mode in order to work on the host server, but since the settings.xml is ignored it won't be able to pass in the password in order to access your private key. Running Putty's PAGEANT won't work either because you would need to have deploy:site read the settings.xml in that case.&lt;br /&gt;&lt;br /&gt;Fortunately there's a solution when you are running Linux (or Cygwin), just run the ssh-agent (which is similar to PAGEANT) and add your key, it will prompt you for the password only once, from that point on the password will no longer be asked, effectively allowing the deploy:site goal to continue. I've found good instructions &lt;a href="http://www.securityfocus.com/infocus/1812"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This is basically what I did:&lt;br /&gt;1. called ssh-agent and copy the output in my ~/.bashrc&lt;br /&gt;2. called ssh-add &lt;path-to-key&gt;&lt;br /&gt;3. entered the password I was prompted for&lt;br /&gt;4. made sure the key was property collected by calling ssh-agent -l&lt;br /&gt;&lt;br /&gt;That's it .. when I was finished I was able to execute site:deploy without any further issues.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-116601929839263037?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/116601929839263037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=116601929839263037' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/116601929839263037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/116601929839263037'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2006/12/mvn-sitedeploy-and-ssh.html' title='mvn site:deploy and SSH'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29883675.post-115642167769414202</id><published>2006-08-24T04:55:00.000-07:00</published><updated>2006-08-25T07:18:11.350-07:00</updated><title type='text'>SessionFactory.getCurrentSession()</title><content type='html'>I recently refactored the data-access code in my current project. I noticed the Spring 2.0 Javadoc as well as the Hibernate 3.x Javadoc to recommend using SessionFactory.getCurrentSession() from now on.&lt;br /&gt;&lt;br /&gt;For Spring users this means that extending HibernateDaoSupport should be avoided in favor of writing plain Hibernate code directly. When putting this in practice it feels like a natural evolution as there's no more need for the typical use of the callback mechanism in this approach.&lt;br /&gt;&lt;br /&gt;A thing to note though, and I feel the current documentation does not stress this enough, is that this new approach requires a transactional context. Basically this means that a transaction interceptor must have been triggered prior to a call to SessionFactory.getCurrentSession(), otherwise a nasty exception will be thrown, saying no Hibernate session is bound to the current thread.&lt;br /&gt;The documentation mentions this &lt;a href="http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#architecture-current-session"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;What I did to make sure stuff would work as before is to intercept DAOs with both the HibernateInterceptor and a TransactionInterceptor, for the transaction interceptor I am using &lt;a href="http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/transaction/interceptor/TransactionAspectSupport.html"&gt;TransactionAspectSupport&lt;/a&gt;&lt;br /&gt;which is able to detect transaction demarcation using Java5 annotations. This is nice since no further Spring configuration is required, just demarcate transactions on the DAOs and you're done.&lt;br /&gt;&lt;br /&gt;All DAO methods are required to propagate the transaction (in order to make sure there is one, we need this to guarantee a reference to the current context in the session factory), finders are flagged with readOnly.&lt;br /&gt;&lt;br /&gt;This all looks pretty innocent but I bothered to write this down here nevertheless, I've spent several hours figuring out what was going wrong, just to learn the Javadoc documentation wasn't mentioning any of this. My problems started when unit tests were failing because I was testing my DAOs (handwritten DAOs, not generated by AndroMDA) and I didn't have any transactional context at that point.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-115642167769414202?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/115642167769414202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=115642167769414202' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115642167769414202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115642167769414202'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2006/08/sessionfactorygetcurrentsession.html' title='SessionFactory.getCurrentSession()'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29883675.post-115510249647890699</id><published>2006-08-08T22:25:00.000-07:00</published><updated>2006-08-08T23:01:13.066-07:00</updated><title type='text'>Networking IO and Threading</title><content type='html'>Recently I had to write a software component capable of dealing with a non-Java service, it was actually pretty straightforward is I only needed to handle lines of text over a TCP socket. I needed both the send and receive data over the socket, this included commands with replies as well as support for notifications. For the sake of testing I also wrote a small mock server instance.&lt;br /&gt;&lt;br /&gt;It's clear that when dealing with incoming data over a network or file system you'll want to wait for the next chunk in another thread, otherwise you'll block the application thread and most of the time this is undesired. Sounds not too hard, I was able to write it in a rather short time frame, tests were all passing ... all was good.&lt;br /&gt;&lt;br /&gt;When I ran the tests in another environment I noticed they consistently failed, I quickly realized this was due to the multi-processor architecture the machine was using. I tested on a few other platforms and I could indeed confirm the failures only to occur on multi-processor machines. Mind you, it worked well on Ubuntu Linux using Pentium 4 with hyper-threading but &lt;span style="font-style:italic;"&gt;not&lt;/span&gt; on Ubuntu using a dual core (Dell D-820).&lt;br /&gt;&lt;br /&gt;Since our production environment features multi-processor machines too it was a big must to have this issue fixed, especially since another collegue of mine also wrote some threading code and it showed the same problem.&lt;br /&gt;&lt;br /&gt;First I thought it was due to the Maven2 Surefire plugin somehow forking tests in parallel (the error I was getting was saying that the server socket I was trying to create was already in use, the well-known JVM_BIND error), however, that was not the case .. tests were being executing sequentially, the problem was that the code I wrote for both the client-side and server-side threads was not bulletproof, I could see in the log file that some threads would never die.&lt;br /&gt;&lt;br /&gt;Now you will probably say "yeah, learn how to work with threads and do it right", and to a certain extent you're right :-) but my case involved a feature which made it a bit special: when a client connection was broken it should automatically attempt to reconnect to it, effectively creating another thread, this required a bit more synchronization and a clear and solid way of starting and stopping threads.&lt;br /&gt;&lt;br /&gt;By following the rules of thumb below I was able to easily write stable threading code:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;it is good for client threads to rely on the socket throwing a SocketException when blocked in a read operation on the socket's inputstream, when the server socket closes this is what will happen&lt;/li&gt;&lt;br /&gt;&lt;li&gt;have two global variables: 'closing' and 'closed'&lt;/li&gt;&lt;br /&gt;&lt;li&gt;define a method which can close the thread, this method should set 'closing' to true&lt;/li&gt;&lt;br /&gt;&lt;li&gt;at the end of the thread's run method 'closed' must be set to true, take care of any exceptions; synchronize this method&lt;/li&gt;&lt;br /&gt;&lt;li&gt;the thread's run method should check whether 'closing' is set to true, in case it is true the thread should break out of any loop it's currently in&lt;/li&gt;&lt;br /&gt;&lt;li&gt;after calling the thread's close method from another thread (!) it's generally a good idea to also call the join method, this will synchronize this thread with the current one by waiting for it to die&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;By using the two global variables above and relying on the SocketException when blocked in an IO operation I was sure to be able to handle any situation where the thread would need to be closed. The thread calling the close method would ideally wait for the thread to finish, this can be done using the join method mentioned above. Following these rules your thread &lt;span style="font-style:italic;"&gt;will&lt;/span&gt; be closed once the close method returns.&lt;br /&gt;&lt;br /&gt;I use two variables because I also provide an 'isClosed' method which will only return true when the thread has actually finished completely.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-115510249647890699?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/115510249647890699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=115510249647890699' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115510249647890699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115510249647890699'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2006/08/networking-io-and-threading.html' title='Networking IO and Threading'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29883675.post-115084138166032005</id><published>2006-06-20T14:47:00.000-07:00</published><updated>2006-06-26T18:21:25.920-07:00</updated><title type='text'>Code generation and Annotations</title><content type='html'>This post will be about code generation and JDK5 annotations. If you are one of the lucky ones being able to make use of the latest JDK features at work you'll surely have benefit from the many improvements such as the templating capabilities, the simplified for-loop, specialized overloading, ... and maybe even the newly introduced annotations.&lt;br /&gt;&lt;br /&gt;For people not familiar with this concept: annotations are specific sets of meta-data used to attach more information to specific parts of a class definition such as a member field. Annotations are becoming increasingly more popular in combination with middleware such as &lt;a href="http://www.springframework.org/"&gt;Spring&lt;/a&gt; and &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt;. If you have used &lt;a href="http://xdoclet.sourceforge.net/"&gt;XDoclet&lt;/a&gt; or &lt;a href="http://www.andromda.org/"&gt;AndroMDA&lt;/a&gt; before you are already familiar with annotations (albeit in another form). I will be giving examples shortly anyway.&lt;br /&gt;&lt;br /&gt;The interesting thing with annotations, and this is what makes them complementary to regular class information, is that they do not convey class information but rather meta-information, information about information, and this is typically what you would do when modeling a class diagram in UML.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Meta-data and UML&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Most people use UML to describe a static part of their domain, typically the object model. This model features classes, inheritance, associations, attributes, and so on. So far nothing special, it gets interesting when using the more advanced features such as &amp;lt;&amp;lt;stereotypes&amp;gt;&amp;gt;, @tagged.values or even the more common features such as changeability, multiplicity, query-flag, etc...&lt;br /&gt;&lt;br /&gt;Let's, for the sake of simplicity, take a small persistable POJO with a few attributes, it could be described as follows:&lt;br /&gt;&lt;/stereotypes&gt;&lt;pre&gt;&lt;br /&gt;Class : "Person"&lt;br /&gt;Attribute id : Long&lt;br /&gt;Attribute name : String&lt;br /&gt;Attribute phone : String&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We can now give additional information to further complete the "Person" class:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;id is required&lt;/li&gt;&lt;br /&gt; &lt;li&gt;name is required&lt;/li&gt;&lt;br /&gt; &lt;li&gt;phone is optional and there can be many numbers per person&lt;/li&gt;&lt;br /&gt; &lt;li&gt;the class can be persisted&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Let's see how this can be modeled using UML:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Class : "Person" @persistable&lt;br /&gt;Attribute id : Long [multiplicity=1]&lt;br /&gt;Attribute name : String [multiplicity=1]&lt;br /&gt;Attribute phone : String [multiplicity=0..*]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see this is probably the most efficient way of expressing our information, it is complete yet does not contain anything extra. The corresponding Java code, on the other hand, is a little more verbose (most of the time you'll write accessors to your member fields).&lt;br /&gt;&lt;br /&gt;For those meta-data features that are not supported by UML (you might want to create your own sets of meta-data) you can always resort to the use of tagged values.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Unfortunately not all UML tools support tagged values that well, they should be supported on ANY possible model element.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;AndroMDA&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When using AndroMDA for code generation it becomes very easy to benefit from these UML features: a simple Velocity (or Freemarker) template can transform the Person class from UML to actual Java code. This is basically a one-on-one transformation, a no-brainer.&lt;br /&gt;&lt;br /&gt;The idea of using AndroMDA with UML is to be able to most efficiently translate the business domain into a binary form, next it can be processed and more code can be produced that could be fed to a compiler or interpreter. It appears the use of annotations extends this smoothly concept.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;In reality&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Why would you want to make use of such features ? Well, let me give you some examples where I'm applying the stuff I explained above:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;My problem domain asks for some kind of administration GUI which can be connected to the   back-end in order to perform operations on the object model. We would like to write as little code as possible for this GUI and therefore we like to have it auto-detect specific meta-data from the individual object types.&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;When the GUI client deserializes class instances received from the server it can introspect them in order to detect this meta-data, it could for instance detect an attribute is mandatory or needs to adhere to some specific format in order to present the user the proper validation logic.&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Objects in the domain model often have attributes that do not need persistence, we call these types of objects operational data, what the persistence framework is concerned these attributes are transient.&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;The AndroMDA templates have been updated to render a specific annotation for these attributes so they are treated differently on the server: all operational data is cached for performance and reused when an the same instance is loaded in a separate session.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;I'm sure you could come up with your own specific applications, the usage is so natural one wonders why it took so long for this feature to be available in the Java programming language.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-115084138166032005?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/115084138166032005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=115084138166032005' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115084138166032005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115084138166032005'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2006/06/code-generation-and-annotations.html' title='Code generation and Annotations'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29883675.post-115063454291193169</id><published>2006-06-18T05:31:00.000-07:00</published><updated>2006-06-18T06:12:40.666-07:00</updated><title type='text'>Rich domain models: Immutability</title><content type='html'>Something which works well with rich domain models is immutability: don't allow client code to update an object instance, in other words: don't use any public setters on your domain objects (I recommend not using any setters at all, set your fields directly).&lt;br /&gt;&lt;br /&gt;I've been thinking about this since a long time but I never dared to implement it because I somehow thought I would run into problems with this approach. When I attended &lt;a href="http://www.springone.com/"&gt;SpringOne&lt;/a&gt; last week I saw a presentation where the speaker what advocating the same approach, this gave me the courage to go out and give it a try. I must say I was surprised how simple things were once I refactored all &lt;a href="http://junit.org/"&gt;JUnit&lt;/a&gt; tests etc..&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;No setters ? Then what do I do when I want to update something ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well basically you would model a business operation returning a new object instance which has been constructed with the members set to the proper state. That way you don't update the current instance but simply copy (some of) its members over into a new one.&lt;br /&gt;&lt;br /&gt;Note that you don't need such business operation for each member field, you should model an operation per use-case: if your application requires you to always change 3 fields at the same time then model a single operation which takes 3 arguments!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Tip: make sure you have a constructor taking the required properties and another constructor taking all properties so that it is easy for users to instantiate objects in a call.&lt;br /&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Can my persistence engine handle objects without setters ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It most likely can. In the case of &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt; you can configure the access level in the mapping file, or by using the @AccessType annotation on your POJO (set it to 'field' instead of the default 'property'). Also: don't forget to have a (non-public) default constructor so that Hibernate can instantiate your POJOs.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Okay, my objects are immutable, now what ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When using them you'll quickly see that working with immutable objects is actually simpler because you are sure client code cannot alter their state. This makes them thread-safe and avoids unnecessary validation checks throughout your code. Give it a try and see how it's more clear to work with them. Granted, you can't reuse an instance and call Session.update() (Hibernate) but you can still copy over the updated fields using Session.merge().&lt;br /&gt;&lt;br /&gt;In my personal experience they are not simply straightforward but they also point out possible flaws in your architecture (too long to go into that right now, maybe in another post sometime), it seems that updating objects is more dangerous that one would think.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What about support for JavaBeans in other tools/APIs ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You won't always be able to make use of them since they often rely on the explicit presence of paired getter/setter accessors. On the other hand, GUI frameworks such as &lt;a href="http://www.jidesoft.com/"&gt;JIDE&lt;/a&gt; support alternative implementations when using their bean forms, I've actually once worked with Map-based beans (no direct accessors, just getProperty(String) and setProperty(String,Object)) and adding support was as simple as implementing their Property interface and make sure it is used instead of their default BeanProperty implementation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-115063454291193169?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/115063454291193169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=115063454291193169' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115063454291193169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115063454291193169'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2006/06/rich-domain-models-immutability.html' title='Rich domain models: Immutability'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29883675.post-115063205290537225</id><published>2006-06-18T04:52:00.000-07:00</published><updated>2006-06-18T07:57:30.046-07:00</updated><title type='text'>Rich domain models: Intro</title><content type='html'>This topic will be a quite controversial one in the Java community in the near future, if not already.&lt;br /&gt;&lt;br /&gt;I'm not 100% sure myself what to think about it, but here goes:&lt;br /&gt;&lt;br /&gt;When people talk about rich domain models they are referring to an object model in which the participating objects are not simply data holders but also carry a lot of business logic which would &lt;span style="font-style: italic;"&gt;'normally'&lt;/span&gt; go into a service. In the current JEE project landscape most developers make use of what is known as &lt;a href="http://en.wikipedia.org/wiki/Anemia"&gt;anemic&lt;/a&gt; domain models in which objects are simply there to carry data back and forth, mainly for usage by a persistence engine such as &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now this sure sounds interesting but some issues quickly come to mind, I'll discuss them here.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What's wrong with anemic domain models ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In my personal opinion it is not that bad to treat your object model as plain data holders, most people currently work that way by making use of the JavaBean convention where each field member has getter and setter accessors.&lt;br /&gt;&lt;br /&gt;The advantage here is that you can treat the object model as a sort of API, the service layer can then act as a coarse-grain abstraction providing an interface to the business use-cases. Since the objects themselves have no specific business logic they can be reused by different service layers (in most cases you'll never need to share an domain model between different service layers, but the project I currently work on will require this).&lt;br /&gt;&lt;br /&gt;The problem is more on a conceptual level where the objects would better reflect the real world if they would actually have specific behavior and knowledge of business logic. Bear in mind that moving service logic into objects will require you to significantly think (!) about your design, more specifically you'll have to become an expert in the business domain as well as a skilled modeler, here's where your analytic skills come into play.&lt;br /&gt;&lt;br /&gt;On the other hand what does it mean to have something like Basket.add(Dvd) ? Technically it is not the basket adding the DVD, it is a human putting the DVD into the basket .. What do we do with this ? Is this an example a corner case ?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Will I be merging my service layer with my persistence layer ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Yes and no. Business logic will obviously be moved from the service layer but surely not all of it, you will still need a service layer, it'll just be more lightweight.&lt;br /&gt;&lt;br /&gt;There's a catch though. A business domain model implementing business logic is fine as long as you are navigating over the domain model itself, remember we are working with POJO objects, there are by default no dependencies outside of the domain!&lt;br /&gt;&lt;br /&gt;Now take the case where a specific business operation needs to count the number of objects in the datastore, you'll not want to pass this number as an argument into the operation but rather you'll want the method itself to discover this. When you have a reference to the datastore available somehow the problem will be solved, but we don't have such reference!&lt;br /&gt;This problem could be overcome by making using of AOP and having dependencies to external resources such as a datastore injected for you, this is quite elegant and can easily be done by making use of the runtime AspectJ support in Spring AOP.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What will I gain ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First of all your service layer will be more light-weight and the object model will more naturally encapsulate the system's behavior. This opens the door to several alternatives.&lt;br /&gt;&lt;br /&gt;With Java 6 around the corner support for scripting will be added, these scripts will be able to access the domain model directly, having business logic executed without any additional effort, that's beautiful, no ? (I'm actually using &lt;a href="http://labs.jboss.com/portal/jbossrules/docs/"&gt;Drools&lt;/a&gt; at the moment, they are definitely more readable and lighter when working with a rich domain model).&lt;br /&gt;&lt;br /&gt;Secondly you'll be able to better express yourself, this quickly becomes clear when writing unit tests, these tests typically are easier to understand and have less dependencies to external resources.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;More on this topic later...&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-115063205290537225?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/115063205290537225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=115063205290537225' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115063205290537225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115063205290537225'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2006/06/rich-domain-models-intro.html' title='Rich domain models: Intro'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29883675.post-115063083499886944</id><published>2006-06-18T04:23:00.000-07:00</published><updated>2006-06-18T06:15:27.506-07:00</updated><title type='text'>Code generation and AOP</title><content type='html'>In most, if not all, of my projects I am making use of &lt;a href="http://docs.andromda.org/"&gt;AndroMDA&lt;/a&gt; in order to get the boilerplate code generated for me, this works great but sometimes I'll find myself customizing the cartridges to fit the architecture/design, in this entry I will give an simple example replacing AndroMDA-generated logic with AOP using &lt;a href="http://www.eclipse.org/aspectj/index.php"&gt;AspectJ&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As an example take the case of the &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt; entities: AndroMDA generates an abstract base class and a concrete subclass suited for implementation. The subclass will be generated only once so that you can safely add your implementation for business operations without the generation process overwriting it each time you run AndroMDA.&lt;br /&gt;&lt;br /&gt;This is an example of an abstract base class:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public abstract class Entity&lt;br /&gt;  {&lt;br /&gt;      ...&lt;br /&gt;      public abstract void myOperation(String value);&lt;br /&gt;      ...&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And here is an example of an implementation:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public class EntityImpl extends Entity&lt;br /&gt;  {&lt;br /&gt;      ...&lt;br /&gt;      public void myOperation(String value)&lt;br /&gt;      {&lt;br /&gt;          // todo: implement&lt;br /&gt;          throw new UnsupportedOperationException("EntityImpl.myOperation");&lt;br /&gt;      }&lt;br /&gt;      ...&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This means, however, that when you are making use of Hibernate inheritance the hierarchy can get rather deep, it would be nice if this could be avoided.. And it can!&lt;br /&gt;&lt;br /&gt;The trick is to make use of AspectJ, with this it is possible to only have the base class as a concrete class and not generating the *Impl class; the business operations still throw an exception as shown above but this behavior can be overridden by an aspect advice.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public aspect EntityAspect&lt;br /&gt;  {&lt;br /&gt;      void around(String value, Entity entity) : &lt;br /&gt;        execution(* Entity.myOperation(String)) &amp;&amp; this(entity) &amp;&amp; args(value)&lt;br /&gt;      {&lt;br /&gt;          // here you can implement the new logic&lt;br /&gt;          //   value = the argument passed in&lt;br /&gt;          //   entity = 'this'&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Having such an aspect woven in will replace the generated method implementation entirely (without removing it though), thus effectively annulling the exception. As far as I know this can only be achieved as elegantly as presented here by making use of the &lt;span style="font-weight:bold;"&gt;around()&lt;/span&gt; advice.&lt;br /&gt;&lt;br /&gt;Note that it is still possible to call the original implementation by making use of &lt;span style="font-weight:bold;"&gt;proceed()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Considering the different possibilities for merging in your own code in generated code somehow (protected sections, inheritance, etc..) I think this is a nice alternative. One could argue that it is more interesting to have such implementation inside the generated .java file but trying to enforce this will result in not-so-elegant situations considering you'll want to regenerate the class each time while retaining you're custom implementation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-115063083499886944?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/115063083499886944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=115063083499886944' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115063083499886944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115063083499886944'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2006/06/code-generation-and-aop.html' title='Code generation and AOP'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29883675.post-115062429065498676</id><published>2006-06-18T02:37:00.000-07:00</published><updated>2006-06-18T06:14:28.793-07:00</updated><title type='text'>SpringOne</title><content type='html'>I just got back from the &lt;a href="http://www.springone.com/"&gt;SpringOne&lt;/a&gt; conference in Antwerp (Belgium), it was a joined effort of &lt;a href="http://www.interface21.com/"&gt;Interface21&lt;/a&gt; and &lt;a href="http://www.bejug.org/"&gt;BeJUG&lt;/a&gt;, the Belgian Java User Group.&lt;br /&gt;&lt;br /&gt;It was a pretty good conference, but not great as most of the talks were rather superficial and sometimes even shameless plugs for commercial tools, I guess that's more or less normal since these kind of events use sponsors to keep the price down but still bring some cash for the organizing parties, ah well..&lt;br /&gt;&lt;br /&gt;These are the presentations I attended:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Practical Quick Start with Acegi Security: &lt;/span&gt;very good presentation by Ben Alex, concise and to the point&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Guaranteeing Spring Application Performance:&lt;/span&gt; this presentation should have been called &lt;span style="font-style: italic;"&gt;"let me show you what my Symantec profiler can do"&lt;/span&gt;, the word "Spring" was not uttered once; I was hoping to learn about some of the pitfalls and design decisions when using Spring which could affect application performance, I wasted my time on this one&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;Spring RCP: &lt;/span&gt;&lt;/span&gt;RCP stands for &lt;span style="font-style: italic;"&gt;Rich-Client Project&lt;/span&gt; which is an attempt to make Java Swing more accessible and maintainable in applications, I've been using Spring RCP since 6 months so I wasn't really hearing anything new, good presentation by Keith Donald though&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Pragmatic Spring: &lt;/span&gt;&lt;font&gt;two guys quickly threw together a presentation about how they abuse Spring at work, nothing to learn here about applying Spring in a pragmatic manner&lt;/span&gt;&lt;/li&gt;&lt;/font&gt;&lt;li&gt;&lt;font&gt;&lt;span style="font-weight: bold;"&gt;Practical Rich Domain Models: &lt;/span&gt;presentation by a local guy, pretty good actually, but a little too dogmatic, and suffering a bit from the Martin Fowler/thought leader syndrome; I hope to discuss the subject of rich domain model later on&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/font&gt;&lt;li&gt;&lt;font&gt;&lt;span style="font-weight: bold;"&gt;The art of domain modeling:&lt;/span&gt; I was hoping Keith would have a bit more tips and best practices for us when modeling the problem domain, as a heavy user of UML/MDA this would have been very interested; on a side note: I got the impression Keith himself wasn't really convinced of the stuff he was presenting&lt;/span&gt;&lt;/li&gt;&lt;/font&gt;&lt;li&gt;&lt;font&gt;&lt;span style="font-weight: bold;"&gt;Embeddable lightweight Messaging:&lt;/span&gt; pretty good presentation on an open-source JMS alternative, targeted at a novice audience but interesting nevertheless; the idea behind the project presented here (called MantaRay) is to no longer have a JMS broker but have the distributed endpoint/nodes copy the information such as topics and queues, Spring is able to make an abstraction out of this (just configure the connection factory for the JMS template and you're good)&lt;/span&gt;&lt;/li&gt;&lt;/font&gt;&lt;li&gt;&lt;font&gt;&lt;span style="font-weight: bold;"&gt;Spring Patterns:&lt;/span&gt; presentation about how to integrate your own technology into the spring framework by following certain conventions at the same time, mildly interesting as I won't be doing that kind of stuff&lt;/span&gt;&lt;/li&gt;&lt;/font&gt;&lt;li&gt;&lt;font&gt;&lt;span style="font-weight: bold;"&gt;Core features of Spring 2.0:&lt;/span&gt; Kinda weird to have this presentation at the very end of the conference; Adrian Colyer did a good job though, seems Spring 2.x features scripting support, simplified configuration, reloadable beans (very interesting when you have Drools rules that could be hot-deployed, like I'm doing in my current project), some improvements in the JMS area etc..&lt;/span&gt;&lt;/li&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;&lt;/font&gt;So overall I enjoyed being there, I'll be reflecting on the domain model stuff in the next couple of days, I'll make sure to post my findings/conclusions...&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29883675-115062429065498676?l=draftdog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://draftdog.blogspot.com/feeds/115062429065498676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=29883675&amp;postID=115062429065498676' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115062429065498676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29883675/posts/default/115062429065498676'/><link rel='alternate' type='text/html' href='http://draftdog.blogspot.com/2006/06/springone.html' title='SpringOne'/><author><name>wouter</name><uri>http://www.blogger.com/profile/02822631911503159520</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13731881426704757652'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>