<?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' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1493353025088627001</id><updated>2012-01-30T01:42:41.635-08:00</updated><category term='Cassandra NoSQL'/><category term='Spring Maven Jetty Classloading'/><title type='text'>Java Code Splitter</title><subtitle type='html'>Guten Tag! Do you like Java and coding as much as I do? I am a 36 yrs old Berlin kid, stranded in Norway. I work in the gaming industry as a Software Engineer and have to solve a lot of code related issues every day.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Reikje</name><uri>http://www.blogger.com/profile/12381574441248297953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-UYKBf_C81Kg/TpMEsKVx45I/AAAAAAAAAAQ/pgbxe7zw7JU/s220/reik_photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>70</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-8266983310593740912</id><published>2012-01-23T05:09:00.000-08:00</published><updated>2012-01-23T05:09:47.669-08:00</updated><title type='text'>Starting Dependency WAR Artifact using maven-jetty-plugin</title><content type='html'>I have worked in a lot of Maven projects, that used the &lt;a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin"&gt;maven-jetty-plugin&lt;/a&gt;. Normally the plugin is used to start a Jetty container with the WAR artifact produced by the current project. This works like a charm. Sometimes however, you want to host the WAR artifact of another project. This could be the case if you are developing the client for a service that can be reached via HTTP. The integration tests in the client project would require the service to be running and reachable, so that these tests can test and verify the client code. To start the Jetty container before and shut down after the integration test, you define two executions and bind them to the correct phase in Mavens lifecycle.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1662983.js?file=pom-integration-test.xml"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Also starting any external WAR artifact is straight forward with the maven-jetty-plugin and the deploy-war goal.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1662983.js?file=pom-external-war.xml"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;As you can see, the version is hard-coded in the path. This is  somewhat ok as long as you are not violating the DRY principle. If you use the version somewhere else in your pom.xml, make sure to use a custom Maven property. Another way, which is a bit nicer perhaps, is to use the &lt;a href="http://cargo.codehaus.org/Maven2+plugin"&gt;cargo-maven2-plugin&lt;/a&gt; which out of the box can start the WAR artifact of any Maven dependency from within the dependencies section. Here is a nice example from &lt;a href="http://stackoverflow.com/questions/2677815/how-to-make-jetty-maven-plugin-deploy-a-war-that-is-retrieved-from-a-repository"&gt;stackoverflow.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As you can see, either the cargo-maven2-plugin or the maven-jetty-plugin can be used for the simple use cases. It gets a bit trickier if you want to start the external WAR artifact and set some System properties during startup of the container. Both the &lt;a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin#MavenJettyPlugin-sysprops"&gt;maven-jetty-plugin&lt;/a&gt; and the &lt;a href="http://cargo.codehaus.org/Passing+system+properties"&gt;cargo-maven2-plugin&lt;/a&gt; allow you to define individual system properties. However, only the maven-jetty-plugin can read a pre-existing properties file instead of individual System properties. This was required in one of the projects I am working on. Copying all the System properties out of the properties file to add them as individual System properties, is a lot of work and would again violate the DRY principle. &lt;br /&gt;&lt;br /&gt;Also sometimes when you are developing both the service and the client project, and you are not using the SNAPSHOT mechanism, it can be tedious to update the version of the server WAR artifact that gets started during the integration tests of the client project. Maven knows two &lt;a href="http://stackoverflow.com/questions/30571/how-do-i-tell-maven-to-use-the-latest-version-of-a-dependency"&gt;fixed keywords&lt;/a&gt; which you can use instead of specifying an exact version or a range. Use LATEST to download the latest snapshot or released version of a dependency from a repository. Use RELEASE to download the latest released version of a dependency from a dependency. Unfortunately you cannot use LATEST or RELEASE to start a WAR artifact of a dependency, if you are using the maven-jetty-plugin. This is because you specify the location of the WAR artifact as a full path inside the configuration - webApp element of the maven-jetty-plugin. The plugin does not use the syntax which is used to define the Maven dependencies. &lt;br /&gt;&lt;br /&gt;There is however a little trick. You use the maven-dependency-plugin, which uses the default syntax for dependencies and can understand LATEST and RELEASE, to copy the WAR artifact to a fixed location. While copying you should also rename the war file. This makes your life easier as you never have to adapt the path in the webApp element of the maven-jetty-plugin if the version changes. Here is an example:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1662983.js?file=pom-xml"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-8266983310593740912?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/8266983310593740912/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=8266983310593740912' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8266983310593740912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8266983310593740912'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2012/01/starting-dependency-war-artifact-using.html' title='Starting Dependency WAR Artifact using maven-jetty-plugin'/><author><name>Reikje</name><uri>http://www.blogger.com/profile/12381574441248297953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-UYKBf_C81Kg/TpMEsKVx45I/AAAAAAAAAAQ/pgbxe7zw7JU/s220/reik_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-50418648515349872</id><published>2012-01-20T02:50:00.000-08:00</published><updated>2012-01-20T02:51:22.742-08:00</updated><title type='text'>Test our new game</title><content type='html'>As some reader of this blog might know, I work for the EA studio of Playfish. Currently we are heading into the closed beta phase for a game which I helped to develop. This is a so called social game which is being played on Facebook. The backend of the game is developed by our team in Java. If you want to be one of the first ones to play the game and become a beta tester, fill in &lt;a href="https://www.surveymonkey.com/s/JMMFLHF"&gt;this application&lt;/a&gt;. I am not allowed to tell anything about the game at this point, just in response to &lt;a href="http://blog.games.com/2012/01/17/playfish-new-game-beta-test/"&gt;this comment&lt;/a&gt; - yes the game is different from Adventure World and Cloudforest Expedition and much more fun to play.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-50418648515349872?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/50418648515349872/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=50418648515349872' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/50418648515349872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/50418648515349872'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2012/01/test-our-new-game.html' title='Test our new game'/><author><name>Reikje</name><uri>http://www.blogger.com/profile/12381574441248297953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-UYKBf_C81Kg/TpMEsKVx45I/AAAAAAAAAAQ/pgbxe7zw7JU/s220/reik_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-4016957769298220989</id><published>2012-01-19T10:30:00.000-08:00</published><updated>2012-01-19T10:30:02.508-08:00</updated><title type='text'>Maybe I should have used a Lock here</title><content type='html'>Java 5 added some really nice classes in the &lt;b&gt;java.util.concurrent&lt;/b&gt; package. For instance there is the &lt;a href="http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ConcurrentMap.html"&gt;ConcurrentMap&lt;/a&gt; interface which allows you to add items to a Map if they are not already contained. The code you would normally write if the ConcurrentMap didn't exist, needs to do this as a atomic check-then-act sequence, if the Map is shared between Threads. With the ConcurrentMap interface you get all of this for free using the &lt;a href="http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ConcurrentMap.html#putIfAbsent(K, V)"&gt;putIfAbscent&lt;/a&gt; method.  &lt;br /&gt;&lt;br /&gt;I shoot myself in the foot today, with a small piece of code, which one of my unit tests was executing from a large number of Threads. The test was failing randomly, like 5% of the times. If you see tests randomly failing, it is often indicating a &lt;a href="http://docs.oracle.com/javase/1.5.0/docs/api/java/sql/Date.html"&gt;Date&lt;/a&gt; problem or a concurrency problem. Here is the class under test. Can you spot the problem?&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1641604.js?file=ChangeAwareDynamicProperty.java"&gt;&lt;/script&gt;&lt;br /&gt;In order to understand what the class does, you need to know what a DynamicProperty is. This is a class wrapping a value which comes from a remote source, i.e. over the Network. So instead of having fixed System properties, you would ask the remote source for the value. Then the value is cached for a couple of seconds and if expired you refresh the value. Now the ChangeAwareDynamicProperty is doing the same thing but additionally react to value changes. So every time the value is changed in the remote source, there is a costly operation that the ChangeAwareDynamicProperty needs to do. This code is not shown as it is not relevant. &lt;br /&gt;&lt;br /&gt;What is the ConcurrentMap for? Obviously the costly operation should only be done once per value change right? So a simple approach is to use locking. Let only 1 Thread at a time go into a critical section where the current value is compared to the new value. If a change is detected, run the costly operation. This would totally work but the throughput would be horrible. Especially when a Thread detects a value change while holding the Lock, running the costly operation would block all other Threads for a while. So my idea was to use a ConcurrentMap instead of a Lock.  If Threads detect a value change, they try to put the new value into a ConcurrentMap. By definition, only one Thread can put the new value into the Map. For this Thread the putIfAbscent call will return null. This Updater Thread will then run the costly operation, while other Threads will still return the previous value. Once the Updater Thread is finished, it will update the current value and remove the new current value from the ConcurrentMap. This is to prevent the Map from growing eternally. Sounds straightforward or?&lt;br /&gt;&lt;br /&gt;Well obviously there was a problem, as the unit test was failing every now and then. Every time the test was failing, I could see that it was trying to run the costly operation twice for the same changed value, as indicated by the following log statement:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1641604.js?file=build.log"&gt;&lt;/script&gt;&lt;br /&gt;I started to believe, that the putIfAbsent method was buggy and returned null even if the value was already present in the Map. I asked another co-worker to check my code, to see if he could spot a problem. After a few minutes we realized that the problem was in my code - as to be expected. Like I said, I don't want the Map to grow forever. So the Updater Thread is removing the new changed value after the costly operation is finished. The problem is that another Thread could be waiting for the CPU in line 14. This is the line that invokes putIfAbscent. So once the Updater Thread is done, and the waiting Thread gets active, it will actually do exactly the same work again. Not good!&lt;br /&gt;&lt;br /&gt;Our immediate solution was to not remove the Map entry after the Update Thread is finished. What we do instead is to remove the old value from the Map before reassigning the new changed value into currentVersion. As the Map will never contain more than 1 entry, it is always possible that a costly operation will be run again, even if a value has already been handled. This change only fixes the problem, that a single value change can trigger a consecutive execution of the costly operation.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1641604.js?file=FixedChangeAwareDynamicProperty.java"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-4016957769298220989?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/4016957769298220989/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=4016957769298220989' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4016957769298220989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4016957769298220989'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2012/01/maybe-i-should-have-used-lock-here.html' title='Maybe I should have used a Lock here'/><author><name>Reikje</name><uri>http://www.blogger.com/profile/12381574441248297953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-UYKBf_C81Kg/TpMEsKVx45I/AAAAAAAAAAQ/pgbxe7zw7JU/s220/reik_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-5388261368102304875</id><published>2012-01-02T23:58:00.000-08:00</published><updated>2012-01-03T00:00:51.362-08:00</updated><title type='text'>git clone and remote end hung up unexpectedly</title><content type='html'>Yesterday morning before going to work, I created a git repository for a new hobby project of mine. I have done this a couple of time before and the git hosting provider of choice is &lt;a href="http://offers.assembla.com/free-git-hosting/"&gt;Assembla&lt;/a&gt;. They are offering private git repositories and I never had any trouble in the past.&lt;br /&gt;&lt;br /&gt;After creating the repository, I tried to clone it. I need to use sudo because I clone into a directory which is not owned by me. I am using the /web directory (or rather the directories under /web) directly as docroot for Apache.&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;sudo git clone git@git.assembla.com:my-new-repository.git&lt;br /&gt;Initialized empty Git repository in /web/my-new-repository/.git/&lt;br /&gt;Permission denied (publickey).&lt;br /&gt;fatal: The remote end hung up unexpectedly&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see, something went wrong. I verified that my public ssh key was added to my Assembla account and it was. I decided it was a problem on the Assembla side and decided to try again this morning but the problem was still there. I created another git repository over at &lt;a href="https://bitbucket.org/"&gt;Bitbucket&lt;/a&gt; and tried again - same problem, wtf. Finally I had the great idea to try and clone the repository into my user directory and voila it worked. So it turned out that doing sudo and ssh public/private key authentication with git does not work. There is a good explanation about it on &lt;a href="http://help.github.com/ssh-issues/"&gt;github&lt;/a&gt;.&lt;blockquote&gt;If you are using sudo with git commands (e.g. using sudo git clone because you are deploying to a root-owned folder), ensure that you also generated the key using sudo. Otherwise, you will have generated a key for your current user, but when you are doing sudo git, you are actually the root user – thus, the keys will not match. &lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-5388261368102304875?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/5388261368102304875/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=5388261368102304875' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5388261368102304875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5388261368102304875'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2012/01/git-clone-and-remote-end-hung-up.html' title='git clone and remote end hung up unexpectedly'/><author><name>Reikje</name><uri>http://www.blogger.com/profile/12381574441248297953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-UYKBf_C81Kg/TpMEsKVx45I/AAAAAAAAAAQ/pgbxe7zw7JU/s220/reik_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-7140035902149334391</id><published>2011-12-20T06:53:00.000-08:00</published><updated>2011-12-23T01:54:49.185-08:00</updated><title type='text'>Using Reference Maps for Caches and Listeners</title><content type='html'>A while ago I wrote a &lt;a href="http://javasplitter.blogspot.com/2011/08/lost-virginity-weakhashmap-first-timer.html"&gt;blog post&lt;/a&gt; about the WeakHashMap. It then turned out that the WeakHashMap was not the optimal choice for that particular use case and I proposed a different solution. To make this a bit more seizable, I decided to implement a post a full code example. Let me again describe the use case.&lt;br /&gt;&lt;br /&gt;Let's say you have a class wrapping some sort of event. Let's give the event class a name, write a Java interface and call it Auditable. Each Auditable subclass must implement two methods: validate and process. There is a invoker class called AuditableInvoker which receives a collection of Auditable's and invokes validate and process on each one of them. So far so good.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=auditable.java"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=AuditableInvoker.java"&gt;&lt;/script&gt;&lt;br /&gt;As an example, let's implement two Auditable subclasses which are pretty stupid. SleepingAuditable will just hold the current Thread for a few milliseconds. IteratingAuditable will run a small loop in it's validate and process methods.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=IteratingAuditable.java"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=SleepingAuditable.java"&gt;&lt;/script&gt;&lt;br /&gt;In addition to that, there is a requirement that you need to know the execution time of the validate and process method in each Auditable subclass. Fortunately you can add listeners to AuditableInvoker. So all you have to do is to write a listener that measures the execution times. The listener need to start a stop watch before validate or process is invoked and stop this very stop watch after process and validate are finished. Once they are finished, the execution time can be computed and kept in a helper class that we call the StatsCollector. To keep things simple, our UnboundedStatsCollector will only increment a counter, completely ignoring the execution times.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=AuditableLifecycleListener.java"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=StatsCollector.java"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=UnboundedStatsCollector.java"&gt;&lt;/script&gt;&lt;br /&gt;The tricky part here is that you need to use the same stop watch before and after the invocations of an Auditable. A good use case for a map using weak referenced keys and object identity for comparison. Once an Auditable subclass has finished it's lifecycle and is no longer referenced somewhere else in the code, the garbage collection can collect the Auditable as well as the associated stop watch. This will prevent the Map from growing indefinitely. So here is a implementation using a ReferenceIdentityMap from the commons-collections project.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=ExecutionTimingAuditableLifecycleListener.java"&gt;&lt;/script&gt;&lt;br /&gt;To verify that we really see the expected behavior, I have written a unit test that is stressing the ExecutionTimingAuditableLifecycleListener using multiple Threads. In this unit test I am re-using a class called MultithreadedStressTester which I stole from Nat Pryze's book "&lt;a href="http://www.growing-object-oriented-software.com/"&gt;Growing Object Oriented Software guided by Tests&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=MultithreadedStressTester.java"&gt;&lt;/script&gt;&lt;br /&gt;The ExecutionTimingAuditableLifecycleListenerTest uses the MultithreadedStressTester to send a bunch of Threads over to the ExecutionTimingAuditableLifecycleListener, verifying that each invocation is properly timed using the ReferenceIdentityMap under the hood.&lt;br /&gt;&lt;script src="https://gist.github.com/1513718.js?file=ExecutionTimingAuditableLifecycleListenerTest.java"&gt;&lt;/script&gt;&lt;br /&gt;Finally, if you want to use &lt;a href="http://code.google.com/p/guava-libraries/"&gt;google-guava&lt;/a&gt; instead of commons-collections, you can also use a LoadingCache with weak keys instead of the ReferenceIdentityMap. Here is a version of the ExecutionTimingAuditableLifecycleListener using google-guava.&lt;br /&gt;&lt;script src="https://gist.github.com/1513758.js?file=ExecutionTimingAuditableLifecycleListenerGuava.java"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-7140035902149334391?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/7140035902149334391/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=7140035902149334391' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7140035902149334391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7140035902149334391'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/12/using-reference-maps-for-caches-and.html' title='Using Reference Maps for Caches and Listeners'/><author><name>Reikje</name><uri>http://www.blogger.com/profile/12381574441248297953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-UYKBf_C81Kg/TpMEsKVx45I/AAAAAAAAAAQ/pgbxe7zw7JU/s220/reik_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-6646630337407163027</id><published>2011-10-10T08:05:00.000-07:00</published><updated>2012-01-21T07:10:01.357-08:00</updated><title type='text'>The Static Final Inline Trap</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-SASoPl34uRY/TpMJj0wLnlI/AAAAAAAAAAw/Z9y6XVaq8sk/s1600/screenshot_no_flash.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="175" src="http://2.bp.blogspot.com/-SASoPl34uRY/TpMJj0wLnlI/AAAAAAAAAAw/Z9y6XVaq8sk/s320/screenshot_no_flash.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Last week I was chasing a very interesting problem which we could only resolve with the help of a colleague. One of our testers found a bug in the current game that we are developing. If the user doesn't  have Flashplayer installed, the No-Flash image is not shown properly. All code related to this, is pulled in from shared libraries which our project depends on. In the screen shot you will see something that looks like magic. There is a method which populates and returns a Map. Amongst others, one key called noflash_image_url is defining the location of the No-Flash image. In the debugger pane to the lower right, you can see the static final constant NOFLASH_IMAGE_URL evaluating to the correct value. This value is the correct location of the No-Flash image.&lt;br /&gt;&lt;br /&gt;The strange thing however, is that the Map contains another (wrong) value, even though the Map value is also set using the same  static final constant NOFLASH_IMAGE_URL. You can see that in the lower middle pane of the screen shot. So for some strange reason, the constant is evaluating to both the correct and the wrong value. I guess we could call it semi-constant in this particular case.&lt;br /&gt;&lt;br /&gt;Anytime you see something weird like this, your first thought should be class loading problem. Based on my experience, the weirdest problems are often rooted in class loading. However this problem is of a different kind. For a better understanding, you have to know that the Class which initializes the Map is a dependency that ours project pulls in from a Maven dependency to library A. This library A then depends on another (transient) Maven library B which contains the NOFLASH_IMAGE_URL constant. Our project also defines a direct Maven dependency to library B. This is needed because library B changes quite often and we always want the latest version of B in our project. The latest version of B does contain the correct value the No-Flash image in the NOFLASH_IMAGE_URL constant. So one might think, that the Maven dependency resolution mechanism pulled in an old version of library B, but this wasn't the case.&lt;br /&gt;&lt;br /&gt;A colleague then hinted me in the right direction. The Java compiler often does something called inlining for access to a static final variable. This is an optimization as the value of a final variable cannot change after it has been assigned. To verify this we ran the Java class file disassembler (javap) over the class file in library A.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;   78: pop&lt;br /&gt;   79: aload_2&lt;br /&gt;   80: ldc #108; //String noflash_image_url&lt;br /&gt;   82: ldc #109; //String http://static.playfish.com/shared/noflash.jpg&lt;br /&gt;   84: invokeinterface #100,  3; //InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see, the compiler is really inlining the value in places where we, by running a debugger over the source code, expect an evaluation of the static final variable at runtime. This is definitely something you have to be aware of. We can fix this, by re-compiling library A against a newer version of library B, which will inline the correct No-Flash image. Another option to prevent inlining would be to declare the constant like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;  public static final String NOFLASH_IMAGE_URL = new String ("...");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But then this might be really hard to understand for other developers and they might revert this change to a String literal if not properly documented. &lt;strong&gt;Update:&lt;/strong&gt; I just realized that this problem is featured as Puzzle 93: Class Warfare in the &lt;a href="http://www.javapuzzlers.com/contents.html"&gt;Java Puzzlers&lt;/a&gt; book from Joshua Bloch. The compiler will inline all constant variables, such as Primitives and Strings which are initialized with a constant expression. Surprisingly, null is not inlined, neither are Java 5 enums.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-6646630337407163027?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/6646630337407163027/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=6646630337407163027' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6646630337407163027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6646630337407163027'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/10/static-final-inline-trap.html' title='The Static Final Inline Trap'/><author><name>Reikje</name><uri>http://www.blogger.com/profile/12381574441248297953</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/-UYKBf_C81Kg/TpMEsKVx45I/AAAAAAAAAAQ/pgbxe7zw7JU/s220/reik_photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-SASoPl34uRY/TpMJj0wLnlI/AAAAAAAAAAw/Z9y6XVaq8sk/s72-c/screenshot_no_flash.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-5447526453880169377</id><published>2011-08-19T08:00:00.000-07:00</published><updated>2011-11-22T05:18:28.696-08:00</updated><title type='text'>Lost Virginity: WeakHashMap first timer</title><content type='html'>It was almost three years ago at &lt;a href="http://www.oopsla.org/oopsla2008/"&gt;OOPSLA in Nashville&lt;/a&gt;, where I heard about the &lt;a href="http://download.oracle.com/javase/6/docs/api/java/util/WeakHashMap.html"&gt;WeakHashMap&lt;/a&gt; for the first time. The class is quite useful if you need a Map implementation, where the keys are compared using their memory references and not using equals. Another important property of the WeakHashMap is that the Map entries are removed "automagically" if no other object (than the WeakHashMap itself) holds a reference to the key object. The garbage collection will in that case remove Map entry and collect the key.&lt;br /&gt;&lt;br /&gt;In the past 3 years I never used the WeakHashMap in any project. That changed yesterday. In the game that we are currently developing, we are using a mechanism where the game client is sending game events to the server. The server will then evaluate the game events and alter the users in memory before their state is made persistent in the database. Here is an example:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;public interface GameEvent {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;&lt;br /&gt;     * Subclasses may implement this to run validation logic, before the GameEvent is processed.&lt;br /&gt;&lt;br /&gt;     *&lt;br /&gt;&lt;br /&gt;     * @param user the {@link User} to apply this {@link GameEvent} on&lt;br /&gt;&lt;br /&gt;     * @return {@link AuditResult} never &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt;&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    AuditResult validate(User user);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;&lt;br /&gt;     * Subclasses may implement this to run implementation specific logic, potentially altering the&lt;br /&gt;&lt;br /&gt;     * given {@link User}. &lt;br /&gt;&lt;br /&gt;     *&lt;br /&gt;&lt;br /&gt;     * @param user the {@link User} to apply this {@link GameEvent} on&lt;br /&gt;&lt;br /&gt;     * @return {@link AuditResult} never &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt;&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    AuditResult process(User user);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class ConsumeFood implements GameEvent {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    private final int amount;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public ConsumeFood(final int amount) {&lt;br /&gt;&lt;br /&gt;        this.amount = amount;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public AuditResult validate(final User user) {&lt;br /&gt;&lt;br /&gt;        if (user.getFood() &amp;lt; this.amount) {&lt;br /&gt;&lt;br /&gt;            return AuditResult("User doesn't have this amount of food.");&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return AuditResult.SUCCESS;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public AuditResult process(final User user) {&lt;br /&gt;&lt;br /&gt;        user.addEnergy(this.amount);&lt;br /&gt;&lt;br /&gt;        user.subtractFood(this.amount);&lt;br /&gt;&lt;br /&gt;        return AuditResult.SUCCESS;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Once the game client sends us the ConsumeFood game event, we subtract food from the player and add energy instead. We also have a wrapper class around a collection of game events and the execution logic looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;public class GameEvents {&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;    .. other methods ...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    protected AuditResult process(final User user, final GameEvent change) {&lt;br /&gt;&lt;br /&gt;        final AuditResult validateResult = change.validate(user);&lt;br /&gt;&lt;br /&gt;        if (validateResult == AuditResult.SUCCESS) {&lt;br /&gt;&lt;br /&gt;            return change.process(user);&lt;br /&gt;&lt;br /&gt;        } else {&lt;br /&gt;&lt;br /&gt;            return validateResult;&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;First we validate that we can apply the game event, then we process the event and alter the player. Since the number of different game events is continuously growing and growing, I thought it might be useful to measure the execution time of the validate and the process method in each game event. The way I implemented this a while ago, was through delegation. I added a wrapper class which was wrapping the real game event and timing the validate and process method: &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;import org.springframework.util.StopWatch;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public final class TimingGameEvent implements GameEvent {&lt;br /&gt;&lt;br /&gt;    private final GameEvent gameEvent;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public TimingGameEvent(final GameEvent gameEvent) {&lt;br /&gt;&lt;br /&gt;        this.gameEvent = gameEvent;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;&lt;br /&gt;     * Delegates the processing to the encapsulated {@link GameEvent}. Uses a {@link StopWatch} to time the&lt;br /&gt;&lt;br /&gt;     * execution time.&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public AuditResult process(final User user) {&lt;br /&gt;&lt;br /&gt;        final StopWatch stopWatch = new StopWatch("process-stop-watch");&lt;br /&gt;&lt;br /&gt;        stopWatch.start();&lt;br /&gt;&lt;br /&gt;        try {&lt;br /&gt;&lt;br /&gt;            return this.gameEvent.process(user);&lt;br /&gt;&lt;br /&gt;        } finally {&lt;br /&gt;&lt;br /&gt;            stopWatch.stop();&lt;br /&gt;&lt;br /&gt;            this.processTimeInMs = stopWatch.getLastTaskTimeMillis();&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;&lt;br /&gt;     * Delegates the validation to the encapsulated {@link GameEvent}. Uses a {@link StopWatch} to time the&lt;br /&gt;&lt;br /&gt;     * execution time.&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public AuditResult validate(final User user) {&lt;br /&gt;&lt;br /&gt;        final StopWatch stopWatch = new StopWatch("validate-stop-watch");&lt;br /&gt;&lt;br /&gt;        stopWatch.start();&lt;br /&gt;&lt;br /&gt;        try {&lt;br /&gt;&lt;br /&gt;            return this.gameEvent.validate(user);&lt;br /&gt;&lt;br /&gt;        } finally {&lt;br /&gt;&lt;br /&gt;            stopWatch.stop();&lt;br /&gt;&lt;br /&gt;            this.validationTimeInMs = stopWatch.getLastTaskTimeMillis();&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This worked well. However, this week we got another requirement from business. We needed to implement some sort of gameplay recorder. Each game event that the server receives must be recorded, so we can replay these events later. My first idea was to add another wrapper around the already existing TimingGameEvent wrapper class but this would have made it difficult to serialize the real game event to a File. Yes we decided to serialize to and deserialize from a String, which is stored in a plain textfile and each line represents one game event. I discarded the idea to add other wrappers around the game event and suggested a refactoring. Instead of using delegating wrappers, why not use a listener mechanism. Each listener would be notified before and after execution of the validate and the process method in each game event. Listeners could register themselves and it would be easier to extend in the future. On the negative side, of course measuring the execution times would not be as accurate anymore, as there could be other listeners which want to be notified before the game event is validated and processed. This however was not a big issue, since we were not interested in the exact time in milliseconds but rather in long running methods of a couple of seconds. I also added a mechanism to make sure the execution timing listener would get notified just before the game event method was executed and right after it was returning. More on that later.&lt;br /&gt;&lt;br /&gt;Here is the listener interface I came up with:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;public interface GameEventLifecycleListener {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    void onValidationStart(final User user, final GameEvent gameEvent);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    void onValidationFinish(final User user, final GameEvent gameEvent, &lt;br /&gt;&lt;br /&gt;             final AuditResult auditResult);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    void onProcessStart(final User user, final GameEvent gameEvent);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    void onProcessFinish(final User user, final GameEvent gameEvent, &lt;br /&gt;&lt;br /&gt;             final AuditResult auditResult);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Refactoring the TimingGameEvent class from above to a TimingGameEventLifecycleListener wasn't straight forward. Each invocation of the validate or the process method will now result in two listener notifications. So how do you know when to “press” stop on the StopWatch?&lt;br /&gt;&lt;br /&gt;This is where the WeakHashMap comes in handy. Remember that each game event is going through the same chain? First onValidationStart is called, then onValidationFinish, onProcessStart and finally onProcessFinish. So the Listener could maintain a Map of all event implemented using a WeakHashMap. The first notification callback will add the game event to this Map. Subsequent notifications can assume that the game event will be present in the WeakHashMap. After the game event has passed through the chain and no object is referencing the game event anymore, it will automatically be removed from the WeakHashMap. Here is a part of the  TimingGameEventLifecycleListener which will show you the concept.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;import org.springframework.core.Ordered;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class TimingGameEventLifecycleListener extends AbstractGameEventLifecycleListener {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;&lt;br /&gt;     * By default the WeakHashMap is not thread-safe, so it needs to be wrapped in a synchronizedMap. This however&lt;br /&gt;&lt;br /&gt;     * is quite slow, hence the ExecutionTimingGameEventLifecycleListener should not be running in production&lt;br /&gt;&lt;br /&gt;     * all the time.&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    private final Map&amp;lt;GameEvent, TimedExecution&amp;gt; timedExecutions = Collections.synchronizedMap(&lt;br /&gt;&lt;br /&gt;        new WeakHashMap&amp;lt;GameEvent, TimedExecution&amp;gt;()&lt;br /&gt;&lt;br /&gt;    );&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public void onValidationStart(final User user, final GameEvent gameEvent) {&lt;br /&gt;&lt;br /&gt;        final TimedExecution timeValidation = &lt;br /&gt;&lt;br /&gt;          new TimedExecution(gameEvent.getClass());&lt;br /&gt;&lt;br /&gt;        this.timedExecutions.put(gameEvent, timeValidation);&lt;br /&gt;&lt;br /&gt;        // other stuff&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public void onValidationFinish(final User user, final GameEvent gameEvent, &lt;br /&gt;&lt;br /&gt;          final AuditResult auditResult) {&lt;br /&gt;&lt;br /&gt;        final TimedExecution timeValidation = this.timedExecutions.get(gameEvent);&lt;br /&gt;&lt;br /&gt;        if (timeValidation != null) {&lt;br /&gt;&lt;br /&gt;     timeValidation.stopTimer();&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    ... other notification methods ...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public int getOrder() {&lt;br /&gt;&lt;br /&gt;        return Ordered.HIGHEST_PRECEDENCE;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So the WeakHashMap can be nice in the role of a cache between different Listener methods. Another thing you may notice in the code above, is that the Listener is deriving from AbstractGameEventLifecycleListener instead of implementing GameEventLifecycleListener. I added a abstract base class for two reasons. First it is better to provide empty default implementations of all notification methods. Concrete Listeners like the TimingGameEventLifecycleListener can then only overwrite the methods they are interested in (okay in this case we are interested in all four notification methods, but other Listeners might not be). The second reason is that we want to force the Listeners to be in a specific order. Every Listener can for himself decide "how important" he is by implementing the &lt;span style="font-style: italic;"&gt;getOrder()&lt;/span&gt; method defined in the &lt;a href="http://static.springsource.org/spring/docs/3.0.5.RELEASE/api/org/springframework/core/Ordered.html"&gt;org.springframework.core.Ordered&lt;/a&gt; interface which the AbstractGameEventLifecycleListener is implementing. Normally this interface is used by Spring to apply an order to &lt;a href="http://www.eclipse.org/aspectj/"&gt;Aspects&lt;/a&gt;. Though you might choose to keep your domain clean of Spring framework classes. Here is the AbstractGameEventLifecycleListener:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;public class GameEvents {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    private final GameEvent[] events;&lt;br /&gt;&lt;br /&gt;    private final NavigableSet&amp;lt;AbstractGameEventLifecycleListener&amp;gt; listeners;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public void addListeners(final&lt;br /&gt;&lt;br /&gt;          Collection&amp;lt;AbstractGameEventLifecycleListener&amp;gt; listeners) {&lt;br /&gt;&lt;br /&gt;        this.listeners.addAll(listeners);&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public GameEvents(final GameEvent[] events) {&lt;br /&gt;&lt;br /&gt;        final int length = events == null ? 0 : events.length;&lt;br /&gt;&lt;br /&gt;        this.listeners = new TreeSet&amp;lt;AbstractGameEventLifecycleListener&amp;gt;();&lt;br /&gt;&lt;br /&gt;        this.events = new GameEvent[length];&lt;br /&gt;&lt;br /&gt;        if (length &amp;gt; 0) {&lt;br /&gt;&lt;br /&gt;            System.arraycopy(events, 0, this.events, 0, length);&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    // other methods&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    protected AuditResult process(final User user, final GameEvent gameEvent) {&lt;br /&gt;&lt;br /&gt;        final AuditResult validateResult = gameEvent.validate(user);&lt;br /&gt;&lt;br /&gt;        if (validateResult == AuditResult.SUCCESS) {&lt;br /&gt;&lt;br /&gt;            return gameEvent.process(user);&lt;br /&gt;&lt;br /&gt;        } else {&lt;br /&gt;&lt;br /&gt;            return validateResult;&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    } &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;&lt;br /&gt;     * Runs the {@link GameEvent#validate(User)} function of the given &lt;br /&gt;&lt;br /&gt;     * {@code gameEvent}, notifying all {@link AbstractGameEventLifecycleListener}s&lt;br /&gt;&lt;br /&gt;     * before and after. The listener having the highest &lt;br /&gt;&lt;br /&gt;     * precidence is notified last before and first after the validation method.&lt;br /&gt;&lt;br /&gt;     * @param user the {@link User} to validate the game event for&lt;br /&gt;&lt;br /&gt;     * @param gameEvent the gameEvent to validate&lt;br /&gt;&lt;br /&gt;     * @return the result of the validation&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    AuditResult runValidate(final User user, final GameEvent gameEvent) {&lt;br /&gt;&lt;br /&gt;        for (Iterator&amp;lt;AbstractGameEventLifecycleListener&amp;gt; &lt;br /&gt;&lt;br /&gt;            iterator = this.listeners.descendingIterator(); &lt;br /&gt;&lt;br /&gt;  iterator.hasNext(); ) {&lt;br /&gt;&lt;br /&gt;            final AbstractGameEventLifecycleListener listener = iterator.next();&lt;br /&gt;&lt;br /&gt;            listener.onValidationStart(user, gameEvent);&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        final AuditResult validateResult = gameEvent.validate(user);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        for (final AbstractGameEventLifecycleListener listener : this.listeners) {&lt;br /&gt;&lt;br /&gt;            listener.onValidationFinish(user, gameEvent, validateResult);&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        return validateResult;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;&lt;br /&gt;     * Runs the {@link GameEvent#process(User)} function of the given &lt;br /&gt;&lt;br /&gt;     * {@code gameEvent}, notifying all {@link AbstractGameEventLifecycleListener}s&lt;br /&gt;&lt;br /&gt;     * before and after. The listener having the highest &lt;br /&gt;&lt;br /&gt;     * precedence is notified last before and first after the validation method.&lt;br /&gt;&lt;br /&gt;     * @param user the {@link User} to process the gameEvent for&lt;br /&gt;&lt;br /&gt;     * @param gameEvent the audit gameEvent to process&lt;br /&gt;&lt;br /&gt;     * @return the result of processing the gameEvent&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    AuditResult runProcess(final User user, final GameEvent gameEvent) {&lt;br /&gt;&lt;br /&gt;        for (Iterator&amp;lt;AbstractGameEventLifecycleListener&amp;gt; iterator =&lt;br /&gt;&lt;br /&gt;             this.listeners.descendingIterator(); &lt;br /&gt;&lt;br /&gt;  iterator.hasNext(); ) {&lt;br /&gt;&lt;br /&gt;            final AbstractGameEventLifecycleListener listener = iterator.next();&lt;br /&gt;&lt;br /&gt;            listener.onProcessStart(user, gameEvent);&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        final AuditResult validateResult = gameEvent.process(user);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        for (final AbstractGameEventLifecycleListener listener : this.listeners) {&lt;br /&gt;&lt;br /&gt;            listener.onProcessFinish(user, gameEvent, validateResult);&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        return validateResult;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I said earlier, it is desirable to notify the TimingGameEventLifecycleListener last before validation starts and first after it finishes (to get  more accurate timings). The GameEvents class, which is  notifying the listeners, will honor the order using a &lt;a href="http://download.oracle.com/javase/6/docs/api/java/util/NavigableSet.html"&gt;NavigableSet&lt;/a&gt; that can be iterated in forward and backward order. Take a look at the updated version of the GameEvents class to see how it is implemented:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;public abstract class AbstractGameEventLifecycleListener &lt;br /&gt;&lt;br /&gt; implements GameEventLifecycleListener, Ordered, Comparable&amp;lt;GameEventLifecycleListener&amp;gt; {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public void onValidationStart(final User user, final GameEvent gameEvent) { }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public void onValidationFinish(final User user, final GameEvent gameEvent, &lt;br /&gt;&lt;br /&gt;       final AuditResult auditResult) { }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public void onProcessStart(final User user, final GameEvent gameEvent) { }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public void onProcessFinish(final User user, final GameEvent gameEvent, &lt;br /&gt;&lt;br /&gt;       final AuditResult auditResult) { }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;&lt;br /&gt;     * Compares the order of the two {@link GameEventLifecycleListener}s &lt;br /&gt;&lt;br /&gt;     * using {@link Ordered}.&lt;br /&gt;&lt;br /&gt;     * @param other another {@link GameEventLifecycleListener}&lt;br /&gt;&lt;br /&gt;     * @return int&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;&lt;br /&gt;    public int compareTo(final GameEventLifecycleListener other) {&lt;br /&gt;&lt;br /&gt;        return Integer.valueOf(this.getOrder()).compareTo(other.getOrder());&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;One thing I wasn't able to come up with, was a good unit test to verify that the WeakHashMap is indeed not holding key references forever. This is extremely difficult to test as it involves testing for garbage collection and no, I am not suggesting running System.gc() from your test. I found something similar on &lt;a href="http://blogs.oracle.com/tor/entry/leak_unit_tests"&gt;this blog post&lt;/a&gt;. Apparently the Netbeans API offers something called assertGC(..) but it wasn't really fitting for my use case. So if you have a good suggestion how to test the behavior of a WeakHashMap, I am happy to hear it.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&lt;b&gt;* UPDATE * UPDATE *&lt;/b&gt;&lt;/span&gt; After a few weeks running this the WeakHashMap and seeing some weird errors in the logs every now and then, I realized it's not the right Map implementation to use. The WeakHashMap is not what you want to use here, because the keys are not really compared using object identity. Initially I thought this was the case, when reading through the Javadoc of the WeakHashMap. What you really want is a hybrid Map, that combines the WeakHashMap with a IdentityHashMap. This hybrid Map will compare the keys based on objects identity and also use weak key references. The bad news is, there is no such map in the JDK (Java 6 at least). The good news is, there is a &lt;a href="http://docs.jboss.org/hibernate/search/3.4/api/org/hibernate/search/util/WeakIdentityHashMap.html"&gt;WeakIdentityHashMap&lt;/a&gt; in the Hibernate Search project and a &lt;a href="http://commons.apache.org/collections/api-release/org/apache/commons/collections/map/ReferenceIdentityMap.html"&gt;ReferenceIdentityMap&lt;/a&gt; in the Commons Collections Project which can be used.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-5447526453880169377?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/5447526453880169377/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=5447526453880169377' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5447526453880169377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5447526453880169377'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/08/lost-virginity-weakhashmap-first-timer.html' title='Lost Virginity: WeakHashMap first timer'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-3465029876661326191</id><published>2011-08-19T02:15:00.000-07:00</published><updated>2011-08-19T02:26:30.140-07:00</updated><title type='text'>Testing JMX between two Web Applications using Maven</title><content type='html'>The problem: you have two web applications and each is developed inside a separate Maven module. You need to communicate from one web application to the other and you don't want to implement a service but use JMX instead. This is a scenario we are having here at the moment. The first web application (application A) contains the game server logic of our new game. The second web application (application B) contains a debug tool which we will not deploy into production. I have selected JMX for the communication, mainly because I didn't wanted to add another technology and we are already using JMX in the first application. Both web application are Spring powered.&lt;br /&gt;&lt;br /&gt;First here is a nice &lt;a href="http://static.springsource.org/spring/docs/3.0.x/reference/jmx.html"&gt;Spring feature&lt;/a&gt;, which completely hides the JMX complexity for the client application behind a proxy.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;    &amp;lt;bean id="clientConnector" class="org.springframework.jmx.support.MBeanServerConnectionFactoryBean"&amp;gt;&lt;br /&gt;        &amp;lt;property name="serviceUrl" value="[SERVICE_URL]"/&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;bean id="gameplayRecordable" class="org.springframework.jmx.access.MBeanProxyFactoryBean"&amp;gt;&lt;br /&gt;        &amp;lt;property name="objectName" value="[MBEAN]" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="proxyInterface" value="any.java.Interface" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="server" ref="clientConnector" /&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;First you define a client connector which connects you to the RMI server port of the other web application. Then you define a &lt;a href="http://static.springsource.org/spring/docs/3.0.5.RELEASE/api/org/springframework/jmx/access/MBeanProxyFactoryBean.html"&gt;MBeanProxyFactoryBean&lt;/a&gt; using this client connector. The &lt;span style="font-weight:bold;"&gt;objectName&lt;/span&gt; must be the name of your MBean inside the MBean container. If you are not sure about the name, use jconsole to connect to the process of the first web application and look it up. Another important property of the MBeanProxyFactoryBean is the &lt;span style="font-weight:bold;"&gt;proxyInterface&lt;/span&gt;. This is an interface that the proxy will implement. The proxy will try to map each method call on that interface in application B to a JMX call in application A. I can really recommend to share the same Interface in both applications as it makes stuff really simple.&lt;br /&gt;&lt;br /&gt;This was simple so far. Now lets say you want to write an integration test to automatically test the whole shebang. The test should start up a JMX enabled Jetty from Maven. This Jetty instance should explode the war file of application A (hosting the MBean you want to invoke). Once Jetty is up, the test should execute, connect to application A via the MBeanProxyFactoryBean and validate the results. First lets enable remote JMX access in the configuration of the &lt;a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin"&gt;maven-jetty-plugin&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;profiles&amp;gt;&lt;br /&gt;&amp;lt;profile&amp;gt;&lt;br /&gt;&amp;lt;id&amp;gt;itest&amp;lt;/id&amp;gt;&lt;br /&gt;&amp;lt;build&amp;gt;&lt;br /&gt;&amp;lt;plugins&amp;gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;&amp;lt;groupId&amp;gt;org.mortbay.jetty&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;maven-jetty-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;version&amp;gt;${version.jetty.plugin}&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;    &amp;lt;stopKey&amp;gt;stop_key&amp;lt;/stopKey&amp;gt;&lt;br /&gt;    &amp;lt;stopPort&amp;gt;9999&amp;lt;/stopPort&amp;gt;&lt;br /&gt;    &amp;lt;contextPath&amp;gt;/&amp;lt;/contextPath&amp;gt;&lt;br /&gt;    &amp;lt;webApp&amp;gt;&lt;br /&gt;        ${settings.localRepository}/com/package/../../your.war&lt;br /&gt;    &amp;lt;/webApp&amp;gt;&lt;br /&gt;    &amp;lt;jettyConfig&amp;gt;&lt;br /&gt;${basedir}/src/test/etc/jetty-jmx.xml&amp;lt;/jettyConfig&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt;    &amp;lt;execution&amp;gt;&lt;br /&gt;        &amp;lt;id&amp;gt;start-jetty&amp;lt;/id&amp;gt;&lt;br /&gt;        &amp;lt;phase&amp;gt;pre-integration-test&amp;lt;/phase&amp;gt;&lt;br /&gt;        &amp;lt;goals&amp;gt;&lt;br /&gt;            &amp;lt;goal&amp;gt;deploy-war&amp;lt;/goal&amp;gt;&lt;br /&gt;        &amp;lt;/goals&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;            &amp;lt;daemon&amp;gt;true&amp;lt;/daemon&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;    &amp;lt;/execution&amp;gt;&lt;br /&gt;    &amp;lt;execution&amp;gt;&lt;br /&gt;        &amp;lt;id&amp;gt;stop-jetty&amp;lt;/id&amp;gt;&lt;br /&gt;        &amp;lt;phase&amp;gt;prepare-package&amp;lt;/phase&amp;gt;&lt;br /&gt;        &amp;lt;goals&amp;gt;&lt;br /&gt;            &amp;lt;goal&amp;gt;stop&amp;lt;/goal&amp;gt;&lt;br /&gt;        &amp;lt;/goals&amp;gt;&lt;br /&gt;    &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&amp;lt;/plugins&amp;gt;&lt;br /&gt;&amp;lt;/build&amp;gt;&lt;br /&gt;&amp;lt;/profile&amp;gt;&lt;br /&gt;&amp;lt;/profiles&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see, this plugin configuration is done in a Maven profile as we are defining this for application B which also has its own Jetty configuration. The important piece is the &lt;a href="http://wiki.eclipse.org/Jetty/Tutorial/JMX"&gt;jettyConfig element&lt;/a&gt; which points to a jetty-jmx.xml file. To get this file, &lt;a href="http://dist.codehaus.org/jetty/"&gt;download the Jetty container&lt;/a&gt; that has the same version as your maven-jetty-plugin. For instance is you use version 6.1.26 of the maven-jetty-plugin, make sure you download jetty-6.1.26 from the codehaus download page. If you are using the the new &lt;a href="http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin"&gt;jetty-maven-plugin&lt;/a&gt; and Jetty 7 or 8, you need to download the &lt;a href="http://download.eclipse.org/jetty/"&gt;Jetty container from Eclipse&lt;/a&gt;. The configuration is the same for the maven-jetty-plugin and the  jetty-maven-plugin. Just make sure you download the jetty-jmx.xml file from the right Jetty container as they are different. You &lt;a href="http://stackoverflow.com/questions/5297462/enable-remote-jmx-on-jetty"&gt;don't need&lt;/a&gt; to specify any additional system properties like -Dcom.sun.management.jmxremote, -Dcom.sun.management.jmxremote.ssl, -Dcom.sun.management.jmxremote.authenticate or -Dcom.sun.management.jmxremote.port.&lt;br /&gt;&lt;br /&gt;Once the jetty-jmx.xml is downloaded, put in somewhere inside your Maven module where it does not get packaged into the module artifact. In the example above you can see that we have the jetty-jmx.xml file in src/test/etc but any other location will do. Open the file and enable remote JMX access via RMI. In the Jetty 6 based jetty-jmx.xml file these elements should be commented in:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;    &amp;lt;Call id="rmiRegistry" class="java.rmi.registry.LocateRegistry" name="createRegistry"&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="int"&amp;gt;2099&amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;/Call&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;Call id="jmxConnectorServer" class="javax.management.remote.JMXConnectorServerFactory"&lt;br /&gt;          name="newJMXConnectorServer"&amp;gt;&lt;br /&gt;        &amp;lt;Arg&amp;gt;&lt;br /&gt;            &amp;lt;New class="javax.management.remote.JMXServiceURL"&amp;gt;&lt;br /&gt;                &amp;lt;Arg&amp;gt;&lt;br /&gt;        service:jmx:rmi://localhost:17264/jndi/rmi://localhost:2099/jmxrmi&lt;br /&gt;               &amp;lt;/Arg&amp;gt;&lt;br /&gt;            &amp;lt;/New&amp;gt;&lt;br /&gt;        &amp;lt;/Arg&amp;gt;&lt;br /&gt;        &amp;lt;Arg/&amp;gt;&lt;br /&gt;        &amp;lt;Arg&amp;gt;&lt;br /&gt;            &amp;lt;Ref id="MBeanServer"/&amp;gt;&lt;br /&gt;        &amp;lt;/Arg&amp;gt;&lt;br /&gt;        &amp;lt;Call name="start"/&amp;gt;&lt;br /&gt;    &amp;lt;/Call&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that we changed the port to 17264. You might want to use the default port instead. In the Jetty 7 based jetty-jmx.xml file these elements should be commented in:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;  &amp;lt;Call name="createRegistry" class="java.rmi.registry.LocateRegistry"&amp;gt;&lt;br /&gt;    &amp;lt;Arg type="java.lang.Integer"&amp;gt;1099&amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;Call name="sleep" class="java.lang.Thread"&amp;gt;&lt;br /&gt;       &amp;lt;Arg type="java.lang.Integer"&amp;gt;1000&amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;/Call&amp;gt;&lt;br /&gt;  &amp;lt;/Call&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer"&amp;gt;&lt;br /&gt;    &amp;lt;Arg&amp;gt;&lt;br /&gt;      &amp;lt;New class="javax.management.remote.JMXServiceURL"&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="java.lang.String"&amp;gt;rmi&amp;lt;/Arg&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="java.lang.String" /&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="java.lang.Integer"&amp;gt;0&amp;lt;/Arg&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="java.lang.String"&amp;gt;/jndi/rmi://localhost:1099/jettyjmx&amp;lt;/Arg&amp;gt;&lt;br /&gt;      &amp;lt;/New&amp;gt;&lt;br /&gt;    &amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;Arg&amp;gt;org.eclipse.jetty:name=rmiconnectorserver&amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;Call name="start" /&amp;gt;&lt;br /&gt;  &amp;lt;/New&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To test the setup, run mvn -Pitest jetty:run and start jconsole. In jconsole you do not connect to a local process. Select Remote Process and enter the service URL. This URL can be copied from the jetty-jmx.xml file if you are using Jetty 6 (i.e. service:jmx:rmi://localhost:17264/jndi/rmi://localhost:2099/jmxrmi). If you are using Jetty 7 and the jetty-maven-plugin, there will be a info statement on the command line when Maven starts the Jetty container from where you can copy the service URL. Finally to execute the integration test, we use the maven-failsafe-plugin like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;&amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;maven-failsafe-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;version&amp;gt;2.9&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;    &amp;lt;includes&amp;gt;&lt;br /&gt;        &amp;lt;include&amp;gt;**/com/package/integration/*.java&amp;lt;/include&amp;gt;&lt;br /&gt;    &amp;lt;/includes&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt;    &amp;lt;execution&amp;gt;&lt;br /&gt;        &amp;lt;id&amp;gt;integration-test&amp;lt;/id&amp;gt;&lt;br /&gt;        &amp;lt;goals&amp;gt;&lt;br /&gt;            &amp;lt;goal&amp;gt;integration-test&amp;lt;/goal&amp;gt;&lt;br /&gt;        &amp;lt;/goals&amp;gt;&lt;br /&gt;    &amp;lt;/execution&amp;gt;&lt;br /&gt;    &amp;lt;execution&amp;gt;&lt;br /&gt;        &amp;lt;id&amp;gt;verify&amp;lt;/id&amp;gt;&lt;/a&gt; to specify any additional system properties like -Dcom.sun.management.jmxremote, -Dcom.sun.management.jmxremote.ssl, -Dcom.sun.management.jmxremote.authenticate or -Dcom.sun.management.jmxremote.port.&lt;br /&gt;&lt;br /&gt;Once the jetty-jmx.xml is downloaded, put in somewhere inside your Maven module where it does not get packaged into the module artifact. In the example above you can see that we have the jetty-jmx.xml file in src/test/etc but any other location will do. Open the file and enable remote JMX access via RMI. In the Jetty 6 based jetty-jmx.xml file these elements should be commented in:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;    &amp;lt;Call id="rmiRegistry" class="java.rmi.registry.LocateRegistry" name="createRegistry"&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="int"&amp;gt;2099&amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;/Call&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;Call id="jmxConnectorServer" class="javax.management.remote.JMXConnectorServerFactory"&lt;br /&gt;          name="newJMXConnectorServer"&amp;gt;&lt;br /&gt;        &amp;lt;Arg&amp;gt;&lt;br /&gt;            &amp;lt;New class="javax.management.remote.JMXServiceURL"&amp;gt;&lt;br /&gt;                &amp;lt;Arg&amp;gt;service:jmx:rmi://localhost:17264/jndi/rmi://localhost:2099/jmxrmi&amp;lt;/Arg&amp;gt;&lt;br /&gt;            &amp;lt;/New&amp;gt;&lt;br /&gt;        &amp;lt;/Arg&amp;gt;&lt;br /&gt;        &amp;lt;Arg/&amp;gt;&lt;br /&gt;        &amp;lt;Arg&amp;gt;&lt;br /&gt;            &amp;lt;Ref id="MBeanServer"/&amp;gt;&lt;br /&gt;        &amp;lt;/Arg&amp;gt;&lt;br /&gt;        &amp;lt;Call name="start"/&amp;gt;&lt;br /&gt;    &amp;lt;/Call&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that we changed the port to 17264. You might want to use the default port instead. In the Jetty 7 based jetty-jmx.xml file these elements should be commented in:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;  &amp;lt;Call name="createRegistry" class="java.rmi.registry.LocateRegistry"&amp;gt;&lt;br /&gt;    &amp;lt;Arg type="java.lang.Integer"&amp;gt;1099&amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;Call name="sleep" class="java.lang.Thread"&amp;gt;&lt;br /&gt;       &amp;lt;Arg type="java.lang.Integer"&amp;gt;1000&amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;/Call&amp;gt;&lt;br /&gt;  &amp;lt;/Call&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer"&amp;gt;&lt;br /&gt;    &amp;lt;Arg&amp;gt;&lt;br /&gt;      &amp;lt;New class="javax.management.remote.JMXServiceURL"&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="java.lang.String"&amp;gt;rmi&amp;lt;/Arg&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="java.lang.String" /&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="java.lang.Integer"&amp;gt;0&amp;lt;/Arg&amp;gt;&lt;br /&gt;        &amp;lt;Arg type="java.lang.String"&amp;gt;/jndi/rmi://localhost:1099/jettyjmx&amp;lt;/Arg&amp;gt;&lt;br /&gt;      &amp;lt;/New&amp;gt;&lt;br /&gt;    &amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;Arg&amp;gt;org.eclipse.jetty:name=rmiconnectorserver&amp;lt;/Arg&amp;gt;&lt;br /&gt;    &amp;lt;Call name="start" /&amp;gt;&lt;br /&gt;  &amp;lt;/New&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To test the setup, run mvn -Pitest jetty:run and start jconsole. In jconsole you do not connect to a local process. Select Remote Process and enter the service URL. This URL can be copied from the jetty-jmx.xml file if you are using Jetty 6 (i.e. service:jmx:rmi://localhost:17264/jndi/rmi://localhost:2099/jmxrmi). If you are using Jetty 7 and the jetty-maven-plugin, there will be a info statement on the command line when Maven starts the Jetty container from where you can copy the service URL. Finally to execute the integration test, we use the maven-failsafe-plugin like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;&amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;maven-failsafe-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;version&amp;gt;2.9&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;    &amp;lt;includes&amp;gt;&lt;br /&gt;        &amp;lt;include&amp;gt;**/com/package/integration/*.java&amp;lt;/include&amp;gt;&lt;br /&gt;    &amp;lt;/includes&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt;    &amp;lt;execution&amp;gt;&lt;br /&gt;        &amp;lt;id&amp;gt;integration-test&amp;lt;/id&amp;gt;&lt;br /&gt;        &amp;lt;goals&amp;gt;&lt;br /&gt;            &amp;lt;goal&amp;gt;integration-test&amp;lt;/goal&amp;gt;&lt;br /&gt;        &amp;lt;/goals&amp;gt;&lt;br /&gt;    &amp;lt;/execution&amp;gt;&lt;br /&gt;    &amp;lt;execution&amp;gt;&lt;br /&gt;        &amp;lt;id&amp;gt;verify&amp;lt;/id&amp;gt;&lt;br /&gt;        &amp;lt;goals&amp;gt;&lt;br /&gt;            &amp;lt;goal&amp;gt;verify&amp;lt;/goal&amp;gt;&lt;br /&gt;        &amp;lt;/goals&amp;gt;&lt;br /&gt;    &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;        &amp;lt;goals&amp;gt;&lt;br /&gt;            &amp;lt;goal&amp;gt;verify&amp;lt;/goal&amp;gt;&lt;br /&gt;        &amp;lt;/goals&amp;gt;&lt;br /&gt;    &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-3465029876661326191?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/3465029876661326191/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=3465029876661326191' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3465029876661326191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3465029876661326191'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/08/testing-jmx-between-two-web.html' title='Testing JMX between two Web Applications using Maven'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-5784146517413001067</id><published>2011-08-09T07:07:00.000-07:00</published><updated>2011-08-09T07:41:25.844-07:00</updated><title type='text'>Sharing configuration files from a Maven Parent Project</title><content type='html'>Okay this post is probably not much news for people who know Maven in and out. I am planning to use this as a reference for myself, in the case that I have to solve a similar problem again in the future. The current project I am working with, is set up as a Maven &lt;a href="http://www.sonatype.com/books/mvnex-book/reference/multimodule.html"&gt;multi module project&lt;/a&gt;. There is a parent pom which is set to pom-packaging. There are several child modules, set to either jar- or war-packaging. Within the pom.xml file of the parent project, we use the &lt;a href="http://maven.apache.org/pom.html#Plugin_Management"&gt;pluginManagement&lt;/a&gt; section to define plugins that should be available to the child modules. The pluginManagement mechanism is an excellent way to avoid the &lt;a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;DRY&lt;/a&gt; problem and not to duplicate Maven configuration within the inheriting projects.&lt;br /&gt;&lt;br /&gt;In most cases configuring plugins within the pluginManagement section is straight forward. It can however get a bit problematic if the plugin depends on (or is reading from external) configuration files. Lets have a look at one example from this parent project of ours.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0"&lt;br /&gt;         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0&lt;br /&gt;                      http://maven.apache.org/maven-v4_0_0.xsd"&amp;gt;&lt;br /&gt;    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;com.package&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;project-parent&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;0.1-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;modules&amp;gt;&lt;br /&gt;        &amp;lt;module&amp;gt;child-a&amp;lt;/module&amp;gt;&lt;br /&gt;        &amp;lt;module&amp;gt;child-b&amp;lt;/module&amp;gt;&lt;br /&gt;        &amp;lt;module&amp;gt;child-c&amp;lt;/module&amp;gt;&lt;br /&gt;    &amp;lt;/modules&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;version.mysql.connector&amp;gt;5.1.12&amp;lt;/version.mysql.connector&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;build&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;pluginManagement&amp;gt;&lt;br /&gt;            &amp;lt;plugins&amp;gt;&lt;br /&gt;                &amp;lt;plugin&amp;gt;&lt;br /&gt;                    &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;&lt;br /&gt;                    &amp;lt;artifactId&amp;gt;sql-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                    &amp;lt;version&amp;gt;1.4&amp;lt;/version&amp;gt;&lt;br /&gt;                    &amp;lt;dependencies&amp;gt;&lt;br /&gt;                        &amp;lt;dependency&amp;gt;&lt;br /&gt;                            &amp;lt;groupId&amp;gt;mysql&amp;lt;/groupId&amp;gt;&lt;br /&gt;                            &amp;lt;artifactId&amp;gt;mysql-connector-java&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                            &amp;lt;version&amp;gt;${version.mysql.connector}&amp;lt;/version&amp;gt;&lt;br /&gt;                        &amp;lt;/dependency&amp;gt;&lt;br /&gt;                    &amp;lt;/dependencies&amp;gt;&lt;br /&gt;                    &amp;lt;configuration&amp;gt;&lt;br /&gt;                        &amp;lt;driver&amp;gt;com.mysql.jdbc.Driver&amp;lt;/driver&amp;gt;&lt;br /&gt;                        &amp;lt;url&amp;gt;jdbc:mysql://localhost/&amp;lt;/url&amp;gt;&lt;br /&gt;                        &amp;lt;username&amp;gt;xyz&amp;lt;/username&amp;gt;&lt;br /&gt;                        &amp;lt;password&amp;gt;xyz&amp;lt;/password&amp;gt;&lt;br /&gt;                    &amp;lt;/configuration&amp;gt;&lt;br /&gt;&lt;br /&gt;                    &amp;lt;executions&amp;gt;&lt;br /&gt;                        &amp;lt;execution&amp;gt;&lt;br /&gt;                            &amp;lt;id&amp;gt;drop-and-recreate-db&amp;lt;/id&amp;gt;&lt;br /&gt;                            &amp;lt;phase&amp;gt;process-test-resources&amp;lt;/phase&amp;gt;&lt;br /&gt;                            &amp;lt;goals&amp;gt;&lt;br /&gt;                                &amp;lt;goal&amp;gt;execute&amp;lt;/goal&amp;gt;&lt;br /&gt;                            &amp;lt;/goals&amp;gt;&lt;br /&gt;                            &amp;lt;configuration&amp;gt;&lt;br /&gt;                                &amp;lt;autocommit&amp;gt;true&amp;lt;/autocommit&amp;gt;&lt;br /&gt;                                &amp;lt;srcFiles&amp;gt;&lt;br /&gt;                                    &amp;lt;srcFile&amp;gt;&lt;br /&gt;                                 ${project.build.directory}/sql/schema/user.sql&lt;br /&gt;                                    &amp;lt;/srcFile&amp;gt;&lt;br /&gt;                                    &amp;lt;srcFile&amp;gt;&lt;br /&gt;                                 ${project.build.directory}/sql/schema/core.sql&lt;br /&gt;                                    &amp;lt;/srcFile&amp;gt;&lt;br /&gt;                                    &amp;lt;srcFile&amp;gt;&lt;br /&gt;                                 ${project.build.directory}/sql/schema/game.sql&lt;br /&gt;                                    &amp;lt;/srcFile&amp;gt;&lt;br /&gt;                                &amp;lt;/srcFiles&amp;gt;&lt;br /&gt;                                &amp;lt;onError&amp;gt;abort&amp;lt;/onError&amp;gt;&lt;br /&gt;                            &amp;lt;/configuration&amp;gt;&lt;br /&gt;                        &amp;lt;/execution&amp;gt;&lt;br /&gt;                    &amp;lt;/executions&amp;gt;&lt;br /&gt;                &amp;lt;/plugin&amp;gt;&lt;br /&gt;            &amp;lt;/plugins&amp;gt;&lt;br /&gt;        &amp;lt;/pluginManagement&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/build&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here we use the &lt;a href="http://mojo.codehaus.org/sql-maven-plugin/"&gt;sql-maven-plugin&lt;/a&gt; to setup the database before tests are being run. The sql-maven-plugin will execute a bunch of &lt;span style="font-weight:bold;"&gt;*.sql&lt;/span&gt; files which are stored in a subfolder in the parent project. As you deploy the parent project to your repository, these files won't be published along with the pom.xml as the packaging is set to pom-packaging. Therefore, if you run the inherited sql-maven-plugin the *.sql files will not be available and the plugin will fail. This will certainly be a problem if your &lt;a href="http://www.atlassian.com/software/bamboo/"&gt;continuous integration server&lt;/a&gt; has a build plan for each Maven child module and not a single build plan for the entire project.&lt;br /&gt;&lt;br /&gt;To overcome this problem, there are 2 things you have to do. First, the parent project needs to publish the *.sql files (or other static files which are needed) to your repository, so that the inheriting modules have access to these files. For this to work, we use the &lt;a href="http://maven.apache.org/plugins/maven-assembly-plugin/"&gt;maven-assembly-plugin&lt;/a&gt; like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0"&lt;br /&gt;         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0&lt;br /&gt;                      http://maven.apache.org/maven-v4_0_0.xsd"&amp;gt;&lt;br /&gt;    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;&lt;br /&gt;	... as before ...&lt;br /&gt;&lt;br /&gt;    &amp;lt;build&amp;gt;&lt;br /&gt;        &amp;lt;plugins&amp;gt;&lt;br /&gt;            &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;maven-assembly-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                &amp;lt;inherited&amp;gt;false&amp;lt;/inherited&amp;gt;&lt;br /&gt;                &amp;lt;configuration&amp;gt;&lt;br /&gt;                    &amp;lt;descriptors&amp;gt;                      &lt;br /&gt;                    &amp;lt;descriptor&amp;gt;&lt;br /&gt;                    ${project.basedir}/assembly/zip.xml&lt;br /&gt;                    &amp;lt;/descriptor&amp;gt;&lt;br /&gt;                    &amp;lt;/descriptors&amp;gt;&lt;br /&gt;                &amp;lt;/configuration&amp;gt;&lt;br /&gt;                &amp;lt;executions&amp;gt;&lt;br /&gt;                    &amp;lt;execution&amp;gt;&lt;br /&gt;                        &amp;lt;id&amp;gt;make-assembly&amp;lt;/id&amp;gt;&lt;br /&gt;                        &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;&lt;br /&gt;                        &amp;lt;goals&amp;gt;&lt;br /&gt;                            &amp;lt;goal&amp;gt;single&amp;lt;/goal&amp;gt;&lt;br /&gt;                        &amp;lt;/goals&amp;gt;&lt;br /&gt;                    &amp;lt;/execution&amp;gt;&lt;br /&gt;                &amp;lt;/executions&amp;gt;&lt;br /&gt;            &amp;lt;/plugin&amp;gt;&lt;br /&gt;        &amp;lt;/plugins&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;pluginManagement&amp;gt;&lt;br /&gt;		... as before ...&lt;br /&gt;        &amp;lt;/pluginManagement&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/build&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that the maven-assembly-plugin in this case is not configured within the pluginManagement section of the parent pom, as we don't want to make this functionality available to child modules. In the configuration you can see that the plugin is set up to be executed during the package phase and that the plugin configuration is defined in the &lt;span style="font-weight:bold;"&gt;zip.xml&lt;/span&gt; file. This zip.xml file looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"&lt;br /&gt;          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"&amp;gt;&lt;br /&gt;    &amp;lt;id&amp;gt;sql-files&amp;lt;/id&amp;gt;&lt;br /&gt;    &amp;lt;formats&amp;gt;&lt;br /&gt;        &amp;lt;format&amp;gt;zip&amp;lt;/format&amp;gt;&lt;br /&gt;    &amp;lt;/formats&amp;gt;&lt;br /&gt;    &amp;lt;includeBaseDirectory&amp;gt;false&amp;lt;/includeBaseDirectory&amp;gt;&lt;br /&gt;    &amp;lt;fileSets&amp;gt;&lt;br /&gt;        &amp;lt;fileSet&amp;gt;&lt;br /&gt;            &amp;lt;directory&amp;gt;${project.basedir}/sql/schema&amp;lt;/directory&amp;gt;&lt;br /&gt;            &amp;lt;outputDirectory/&amp;gt;&lt;br /&gt;            &amp;lt;includes&amp;gt;&lt;br /&gt;                &amp;lt;include&amp;gt;**/*&amp;lt;/include&amp;gt;&lt;br /&gt;            &amp;lt;/includes&amp;gt;&lt;br /&gt;        &amp;lt;/fileSet&amp;gt;&lt;br /&gt;    &amp;lt;/fileSets&amp;gt;&lt;br /&gt;&amp;lt;/assembly&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This configuration will create a zip-file of all *.sql files found in &lt;span style="font-weight:bold;"&gt;${project.basedir}/sql/schema&lt;/span&gt; and publish this zip-file along with the pom.xml when mvn deploy is executed. The id of this configuration is "&lt;span style="font-style:italic;"&gt;sql-files&lt;/span&gt;". This id will be used as a suffix and become part of the filename of the zip-file.&lt;br /&gt;&lt;br /&gt;Now that we publish the zip-file to the repository, we need a way for the child modules to grab and extract the zip-file before the maven-sql-plugin is executed. This is where the &lt;a href="http://maven.apache.org/plugins/maven-dependency-plugin/"&gt;maven-dependency-plugin&lt;/a&gt; comes in handy. Again, the maven-dependency-plugin is configured in the pluginManagement section of the parent pom.xml, as this time we want to inherit the functionality to child modules. Here is what the configuration of the maven-dependency-plugin looks like:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0"&lt;br /&gt;         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0&lt;br /&gt;                      http://maven.apache.org/maven-v4_0_0.xsd"&amp;gt;&lt;br /&gt;    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;&lt;br /&gt;	... as before ...&lt;br /&gt;&lt;br /&gt;    &amp;lt;build&amp;gt;&lt;br /&gt;        &amp;lt;plugins&amp;gt;&lt;br /&gt;		... as before ...&lt;br /&gt;        &amp;lt;/plugins&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;pluginManagement&amp;gt;&lt;br /&gt;                &amp;lt;plugin&amp;gt;&lt;br /&gt;                    &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;                    &amp;lt;artifactId&amp;gt;maven-dependency-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                    &amp;lt;version&amp;gt;2.3&amp;lt;/version&amp;gt;&lt;br /&gt;                    &amp;lt;executions&amp;gt;&lt;br /&gt;                        &amp;lt;execution&amp;gt;&lt;br /&gt;                            &amp;lt;id&amp;gt;unpack-sql-files&amp;lt;/id&amp;gt;&lt;br /&gt;                            &amp;lt;phase&amp;gt;process-test-resources&amp;lt;/phase&amp;gt;&lt;br /&gt;                            &amp;lt;goals&amp;gt;&lt;br /&gt;                                &amp;lt;goal&amp;gt;unpack&amp;lt;/goal&amp;gt;&lt;br /&gt;                            &amp;lt;/goals&amp;gt;&lt;br /&gt;                            &amp;lt;configuration&amp;gt;&lt;br /&gt;                                &amp;lt;artifactItems&amp;gt;&lt;br /&gt;                                    &amp;lt;artifactItem&amp;gt;&lt;br /&gt;                                        &amp;lt;groupId&amp;gt;com.package&amp;lt;/groupId&amp;gt;&lt;br /&gt;                                        &amp;lt;artifactId&amp;gt;project-parent&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                                        &amp;lt;version&amp;gt;&lt;br /&gt;                                         ${parent.version}&lt;br /&gt;                                        &amp;lt;/version&amp;gt;&lt;br /&gt;                                        &amp;lt;type&amp;gt;zip&amp;lt;/type&amp;gt;&lt;br /&gt;                                        &amp;lt;classifier&amp;gt;sql-files&amp;lt;/classifier&amp;gt;&lt;br /&gt;                                        &amp;lt;overWrite&amp;gt;true&amp;lt;/overWrite&amp;gt;&lt;br /&gt;                                        &amp;lt;outputDirectory&amp;gt;&lt;br /&gt;                                         ${project.build.directory}/sql/schema&lt;br /&gt;                                        &amp;lt;/outputDirectory&amp;gt;&lt;br /&gt;                                        &amp;lt;includes&amp;gt;**/*.sql&amp;lt;/includes&amp;gt;&lt;br /&gt;                                    &amp;lt;/artifactItem&amp;gt;&lt;br /&gt;                                &amp;lt;/artifactItems&amp;gt;&lt;br /&gt;                                &amp;lt;includes&amp;gt;**/*&amp;lt;/includes&amp;gt;&lt;br /&gt;                                &amp;lt;overWriteReleases&amp;gt;true&amp;lt;/overWriteReleases&amp;gt;&lt;br /&gt;                                &amp;lt;overWriteSnapshots&amp;gt;true&amp;lt;/overWriteSnapshots&amp;gt;&lt;br /&gt;                            &amp;lt;/configuration&amp;gt;&lt;br /&gt;                        &amp;lt;/execution&amp;gt;&lt;br /&gt;                    &amp;lt;/executions&amp;gt;&lt;br /&gt;                &amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;br /&gt;		... as before ...&lt;br /&gt;&lt;br /&gt;        &amp;lt;/pluginManagement&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/build&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The plugin (if a child module decides to use this) will be executed during the process-test-resources phase of the build. We are getting the zip file by specifying the groupId, artifactId, version and the type. Also the classifier value must match the id which we used earlier in the zip.xml file for configuring the maven-assembly-plugin. The zip-file is extracted to ${project.build.directory}/sql/schema and we are only extracting files having the *.sql extension (well there shouldn't be any other files but ok). This concludes what needs to be done to extract the zip-file and child modules are now ready to use the extracted files. Here is a snippet from a pom.xml file in a Maven child module. This is everything needed to run the sql-maven-plugin defined in the parent pom and extract the required configuration files upfront.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;    &amp;lt;parent&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;com.package&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;project-parent&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;0.1-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/parent&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;child-a&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;packaging&amp;gt;war&amp;lt;/packaging&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;build&amp;gt;&lt;br /&gt;        &amp;lt;plugins&amp;gt;&lt;br /&gt;            &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;maven-dependency-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;br /&gt;            &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;sql-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;/plugin&amp;gt;&lt;br /&gt;        &amp;lt;/plugins&amp;gt;&lt;br /&gt;    &amp;lt;/build&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For the sake of completeness, once again the full parent pom.xml file.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0"&lt;br /&gt;         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0&lt;br /&gt;                      http://maven.apache.org/maven-v4_0_0.xsd"&amp;gt;&lt;br /&gt;    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;com.package&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;project-parent&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;0.1-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;modules&amp;gt;&lt;br /&gt;        &amp;lt;module&amp;gt;child-a&amp;lt;/module&amp;gt;&lt;br /&gt;        &amp;lt;module&amp;gt;child-b&amp;lt;/module&amp;gt;&lt;br /&gt;        &amp;lt;module&amp;gt;child-c&amp;lt;/module&amp;gt;&lt;br /&gt;    &amp;lt;/modules&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;version.mysql.connector&amp;gt;5.1.12&amp;lt;/version.mysql.connector&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;build&amp;gt;&lt;br /&gt;        &amp;lt;plugins&amp;gt;&lt;br /&gt;            &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;maven-assembly-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                &amp;lt;inherited&amp;gt;false&amp;lt;/inherited&amp;gt;&lt;br /&gt;                &amp;lt;configuration&amp;gt;&lt;br /&gt;                    &amp;lt;descriptors&amp;gt;&lt;br /&gt;                     &amp;lt;descriptor&amp;gt;&lt;br /&gt;                      ${project.basedir}/assembly/zip.xml&lt;br /&gt;                    &amp;lt;/descriptor&amp;gt;&lt;br /&gt;                    &amp;lt;/descriptors&amp;gt;&lt;br /&gt;                &amp;lt;/configuration&amp;gt;&lt;br /&gt;                &amp;lt;executions&amp;gt;&lt;br /&gt;                    &amp;lt;execution&amp;gt;&lt;br /&gt;                        &amp;lt;id&amp;gt;make-assembly&amp;lt;/id&amp;gt;&lt;br /&gt;                        &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;&lt;br /&gt;                        &amp;lt;goals&amp;gt;&lt;br /&gt;                            &amp;lt;goal&amp;gt;single&amp;lt;/goal&amp;gt;&lt;br /&gt;                        &amp;lt;/goals&amp;gt;&lt;br /&gt;                    &amp;lt;/execution&amp;gt;&lt;br /&gt;                &amp;lt;/executions&amp;gt;&lt;br /&gt;            &amp;lt;/plugin&amp;gt;&lt;br /&gt;        &amp;lt;/plugins&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;pluginManagement&amp;gt;&lt;br /&gt;                &amp;lt;plugin&amp;gt;&lt;br /&gt;                    &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;                    &amp;lt;artifactId&amp;gt;maven-dependency-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                    &amp;lt;version&amp;gt;2.3&amp;lt;/version&amp;gt;&lt;br /&gt;                    &amp;lt;executions&amp;gt;&lt;br /&gt;                        &amp;lt;execution&amp;gt;&lt;br /&gt;                            &amp;lt;id&amp;gt;unpack-sql-files&amp;lt;/id&amp;gt;&lt;br /&gt;                            &amp;lt;phase&amp;gt;process-test-resources&amp;lt;/phase&amp;gt;&lt;br /&gt;                            &amp;lt;goals&amp;gt;&lt;br /&gt;                                &amp;lt;goal&amp;gt;unpack&amp;lt;/goal&amp;gt;&lt;br /&gt;                            &amp;lt;/goals&amp;gt;&lt;br /&gt;                            &amp;lt;configuration&amp;gt;&lt;br /&gt;                                &amp;lt;artifactItems&amp;gt;&lt;br /&gt;                                    &amp;lt;artifactItem&amp;gt;&lt;br /&gt;                                        &amp;lt;groupId&amp;gt;com.package&amp;lt;/groupId&amp;gt;&lt;br /&gt;                                        &amp;lt;artifactId&amp;gt;project-parent&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                                        &amp;lt;version&amp;gt;&lt;br /&gt;                                         ${parent.version}&lt;br /&gt;                                        &amp;lt;/version&amp;gt;&lt;br /&gt;                                        &amp;lt;type&amp;gt;zip&amp;lt;/type&amp;gt;&lt;br /&gt;                                        &amp;lt;classifier&amp;gt;sql-files&amp;lt;/classifier&amp;gt;&lt;br /&gt;                                        &amp;lt;overWrite&amp;gt;true&amp;lt;/overWrite&amp;gt;&lt;br /&gt;                                        &amp;lt;outputDirectory&amp;gt;&lt;br /&gt;                                          ${project.build.directory}/sql/schema&lt;br /&gt;                                        &amp;lt;/outputDirectory&amp;gt;&lt;br /&gt;                                        &amp;lt;includes&amp;gt;**/*.sql&amp;lt;/includes&amp;gt;&lt;br /&gt;                                    &amp;lt;/artifactItem&amp;gt;&lt;br /&gt;                                &amp;lt;/artifactItems&amp;gt;&lt;br /&gt;                                &amp;lt;includes&amp;gt;**/*&amp;lt;/includes&amp;gt;&lt;br /&gt;                                &amp;lt;overWriteReleases&amp;gt;true&amp;lt;/overWriteReleases&amp;gt;&lt;br /&gt;                                &amp;lt;overWriteSnapshots&amp;gt;true&amp;lt;/overWriteSnapshots&amp;gt;&lt;br /&gt;                            &amp;lt;/configuration&amp;gt;&lt;br /&gt;                        &amp;lt;/execution&amp;gt;&lt;br /&gt;                    &amp;lt;/executions&amp;gt;&lt;br /&gt;                &amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;br /&gt;		&amp;lt;plugin&amp;gt;&lt;br /&gt;                    &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;&lt;br /&gt;                    &amp;lt;artifactId&amp;gt;sql-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                    &amp;lt;version&amp;gt;1.4&amp;lt;/version&amp;gt;&lt;br /&gt;                    &amp;lt;dependencies&amp;gt;&lt;br /&gt;                        &amp;lt;dependency&amp;gt;&lt;br /&gt;                            &amp;lt;groupId&amp;gt;mysql&amp;lt;/groupId&amp;gt;&lt;br /&gt;                            &amp;lt;artifactId&amp;gt;mysql-connector-java&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                            &amp;lt;version&amp;gt;${version.mysql.connector}&amp;lt;/version&amp;gt;&lt;br /&gt;                        &amp;lt;/dependency&amp;gt;&lt;br /&gt;                    &amp;lt;/dependencies&amp;gt;&lt;br /&gt;                    &amp;lt;configuration&amp;gt;&lt;br /&gt;                        &amp;lt;driver&amp;gt;com.mysql.jdbc.Driver&amp;lt;/driver&amp;gt;&lt;br /&gt;                        &amp;lt;url&amp;gt;jdbc:mysql://localhost/&amp;lt;/url&amp;gt;&lt;br /&gt;                        &amp;lt;username&amp;gt;xyz&amp;lt;/username&amp;gt;&lt;br /&gt;                        &amp;lt;password&amp;gt;xyz&amp;lt;/password&amp;gt;&lt;br /&gt;                    &amp;lt;/configuration&amp;gt;&lt;br /&gt;&lt;br /&gt;                    &amp;lt;executions&amp;gt;&lt;br /&gt;                        &amp;lt;execution&amp;gt;&lt;br /&gt;                            &amp;lt;id&amp;gt;drop-and-recreate-db&amp;lt;/id&amp;gt;&lt;br /&gt;                            &amp;lt;phase&amp;gt;process-test-resources&amp;lt;/phase&amp;gt;&lt;br /&gt;                            &amp;lt;goals&amp;gt;&lt;br /&gt;                                &amp;lt;goal&amp;gt;execute&amp;lt;/goal&amp;gt;&lt;br /&gt;                            &amp;lt;/goals&amp;gt;&lt;br /&gt;                            &amp;lt;configuration&amp;gt;&lt;br /&gt;                                &amp;lt;autocommit&amp;gt;true&amp;lt;/autocommit&amp;gt;&lt;br /&gt;                                &amp;lt;srcFiles&amp;gt;&lt;br /&gt;                                    &amp;lt;srcFile&amp;gt;&lt;br /&gt;                                ${project.build.directory}/sql/schema/user.sql&lt;br /&gt;                                    &amp;lt;/srcFile&amp;gt;&lt;br /&gt;                                    &amp;lt;srcFile&amp;gt;&lt;br /&gt;                                ${project.build.directory}/sql/schema/core.sql&lt;br /&gt;                                    &amp;lt;/srcFile&amp;gt;&lt;br /&gt;                                    &amp;lt;srcFile&amp;gt;&lt;br /&gt;                                ${project.build.directory}/sql/schema/game.sql&lt;br /&gt;                                    &amp;lt;/srcFile&amp;gt;&lt;br /&gt;                                &amp;lt;/srcFiles&amp;gt;&lt;br /&gt;                                &amp;lt;onError&amp;gt;abort&amp;lt;/onError&amp;gt;&lt;br /&gt;                            &amp;lt;/configuration&amp;gt;&lt;br /&gt;                        &amp;lt;/execution&amp;gt;&lt;br /&gt;                    &amp;lt;/executions&amp;gt;&lt;br /&gt;                &amp;lt;/plugin&amp;gt;&lt;br /&gt;        &amp;lt;/pluginManagement&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/build&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-5784146517413001067?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/5784146517413001067/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=5784146517413001067' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5784146517413001067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5784146517413001067'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/08/sharing-configuration-files-from-maven.html' title='Sharing configuration files from a Maven Parent Project'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-4848335350464800966</id><published>2011-08-05T07:10:00.000-07:00</published><updated>2011-08-05T07:35:35.070-07:00</updated><title type='text'>Heating up the Code Generator</title><content type='html'>It has been a couple of years since I used a code generator in one of my projects. It must have been 2004 or 2005, when &lt;a href="http://en.wikipedia.org/wiki/Model-driven_architecture"&gt;MDA&lt;/a&gt; was a big buzzword. Back then, we used a self-made code generator, which was written by a very smart developer who I used to work with at &lt;a href="http://www.aperto.de/en.html"&gt;Aperto AG&lt;/a&gt; in Berlin. He even &lt;a href="http://sourceforge.net/projects/apertogenerator/"&gt;contributed&lt;/a&gt; the code generator to the open source community later on. Those were the days.&lt;br /&gt;&lt;br /&gt;Since then, there wasn't much use for a code generator anymore. IDE's getting better and better at helping you with code generation and auto-completion etc. And of course, adding a generator to your build process is always a bit of work. So it is often faster to write the boilerplate code yourself, if that doesn't takes forever. However, last week it was time to bring code generation back from the grave. The  game we are currently developing for &lt;a href="http://www.playfish.com/?page=company"&gt;EA here in Norway&lt;/a&gt;, has a mechanism where the game client sends game events to the server. In our domain we call these events also audit changes. A typical audit change can be that the player has found a treasure, that the player has consumed food or that the player has discovered a new scenery. On the client side, the audit change is implemented in ActionScript 3. On the server side the audit change is implemented in Java. There is a transport layer in between which serializes the AS3 object, sends it over the network and deserializes it back into a Java object. For us server developers, this meant that every new audit change also needed a transport definition about how to serialize and deserialize the audit change. This definition was always wrapped into a new audit change type class. The type definition class was written manually, which sort of was okay until we had more than 20 audit changes in the game. Thats when I started to look into generating the transport layer on the server side.&lt;br /&gt;&lt;br /&gt;In Java 5 along with the new Annotation language feature, Sun added a command-line utility called &lt;a href="http://download.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html"&gt;Annotation Processing Tool&lt;/a&gt; (apt). This was later merged into the standard javac compiler with the release of Java 6. There is also the &lt;a href="http://apt-jelly.sourceforge.net/"&gt;apt-jelly project&lt;/a&gt; which provides an interface to apt and can be used to generate code artifacts based on templates written with &lt;a href="http://freemarker.sourceforge.net/"&gt;Freemarker&lt;/a&gt; or &lt;a href="http://commons.apache.org/jelly/index.html"&gt;Jelly&lt;/a&gt;. Finally to glue everything together, there is the &lt;a href="http://mojo.codehaus.org/apt-maven-plugin/"&gt;maven-apt-plugin&lt;/a&gt; which can be used to execute a &lt;a href="http://download.oracle.com/javase/1.5.0/docs/guide/apt/mirror/com/sun/mirror/apt/AnnotationProcessorFactory.html"&gt;AnnotationProcessorFactory&lt;/a&gt; during your build and therefore integrate apt into your project. The maven-apt-plugin looks sort of dead however. I think nowadays even the standard &lt;a href="http://jira.codehaus.org/browse/MCOMPILER-75"&gt;maven-compiler-plugin&lt;/a&gt; or the &lt;a href="http://code.google.com/p/maven-annotation-plugin/"&gt;maven-annotation-plugin&lt;/a&gt; can be used to process your annotations and generate code artifacts. Since I got our generator working using the maven-apt-plugin, I did not bother looking at the other 2 plugins. If someone has a working example on how they are used with a  AnnotationProcessorFactory, I would be really happy to see it. Let's look into some code now.&lt;br /&gt;&lt;br /&gt;Here is an example of an audit change as it could exist in the game:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Audit change telling that the {@link User} has bought a {@link House}.&lt;br /&gt; */&lt;br /&gt;@DatatypeDefinition(minSize = 7)&lt;br /&gt;public class BoughtHouseForGold implements AuditChange {&lt;br /&gt;&lt;br /&gt;    private int itemId;&lt;br /&gt;&lt;br /&gt;    @DatatypeCollection(elementType = Integer.class)&lt;br /&gt;    private List&amp;lt;Integer&amp;gt; sceneries;&lt;br /&gt;&lt;br /&gt;    @DatatypeIgnore&lt;br /&gt;    private User friend;&lt;br /&gt;&lt;br /&gt;    ... other stuff not relevant ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The transport class that we want to generate need to serialize and deserialize every field of the audit change. As you can guess from above, we do not want to transport the friend field in the example. The meta data, that isn't accessible via reflection within the template which we will write later, needs to be given to the generator in another way - for instance via Annotations. Thats why I created a bunch of Annotations just to instruct the generator.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Marks the type annotated by this annotation as something that can be &lt;br /&gt; * serialized and deserialized using a Datatype.&lt;br /&gt; */&lt;br /&gt;@Retention(RetentionPolicy.SOURCE)&lt;br /&gt;@Target({ElementType.TYPE})&lt;br /&gt;public @interface DatatypeDefinition {&lt;br /&gt;    int minSize() default 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Any {@link Field} annotated this way, will be rendered as a Collection of the &lt;br /&gt; * specified type when the Datatype is generated.&lt;br /&gt; */&lt;br /&gt;@Retention(RetentionPolicy.SOURCE)&lt;br /&gt;@Target({ElementType.FIELD})&lt;br /&gt;public @interface DatatypeCollection {&lt;br /&gt;    Class&amp;lt;?&amp;gt; elementType();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Any {@link Field} annotated this way, will be ignored in when the Datatype is generated.&lt;br /&gt; */&lt;br /&gt;@Retention(RetentionPolicy.SOURCE)&lt;br /&gt;@Target({ElementType.FIELD})&lt;br /&gt;public @interface DatatypeIgnore {&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now for the hardest part, the template. I can recommend, that you start writing the code for the first class (the one that should be generated later) manually before you work on the template. Add the class into the default location in Maven, i.e. &lt;span style="font-weight:bold;"&gt;src/main/java/com/whatever/package&lt;/span&gt;. The generated classes will end up in a different location later (under &lt;span style="font-weight:bold;"&gt;target/generated-sources/&lt;/span&gt;) so it will be easy to compare the expected outcome and the generated outcome while working on the template. Here is a template example in which I use Freemarker directives.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;#-- for each type annotated with DatatypeDefinition --&amp;gt;&lt;br /&gt;&amp;lt;@forAllTypes var="type" annotationVar="datatypeDefinition" annotation="package.DatatypeDefinition"&amp;gt;&lt;br /&gt;&amp;lt;#-- tell apt-jelly that the outcome will be a java source artifact --&amp;gt;&lt;br /&gt;&amp;lt;@javaSource name="package.types.${type.simpleName}Type"&amp;gt;&lt;br /&gt;package package.types;&lt;br /&gt;&lt;br /&gt;&amp;lt;#-- all imports go here --&amp;gt;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * This class contains the {@link Datatype} for {@link ${type.simpleName}}.&lt;br /&gt; */&lt;br /&gt;public class ${type.simpleName}Type extends AbstractAuditableType&amp;lt;${type.simpleName}&amp;gt; { &amp;lt;#-- class name based on type that was annotated with DatatypeDefinition --&amp;gt;&lt;br /&gt;    public ${type.simpleName}Type() {&lt;br /&gt;        super(&lt;br /&gt;     &amp;lt;#-- replace camel case with underscores --&amp;gt;&lt;br /&gt;            TypeCodes.${type.simpleName?replace("(?&amp;lt;=[a-z0-9])[A-Z]|(?&amp;lt;=[a-zA-Z])[0-9]|(?&amp;lt;=[A-Z])[A-Z](?=[a-z])", "_$0", 'r')?upper_case}_TYPE_CODE,&lt;br /&gt;            new Datatype&amp;lt;${type.simpleName}&amp;gt;(${type.simpleName}.class, ${datatypeDefinition.minSize}) {&lt;br /&gt;&lt;br /&gt;                @Override&lt;br /&gt;                public ${type.simpleName} read(final DatatypeInput in) throws DataFormatException {&lt;br /&gt;                    final ${type.simpleName} value = new ${type.simpleName}();&lt;br /&gt;                    &amp;lt;@forAllFields var="field"&amp;gt;&lt;br /&gt;                        &amp;lt;#assign useField = true&amp;gt;&lt;br /&gt;                        &amp;lt;#-- do not do anything if field is a constant --&amp;gt;&lt;br /&gt;                        &amp;lt;#if field.static = true&amp;gt;&amp;lt;#assign useField = false&amp;gt;&amp;lt;/#if&amp;gt;&lt;br /&gt;                        &amp;lt;#-- do not do anything if annotated with @DatatypeIgnore --&amp;gt;&lt;br /&gt;                        &amp;lt;@ifHasAnnotation declaration=field annotation="package.DatatypeIgnore"&amp;gt;&amp;lt;#assign useField = false&amp;gt;&amp;lt;/@ifHasAnnotation&amp;gt;&lt;br /&gt;                        &amp;lt;#if useField = true&amp;gt;&lt;br /&gt;                            &amp;lt;#-- build name of the setter method --&amp;gt;&lt;br /&gt;                            &amp;lt;#assign setter = "set${field?cap_first}"&amp;gt;&lt;br /&gt;                            &amp;lt;#assign useCollection = false&amp;gt;&lt;br /&gt;                            &amp;lt;@ifHasAnnotation var="datatypeCollectionAnnotation" declaration=field annotation="package.DatatypeCollection"&amp;gt;&amp;lt;#assign useCollection = true&amp;gt;&amp;lt;/@ifHasAnnotation&amp;gt;&lt;br /&gt;                            &amp;lt;#if useCollection = true&amp;gt;&lt;br /&gt;                                &amp;lt;#if datatypeCollectionAnnotation.elementType = "java.lang.Integer"&amp;gt;&lt;br /&gt;                    value.${setter}(in.readList(Datatype.uintvar31));&lt;br /&gt;                                &amp;lt;#else&amp;gt;&lt;br /&gt;                    System.out.println('Cannot read collections of type: ${datatypeCollectionAnnotation.elementType}. Extend auditable-type.fmt');&lt;br /&gt;                                &amp;lt;/#if&amp;gt;&lt;br /&gt;                            &amp;lt;#else&amp;gt;&lt;br /&gt;                                &amp;lt;#-- Handling for fields without extra annotations --&amp;gt;&lt;br /&gt;                                &amp;lt;#if field.type = "int" || field.type = "java.lang.Integer"&amp;gt;&lt;br /&gt;                    value.${setter}(in.readUintvar31());                                &lt;br /&gt;                                &amp;lt;#elseif field.type = "boolean" || field.type = "java.lang.Boolean"&amp;gt;&lt;br /&gt;                    value.${setter}(in.readBoolean());&lt;br /&gt;                                &amp;lt;#elseif field.type = "java.lang.String"&amp;gt;&lt;br /&gt;                    value.${setter}(in.readString());&lt;br /&gt;                                &amp;lt;/#if&amp;gt;&lt;br /&gt;                            &amp;lt;/#if&amp;gt;&lt;br /&gt;                            &amp;lt;#assign useCollection = false&amp;gt;&lt;br /&gt;                        &amp;lt;/#if&amp;gt;&lt;br /&gt;                        &amp;lt;#assign useField = false&amp;gt;&lt;br /&gt;                    &amp;lt;/@forAllFields&amp;gt;&lt;br /&gt;                    return value;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                @Override&lt;br /&gt;                public void write(final DatatypeOutput out, final ${type.simpleName} value) throws IOException {&lt;br /&gt;                    &amp;lt;@forAllFields var="field"&amp;gt;&lt;br /&gt;                        &amp;lt;#assign useField = true&amp;gt;&lt;br /&gt;                        &amp;lt;#-- do not do anything if field is a constant --&amp;gt;&lt;br /&gt;                        &amp;lt;#if field.static = true&amp;gt;&amp;lt;#assign useField = false&amp;gt;&amp;lt;/#if&amp;gt;&lt;br /&gt;                        &amp;lt;#-- do not do anything if annotated with @DatatypeIgnore --&amp;gt;&lt;br /&gt;                        &amp;lt;@ifHasAnnotation declaration=field annotation="DatatypeIgnore"&amp;gt;&amp;lt;#assign useField = false&amp;gt;&amp;lt;/@ifHasAnnotation&amp;gt;&lt;br /&gt;                        &amp;lt;#if useField&amp;gt;&lt;br /&gt;                            &amp;lt;#-- build name of the getter method --&amp;gt;&lt;br /&gt;                            &amp;lt;#assign getter = "get${field?cap_first}"&amp;gt;&lt;br /&gt;                            &amp;lt;#if field.type = "boolean" || field.type = "java.lang.Boolean"&amp;gt;&lt;br /&gt;                                &amp;lt;#-- boolean getter starts with is --&amp;gt;&lt;br /&gt;                                &amp;lt;#assign getter = "is${field?cap_first}"&amp;gt;&lt;br /&gt;                            &amp;lt;/#if&amp;gt;&lt;br /&gt;                            &amp;lt;#assign useCollection = false&amp;gt;&lt;br /&gt;                            &amp;lt;@ifHasAnnotation var="datatypeCollectionAnnotation" declaration=field annotation="DatatypeCollection"&amp;gt;&amp;lt;#assign useCollection = true&amp;gt;&amp;lt;/@ifHasAnnotation&amp;gt;&lt;br /&gt;                            &amp;lt;#if useCollection = true&amp;gt;&lt;br /&gt;                                &amp;lt;#if datatypeCollectionAnnotation.elementType = "java.lang.Integer"&amp;gt;&lt;br /&gt;                    out.writeCollection(Datatype.uintvar31, value.${getter}());&lt;br /&gt;                                &amp;lt;#else&amp;gt;&lt;br /&gt;                    System.out.println('Cannot write collections of type: ${datatypeCollectionAnnotation.elementType}. Extend auditable-type.fmt');&lt;br /&gt;                                &amp;lt;/#if&amp;gt;                            &lt;br /&gt;                            &amp;lt;#else&amp;gt;&lt;br /&gt;                                &amp;lt;#if field.type = "int" || field.type = "java.lang.Integer"&amp;gt;&lt;br /&gt;                    out.writeUintvar31(value.${getter}());                                &lt;br /&gt;                                &amp;lt;#elseif field.type = "boolean" || field.type = "java.lang.Boolean"&amp;gt;&lt;br /&gt;                    out.writeBoolean(value.${getter}());&lt;br /&gt;                                &amp;lt;#elseif field.type = "java.lang.String"&amp;gt;&lt;br /&gt;                    out.writeString(value.${getter}());&lt;br /&gt;                                &amp;lt;/#if&amp;gt;&lt;br /&gt;                            &amp;lt;/#if&amp;gt;&lt;br /&gt;                            &amp;lt;#assign useCollection = false&amp;gt;&lt;br /&gt;                        &amp;lt;/#if&amp;gt;&lt;br /&gt;                        &amp;lt;#assign useField = false&amp;gt;&lt;br /&gt;                    &amp;lt;/@forAllFields&amp;gt;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        );&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&amp;lt;/@javaSource&amp;gt;&lt;br /&gt;&amp;lt;/@forAllTypes&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;My apologies, this is incredibly hard to read here on the blog. It helps to click the "view source" button in the upper right corner of the code above and copy everything to a text editor. I also added comments in the template to explain what I am doing.&lt;br /&gt;&lt;br /&gt;Finally here is the configuration for the maven-apt-plugin, so that it will generate your code artifacts before compiling your project (note that target/generated-sources will be merged with the real sources during compile time). &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;&amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;apt-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;version&amp;gt;1.0-alpha-4&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;    &amp;lt;factory&amp;gt;net.sf.jelly.apt.freemarker.FreemarkerProcessorFactory&amp;lt;/factory&amp;gt;&lt;br /&gt;    &amp;lt;options&amp;gt;&lt;br /&gt;        &amp;lt;option&amp;gt;template=${basedir}/src/main/resources/apt/auditable-type.fmt&lt;br /&gt;        &amp;lt;/option&amp;gt;&lt;br /&gt;    &amp;lt;/options&amp;gt;&lt;br /&gt;    &amp;lt;fork&amp;gt;true&amp;lt;/fork&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;dependencies&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;net.sf.apt-jelly&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;apt-jelly-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;2.14&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;net.sf.apt-jelly&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;apt-jelly-freemarker&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;2.14&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;&amp;lt;/dependencies&amp;gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt;    &amp;lt;execution&amp;gt;&lt;br /&gt;        &amp;lt;goals&amp;gt;&lt;br /&gt;            &amp;lt;goal&amp;gt;process&amp;lt;/goal&amp;gt;&lt;br /&gt;        &amp;lt;/goals&amp;gt;&lt;br /&gt;    &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And voilà, here is our generated &lt;span style="font-weight:bold;"&gt;BoughtHouseForGoldType&lt;/span&gt; class fresh out of the oven:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;package package.types;&lt;br /&gt;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * This class contains the {@link Datatype} for {@link BoughtHouseForGold}.&lt;br /&gt; */&lt;br /&gt;public class BoughtHouseForGoldType extends AbstractAuditableType&amp;lt;BoughtHouseForGold&amp;gt; {&lt;br /&gt;    public BoughtHouseForGoldType() {&lt;br /&gt;        super(&lt;br /&gt;            TypeCodes.BOUGHT_HOUSE_FOR_GOLD_TYPE_CODE,&lt;br /&gt;            new Datatype&amp;lt;BoughtHouseForGold&amp;gt;(BoughtHouseForGold.class, 7) {&lt;br /&gt;&lt;br /&gt;                @Override&lt;br /&gt;                public BoughtHouseForGold read(final DatatypeInput in) throws DataFormatException {&lt;br /&gt;                    final BoughtHouseForGold value = new BoughtHouseForGold();&lt;br /&gt;                    value.setItemId(in.readUintvar31());&lt;br /&gt;                    value.setSceneries(in.readList(Datatype.uintvar31));&lt;br /&gt;                    return value;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                @Override&lt;br /&gt;                public void write(final DatatypeOutput out, final BoughtHouseForGold value) throws IOException {&lt;br /&gt;                    out.writeUintvar31(value.getItemId());&lt;br /&gt;                    out.writeCollection(Datatype.uintvar31, value.getSceneries());&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        );&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-4848335350464800966?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/4848335350464800966/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=4848335350464800966' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4848335350464800966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4848335350464800966'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/08/heating-up-code-generator.html' title='Heating up the Code Generator'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-8418544715329155486</id><published>2011-07-26T09:20:00.000-07:00</published><updated>2011-07-26T09:52:52.092-07:00</updated><title type='text'>The Beauties and Pitfalls of ThreadLocals</title><content type='html'>&lt;a href="http://download.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html"&gt;ThreadLocal&lt;/a&gt; must be one of the Java features, which not many developers have used. It doesn't happen so often, that you stand in front of a problem, for which ThreadLocal is the best solution. In the current game I am developing, I have however decided to use a ThreadLocal to store per-thread slash per-request context information. Actually this is one of the use cases that Brian Goetz wrote about in his great &lt;a href="http://www.ibm.com/developerworks/library/j-threads3/index.html"&gt;article about ThreadLocals&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Other applications for ThreadLocal include storing or accumulating per-thread context information for later retrieval.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;This game uses the Spring Framework and the Servlet which is handling all requests, is a Spring Bean. When the request comes in, the Servlet will delegate handling of the request data to something that we call a RpcHandler. Once the appropriate RpcHandler is selected by the Servlet, the request has to go through 3 stages and each stage is mapped to a method in the RpcHandler. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;// stage 1&lt;br /&gt;public void readRequest(final DatatypeInput in) {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// stage 2&lt;br /&gt;public void performOperation() {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// stage 3&lt;br /&gt;public void writeResponse(final DatatypeOutput out) {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;First the request data is read, then the RpcHandler is performing it's main operation and finally some response data might be written. In other games developers have decided to create a new instance of the RpcHandler subclass for each request. This makes it easy as the per-request context information can be stored in private fields of the RpcHandler. The negative part is that this approach is using more memory as there will be 1 instance of RpcHandler per request. This might sound acceptable if the RpcHandler was simple and lightweight but often they contain further object-trees. Because our game was Spring based, I was striving for a solution were we only had 1 instance per RpcHandler sublass. Each instance is injected as a Spring Bean into the Servlet. Since the RpcHandler interface could not be changed, so that per-request context information was given as a parameter to the 3 methods above, I needed to use a ThreadLocal.&lt;br /&gt;&lt;br /&gt;First I create a wrapper class for the context information called Message. The RpcHandler would then contain a private field of type ThreadLocal encapsulating a Message on a per-request basis. Even though ServletContainers like Jetty or Tomcat use a thread pool were Threads are recycled, this would still be okay as one Thread is used to service an entire request (actually this might be different in Servlet 3.0 where &lt;a href="http://blogs.webtide.com/gregw/entry/patterns_for_servlet_3_0"&gt;requests can be suspended&lt;/a&gt; and I'am assuming Threads are given back to the pool?). &lt;a href="http://www.ibm.com/developerworks/library/j-threads3/index.html"&gt;Quoting&lt;/a&gt; Brian Goetz:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;ThreadLocal is also useful in servlet-based applications or any multithreaded server application in which the unit of work is an entire request, because then a single thread will be used during the entire course of handling the request.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Since usually each Spring Bean does only exist as 1 instance per ApplicationContext (unless specified otherwise), I decided to have a &lt;span style="font-weight:bold;"&gt;non-static&lt;/span&gt; ThreadLocal field which is sort of different from what the &lt;a href="http://download.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html"&gt;JavaDoc class comment&lt;/a&gt; suggests:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Here is an example of a typical RpcHandler subclass in the game:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;public class SaveChangesHandler extends AbstractRpcHandler {&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public void readRequest(final DatatypeInput in) {&lt;br /&gt;        // extract Message from DatatypeInput&lt;br /&gt;        setMessage(...);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public void performOperation() throws DAOException, RpcFailureException {&lt;br /&gt;        final Message message = getMessage();&lt;br /&gt;        // use Message to update the User&lt;br /&gt;        userService.save(message.getUser(), ...);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public void writeResponse(final DatatypeOutput out) throws IOException {&lt;br /&gt;        final Message message = getMessage();&lt;br /&gt;        // use Message to write something back to repsonse&lt;br /&gt;        out.write(message.getUser(), ...)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The AbstractRpcHandler class looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;public abstract class AbstractRpcHandler extends RpcHandler&amp;lt;GameDaoSupport&amp;gt; {&lt;br /&gt;&lt;br /&gt;    private ThreadLocal&amp;lt;Message&amp;gt; threadLocalMessage;&lt;br /&gt;&lt;br /&gt;    public Message getMessage() {&lt;br /&gt;        return threadLocalMessage.get();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setMessage(final Message message) {&lt;br /&gt;        this.threadLocalMessage = new ThreadLocal&amp;lt;Message&amp;gt;();&lt;br /&gt;        this.threadLocalMessage.set(message);&lt;br /&gt;        &lt;br /&gt;        // add a cleanup callback which will be &lt;br /&gt;        // executed from the ServletRequestCleanupFilter&lt;br /&gt;        ServletRequestCleanupService.addCleanupCallback(&lt;br /&gt;            new ServletRequestThreadLocalCleanupCallback(&lt;br /&gt;               this.threadLocalMessage&lt;br /&gt;            )&lt;br /&gt;        );&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This worked well for some time but sometimes I could see the following errors in the logs:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;2011-07-26 13:50:50 ERROR c.p.s.RpcServlet:handleRequest threw exception:&lt;br /&gt;java.lang.NullPointerException: null&lt;br /&gt;        at com.foo.save.SaveChangesHandler.writeResponse(SaveChangesHandler.java:21) &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Apparently the Message in writeResponse(..) was &lt;span style="font-weight:bold;"&gt;null&lt;/span&gt;, which was a bit strange because it was not null when performOperation(..) was invoked by the RpcServlet in stage 2. It took a bit but I found at least one problem with the code in AbstractRpcHandler:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;    public void setMessage(final Message message) {&lt;br /&gt;        this.threadLocalMessage = new ThreadLocal&amp;lt;Message&amp;gt;();&lt;br /&gt;        this.threadLocalMessage.set(message);&lt;br /&gt;        &lt;br /&gt;        // add a cleanup callback which will be &lt;br /&gt;        // executed from the ServletRequestCleanupFilter&lt;br /&gt;        ServletRequestCleanupService.addCleanupCallback(&lt;br /&gt;            new ServletRequestThreadLocalCleanupCallback(&lt;br /&gt;               this.threadLocalMessage&lt;br /&gt;            )&lt;br /&gt;        );&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The intention was to update the thread-local Message for the current Thread. Instead the code was reassigning the shared field to a new ThreadLocal instance and the previously assigned ThreadLocal instance was probably garbage collected. Here is a visualization of the problem flow:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;Thread1 → setMessage(m1)&lt;br /&gt;   assigning new ThreadLocal1&lt;br /&gt;   ThreadLocal1.set(m1)&lt;br /&gt;Thread1 → getMessage&lt;br /&gt;    ThreadLocal1.get → m1&lt;br /&gt;Thread2 → setMessage(m2)&lt;br /&gt;   assigning new ThreadLocal2&lt;br /&gt;   ThreadLocal2.set(m2)&lt;br /&gt;Thread1 → getMessage&lt;br /&gt;   ThreadLocal2.get → null *bang*&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Took a while to spot the problem. I can really recommend to mark you static or non-static ThreadLocals as final, so this problem could not have occurred. I changed the AbstractRpcHandler to the following code and the errors disappeared.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;public abstract class AbstractRpcHandler extends RpcHandler&amp;lt;GameDaoSupport&amp;gt; {&lt;br /&gt;&lt;br /&gt;    private final ThreadLocal&amp;lt;Message&amp;gt; threadLocalMessage = new ThreadLocal&amp;lt;Message&amp;gt;();&lt;br /&gt;&lt;br /&gt;    public Message getMessage() {&lt;br /&gt;        return threadLocalMessage.get();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setMessage(final Message message) {&lt;br /&gt;        this.threadLocalMessage.set(message);&lt;br /&gt;        &lt;br /&gt;        // add a cleanup callback which will be &lt;br /&gt;        // executed from the ServletRequestCleanupFilter&lt;br /&gt;        ServletRequestCleanupService.addCleanupCallback(&lt;br /&gt;            new ServletRequestThreadLocalCleanupCallback(&lt;br /&gt;               this.threadLocalMessage&lt;br /&gt;            )&lt;br /&gt;        );&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On a side note, I found it was a good practice to cleanup the ThreadLocals after the request was finished. Not really because this represented a memory problem as the number of Threads was limited by the Jetty thread pool. Rather I felt safer, if the recycled Thread serving a new Request would not see the Message of the previously handled HTTP Request. To do the cleanup using a Servlet Filter, I &lt;a href="http://svn.apache.org/viewvc?view=revision&amp;revision=1101917"&gt;stole some code&lt;/a&gt; from the Apache Jetspeed 2 project (ServletRequestCleanupFilter, ServletRequestCleanupService, ServletRequestThreadLocalCleanupCallback and ServletRequestCleanupCallback).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-8418544715329155486?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/8418544715329155486/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=8418544715329155486' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8418544715329155486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8418544715329155486'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/07/beauties-and-pitfalls-of-threadlocals.html' title='The Beauties and Pitfalls of ThreadLocals'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-2006215664028265109</id><published>2011-07-20T00:59:00.000-07:00</published><updated>2011-07-20T01:01:46.746-07:00</updated><title type='text'>Interviewed at Google Pt.2</title><content type='html'>Some people asked me why I wasn't publishing the second part of my Google interview experience. Well I didn't care so much about Google and job interviews in general after I moved to Norway. Anyway, I finished the whole blog post back in September at the airport in Zürich. So you might as well read the rest.&lt;br /&gt;&lt;br /&gt;So lunch was great. Google has his own canteen with dedicated cooking staff etc. There is a salad bar, free drinks, desert and 3 dishes to choose from every day. Not bad. The canteen was packed when we went. It must have been 200 people or so.&lt;br /&gt; &lt;br /&gt;Anyway, after lunch the next interview was again with two people, of which one was talking and the other one listening. This time I had two coding exercises in the interview. The first one, was to come up with an implementation of a class, which you could send a function or a block of executable code to, that should then be executed after 34 seconds. The second exercise was to suggest a unit test for a function producing random floats values between 0 and 1. For the first task I picked Java as concrete language and suggested using a ThreadPoolExecutor, Callable and Thread.sleep. The interviewer asked me, how we could bring down the test execution time, as we did not want to wait 34 seconds every time the test runs. I suggested having the time span configurable, so that it would fire after the configured amount of seconds. A better answer would have been to refactor the code, so that it was given an instance of a class representing a clock. I knew the clock test pattern but I was not able to pull it out in this situation - too bad. As for second task, testing random float values, I suggested creating a test set and group/count the values using some array indices. The test validation should only allow a certain degree of deviation. The interviewer then asked me how to calculate the deviation based on the input size but it was out of my league and I could not answer. For the correct answer you need some good knowledge in statistics I suppose. This was probably the worst interview I gave this day. It was also a bit harder for me because the interviewer had a very strong French accent. I had to ask him to repeat a couple of times, which might have been annoying for him. This is particular maddening because a co-worker I worked with for 3 years was French, so I should have been used to French-English.&lt;br /&gt;&lt;br /&gt;The next interviewer was from Poland. He was a very cool guy and very friendly. We talked a bit about Apache Cassandra, which I had mentioned in my CV, since he knew one of the Facebook developers working with Cassandra. The coding exercise he had for me was about a graph problem. He gave me a class data-structure holding a list of File objects. The Files were supposed to have references to each other, pretty much like edges in a graph. I was given the task to print out the Files in a specific order. Unfortunately I understood him wrong and suggested a standard DFS traversal. But he was interested in a very specific order, which required a modified DFS approach. It was a nice interview anyways and he told me I was actually the first guy who had implemented a DFS using a stack and that he liked it. Well, I thought using a Stack for DFS was the default way, strange.&lt;br /&gt;&lt;br /&gt;Time went by and after 45 minutes I found myself again in a very test-orientated session. The first 20 minutes or so, I was asked a lot of test related questions like "How would you do performance testing and let the development team know about the results?". My gut feeling was that I didn't give very great answers to these questions. Basically in my previous companies we never had an organization, where there was a unit of Software test engineers supporting the main developers. It is often the developer itself who does the performance testing and has the results at hand.. At least at this point, I realized I should have prepared myself more for test related questions since this was a Software Engineer in Test position after all. In my preparations I spent most time focusing on solving technical questions. But okay you never know this in advance. The final coding exercise in this interview was to come up with a suggestion on how to verify a file backup (directory structure) so that it matches a given source directory. I suggested to create an abstraction for each physical file or directory which would store the filename and a checksum. Then you could do a traversal of each tree, building up two linked lists. Finally you start removing the first item in each list and compare the items. If they don't match, it is either the directory structure that was wrong or something with the files. As the last step, I had to implement this in a language of my choice. I used again Java.&lt;br /&gt;&lt;br /&gt;After a long day, the final interview started. A very nice girl, who worked with the Google search as a Software engineer, started to ask questions about my current job position. Surprise, this was actually the only time someone showed interest in what I was currently doing. I spoke about our system, the problems which we had and have. She asked me questions like "What happens if the database fails in this case?" and so on. I think she was testing my overall understanding of how different parts of a software system affect each other. The second part of the interview was performed as a code review. She had printed a function in Java and I my task was to review it. It was easy enough to find most of the potential issues like using static members (testability), not validating input, thread safety, going over the index bound of an array etc. I mixed up the explanation for bitwise XOR with AND, embarrassing but hey you are nervous. After doing the code review I had to rewrite a recursive function call into a iterative one, which I somehow managed. When the time was up, we said goodbye and she guided me out of the Zürich office building.&lt;br /&gt;&lt;br /&gt;So what do I think about the interview? I think it was a great experience. I met nice people and they showed me some of my weaknesses. The preparations I had done upfront helped me only to some extend. There were less technical questions, no behavioral questions and definitely no questions about me or Google's history. A better preparation would have been to read some books on Software testing and less books about algorithms and data-structures.&lt;br /&gt;&lt;br /&gt;So much for the second part. Here is something I am adding to the text I wrote 9 months ago. Never add technologies to your CV which you only know superficial. This can get you into embarrassing situations. Less is more. I have seen CV's for candidates who have worked with everything that exists out there - not good. For a Google interview, I think it is a plus if you know more than one language. Back then I was a Java only guy more or less. It's great if you can Python, C or C++. Some of my whiteboard examples where too Java specific, i.e. when using something like &lt;a href="http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html"&gt;ThreadPoolExecutor&lt;/a&gt; take a step back and talk more about concepts than JDK classes. Don't expect every interviewer to know the language you are good at. Finally, expect to be disappointed if you fail. This can hit you hard, especially if you are used to getting a job offer every time you been to an interview.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-2006215664028265109?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/2006215664028265109/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=2006215664028265109' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2006215664028265109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2006215664028265109'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/07/interviewed-at-google-pt2.html' title='Interviewed at Google Pt.2'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-7019209573521164416</id><published>2011-07-18T05:50:00.000-07:00</published><updated>2011-07-18T06:08:57.374-07:00</updated><title type='text'>Fluent Flexunit tests</title><content type='html'>As some of you might know, I work for a company which is doing Facebook games. Currently almost all of our Facebook games use Adobe Flash a the client and Java as the backend technology. There are different ways to have a Flex client communicate with a Java server application. For instance &lt;a href="http://opensource.adobe.com/wiki/display/blazeds/BlazeDS"&gt;BlazeDS&lt;/a&gt;, which I really like. Unfortunately we are not using BlazeDS for the games I have been involved with. Instead we are using a framework, also based on a binary format similar to &lt;a href="http://en.wikipedia.org/wiki/Action_Message_Format"&gt;AMF&lt;/a&gt;, that someone at my company has written some time ago. There are some things about this framework which I don't like but overall it is performing really good. Anyway, last weekend I started to read a great book called &lt;a href="http://manning.com/allmon/"&gt;Flex on Java&lt;/a&gt;, which was published by Manning almost half a year ago.&lt;br /&gt;&lt;br /&gt;I am not the best Action Script developer, in fact I had never written a single line of Action Script when I started at my current company. The language is quite similar to JavaScript however, so Java developers are able to learn Action Script rather fast. From the first chapters in the book I could learn some stuff about Flex that I didn't knew before. Also it woke my interest in asynchronous testing using Flexunit. Similar to the Webservice example from the book, our unit-tests are also using asynchronous service calls. Well these tests are not really unit but integration tests. The first thing that is done is to start a embedded jetty using Maven and the &lt;a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin"&gt;maven-jetty-plugin&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;build&amp;gt;&lt;br /&gt;&amp;lt;plugins&amp;gt;&lt;br /&gt;    &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.mortbay.jetty&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-jetty-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;6.1.26&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;            &amp;lt;stopKey&amp;gt;foo&amp;lt;/stopKey&amp;gt;&lt;br /&gt;            &amp;lt;stopPort&amp;gt;9999&amp;lt;/stopPort&amp;gt;&lt;br /&gt;            &amp;lt;contextPath&amp;gt;/&amp;lt;/contextPath&amp;gt;&lt;br /&gt;            &amp;lt;webApp&amp;gt;&lt;br /&gt;                ${settings.localRepository}/package/goes/here/1.0-SNAPSHOT/game-1.0-SNAPSHOT.war&lt;br /&gt;            &amp;lt;/webApp&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;        &amp;lt;executions&amp;gt;&lt;br /&gt;            &amp;lt;execution&amp;gt;&lt;br /&gt;                &amp;lt;id&amp;gt;start-jetty&amp;lt;/id&amp;gt;&lt;br /&gt;                &amp;lt;phase&amp;gt;process-test-classes&amp;lt;/phase&amp;gt;&lt;br /&gt;                &amp;lt;goals&amp;gt;&lt;br /&gt;                    &amp;lt;goal&amp;gt;deploy-war&amp;lt;/goal&amp;gt;&lt;br /&gt;                &amp;lt;/goals&amp;gt;&lt;br /&gt;                &amp;lt;configuration&amp;gt;&lt;br /&gt;                    &amp;lt;daemon&amp;gt;true&amp;lt;/daemon&amp;gt;&lt;br /&gt;                &amp;lt;/configuration&amp;gt;&lt;br /&gt;            &amp;lt;/execution&amp;gt;&lt;br /&gt;            &amp;lt;execution&amp;gt;&lt;br /&gt;                &amp;lt;id&amp;gt;stopconfigurationReport-jetty&amp;lt;/id&amp;gt;&lt;br /&gt;                &amp;lt;phase&amp;gt;prepare-package&amp;lt;/phase&amp;gt;&lt;br /&gt;                &amp;lt;goals&amp;gt;&lt;br /&gt;                    &amp;lt;goal&amp;gt;stop&amp;lt;/goal&amp;gt;&lt;br /&gt;                &amp;lt;/goals&amp;gt;&lt;br /&gt;            &amp;lt;/execution&amp;gt;&lt;br /&gt;        &amp;lt;/executions&amp;gt;&lt;br /&gt;    &amp;lt;/plugin&amp;gt;&lt;br /&gt;&amp;lt;/plugins&amp;gt;&lt;br /&gt;&amp;lt;/build&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It is a bit dirty that we are starting a WAR file straight out of the Maven repository using an absolute file path. Not sure there is a way to tell the maven-jetty-plugin to start a WAR file of a Maven dependency instead. This does the job for now.&lt;br /&gt;&lt;br /&gt;When embedded Jetty is running, our Flexunit integration tests will fire a sequence of service calls against the server. The sequence starts with resetting the test user, then some calls altering the player data and finally a call to load the test user back from the server. For the test user loaded at the end of the test, we run some Flexunit assert statements to validate that we are in the expected state. Since each of the service calls in the test sequence must be fired asynchronously, we use &lt;a href="http://docs.flexunit.org/asdocs/org/flexunit/async/Async.html"&gt;Async.handleEvent&lt;/a&gt; to wait until a certain Event has occurred otherwise we fail the test. Async.handleEvent has a Function argument called eventHandler, which will be the Function that is invoked if the Event has been fired successfully. Given that your service call sequence has a few steps, the test quickly mutates into a chain of Function calls of private Functions within the same test class. If you are coming from a &lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt; or &lt;a href="http://testng.org/doc/index.html"&gt;TestNG&lt;/a&gt; background, these sort of tests are not very attractive. For another developer, just from reading the code, it might be really hard to follow the test flow. I found myself adding comments all over the place, documenting where the test is continuing and what we were testing.&lt;br /&gt;&lt;br /&gt;Here is a typical test which I made up to give you an example: &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;    public class AlterPlayerTest {&lt;br /&gt;&lt;br /&gt;        private static const TIMEOUT : int = 2000;&lt;br /&gt;&lt;br /&gt;        private static const INITIALIZED : String = "initialized";&lt;br /&gt;        private static const SAVED : String = "saved";&lt;br /&gt;        private static const LOADED : String = "loaded";&lt;br /&gt; private static const FAILED : String = "failed";&lt;br /&gt;&lt;br /&gt; private var eventDispatcher : EventDispatcher = new EventDispatcher();&lt;br /&gt;        private var rpcClient : RpcClient;&lt;br /&gt;        private var user : User = null;&lt;br /&gt;&lt;br /&gt;        public function AlterPlayerTest() { }&lt;br /&gt;&lt;br /&gt;        [Test(async)]&lt;br /&gt;        public function testAlteringUser() : void {&lt;br /&gt;            this.rpcClient = new RpcClient(ConnectionParameters.getValues());&lt;br /&gt;&lt;br /&gt;            // make sure the user is created on the server side &lt;br /&gt;            this.rpcClient.init(dispatchInitializeEvent, dispatchFailEvent);&lt;br /&gt;            Async.handleEvent(this, this.eventDispatcher, INITIALIZED, alterUser, TIMEOUT);  // flow continues in alterUser function&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private function alterUser(evt : Event, passThru : Object) : void {&lt;br /&gt;            var user : User = new User();&lt;br /&gt;            user.id = new NetworkId(NetworkId.FACEBOOK, "189891015686187");&lt;br /&gt;&lt;br /&gt;            // make sure all objects are gone&lt;br /&gt;            var removeAll : RemoveAllObjects = new RemoveAllObjects();&lt;br /&gt;&lt;br /&gt;            var changeBatch : ChangeBatch = new ChangeBatch(new ArrayCollection([ removeAll ]).source);&lt;br /&gt;&lt;br /&gt;            this.rpcClient.saveUserUsingChangeBatch(dispatchSavedEvent, dispatchFailEvent, user, changeBatch);&lt;br /&gt;            Async.handleEvent(this, this.eventDispatcher, SAVED, reloadChangedUser, TIMEOUT);   // flow continues in the reloadChangedUser function&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private function reloadChangedUser(evt : Event, passThru : Object) : void {&lt;br /&gt;            // load back the user and verify that the RemoveAllObjects has been applied&lt;br /&gt;            this.rpcClient.load(dispatchUserLoadedEvent, dispatchFailEvent);&lt;br /&gt;            Async.handleEvent(this, this, LOADED, assertChanges, TIMEOUT);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private function assertChanges(evt : Event, passThru : Object) : void {&lt;br /&gt;            var user : User = this.user;&lt;br /&gt;            Assert.assertNotNull("user should not be null", user);&lt;br /&gt;&lt;br /&gt;            var objects : WorldObjects = this.user.worldObjects;&lt;br /&gt;            Assert.assertTrue("user should not have any objects left but had " + objects.length, objects.length == 0);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private function dispatchInitializeEvent(... args) : void {&lt;br /&gt;            dispatchEvent(new Event(INITIALIZED));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private function dispatchSavedEvent(results : Array) : void {&lt;br /&gt;            dispatchEvent(new Event(SAVED));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private function dispatchUserLoadedEvent(user : User) : void {&lt;br /&gt;            this.user = user;&lt;br /&gt;            dispatchEvent(new Event(LOADED));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private function dispatchFailEvent() : void {&lt;br /&gt;            dispatchEvent(new Event("Failed"));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the AlterPlayerTest the service call sequence has contains only 3 service calls. The initial Flexunit test method is called testAlteringUser from which rpcClient.init is invoked. The test will break if no INITIALIZED Event is fired within 2 seconds. If the INITIALIZED Event is dispatched properly, the test flow continues with the alterUser function in which the service call rpcClient.saveUserUsingChangeBatch is made. Here the test expects the SAVED Event or it will fail. Being successful, the test will finally continue in reloadChangedUser, where the last service call rpcClient.load is made. Here the test user is retrieved from the Java server backend and again, a LOADED Event is expected. At the end the test is asserting that the test user has been altered. &lt;br /&gt;&lt;br /&gt;While this test might be fine, we often have test scenarios where different game players interact with each other and the service call sequence is 10+ calls long, which makes the test really hard to read.&lt;br /&gt;&lt;br /&gt;Fortunately today I found a nice framework called &lt;a href="http://code.google.com/p/fluint/wiki/Sequences"&gt;Fluint Sequences&lt;/a&gt; which has been contributed and become &lt;a href="http://docs.flexunit.org/index.php?title=Fluint_Sequences"&gt;part of Flexunit&lt;/a&gt;. As the name suggests, use this if you want to write a fluent sequence of service calls within your test case. So here is a rewrite of the test above using Fluint Sequences:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;public class AlterPlayerSequentiallyTest {&lt;br /&gt;&lt;br /&gt; private static const TIMEOUT : int = 2000;&lt;br /&gt;&lt;br /&gt; private static const INITIALIZED : String = "initialized";&lt;br /&gt; private static const SAVED : String = "saved";&lt;br /&gt; private static const LOADED : String = "loaded";&lt;br /&gt; private static const FAILED : String = "failed";&lt;br /&gt;&lt;br /&gt; private var eventDispatcher : EventDispatcher = new EventDispatcher();&lt;br /&gt;&lt;br /&gt; public function AlterPlayerSequentiallyTest() { }&lt;br /&gt;&lt;br /&gt; [Test(async)]&lt;br /&gt; public function testAlteringUser() : void {&lt;br /&gt;     var rpcClient = new RpcClient(ConnectionParameters.getValues());&lt;br /&gt;     &lt;br /&gt;     var user : User = new User();&lt;br /&gt;     user.id = new NetworkId(NetworkId.FACEBOOK, "189891015686187");&lt;br /&gt;&lt;br /&gt;     var passThroughData : Object = new Object();&lt;br /&gt;     passThroughData.usr = null;&lt;br /&gt;&lt;br /&gt;     var sequence:SequenceRunner = new SequenceRunner(this);&lt;br /&gt;&lt;br /&gt;     // make sure the user is created on the server side &lt;br /&gt;     sequence.addStep(sequenceCaller(rpcClient.init,&lt;br /&gt;      [function() : void {&lt;br /&gt;          eventDispatcher.dispatchEvent(new Event(INITIALIZED));&lt;br /&gt;      }, dispatchFailEvent]&lt;br /&gt;  )&lt;br /&gt;     );&lt;br /&gt;     sequence.addStep(new SequenceWaiter(this.eventDispatcher, INITIALIZED, TIMEOUT));&lt;br /&gt;&lt;br /&gt;     // make sure all objects are gone&lt;br /&gt;     sequence.addStep(sequenceCaller(rpcClient.saveUserUsingChangeBatch,&lt;br /&gt;      [function() : void {&lt;br /&gt;          eventDispatcher.dispatchEvent(new Event(SAVED));&lt;br /&gt;      }, dispatchFailEvent, user, new ChangeBatch(new ArrayCollection([ new RemoveAllObjects() ]).source)]&lt;br /&gt;  )&lt;br /&gt;     );&lt;br /&gt;     sequence.addStep(new SequenceWaiter(this.eventDispatcher, SAVED, TIMEOUT));&lt;br /&gt;&lt;br /&gt;     // reload user and store in passThroughData&lt;br /&gt;     sequence.addStep(sequenceCaller(rpcClient.load,&lt;br /&gt;      [function(user : User) : void {&lt;br /&gt;          passThroughData.usr = user;&lt;br /&gt;          eventDispatcher.dispatchEvent(new Event(LOADED));&lt;br /&gt;      }, dispatchFailEvent]&lt;br /&gt;  )&lt;br /&gt;     );&lt;br /&gt;     sequence.addStep(new SequenceWaiter(this.eventDispatcher, LOADED, TIMEOUT));&lt;br /&gt;&lt;br /&gt;     // assert changes&lt;br /&gt;     sequence.addAssertHandler(assertChanges, passThroughData);&lt;br /&gt;&lt;br /&gt;     // start the test&lt;br /&gt;     sequence.run();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private function sequenceCaller(fnc : Function, args : Array) {&lt;br /&gt;     return new SequenceCaller(&lt;br /&gt;  this.eventDispatcher,&lt;br /&gt;  fnc,&lt;br /&gt;  args&lt;br /&gt;     )&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private function assertChanges(evt : Event, passThroughData : Object) : void {&lt;br /&gt;     var user : User = passThroughData.usr;&lt;br /&gt;     Assert.assertNotNull("user should not be null", user);&lt;br /&gt;&lt;br /&gt;     var objects : WorldObjects = this.user.worldObjects;&lt;br /&gt;     Assert.assertTrue("user should not have any objects left but had " + objects.length, objects.length == 0);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private function dispatchFailEvent() : void {&lt;br /&gt;     dispatchEvent(new Event("Failed"));&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This test is not at all shorter than the first one but I think it is much easier to read and understand. Also some private member fields could be changed to local variables. The bread and butter of this test is the SequenceRunner, which acts as a container for &lt;a href="http://docs.flexunit.org/asdocs/org/fluint/sequence/package-detail.html"&gt;steps&lt;/a&gt; which should be executed in order. No step will be executed until you invoke SequenceRunner.run() however. The first step is a SequenceCaller wrapping the rpcClient.init call followed by a SequenceWaiter step which waits the specified time for the INITIALIZED Event to occur. I do the same thing for altering and reloading the user. Finally I define and execute a Function to contain my assertions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-7019209573521164416?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/7019209573521164416/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=7019209573521164416' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7019209573521164416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7019209573521164416'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/07/fluent-flexunit-tests.html' title='Fluent Flexunit tests'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-8569569665217574189</id><published>2011-06-23T08:22:00.000-07:00</published><updated>2011-06-23T08:45:33.918-07:00</updated><title type='text'>Bean Definition Profiles and PropertySource in Spring 3.1</title><content type='html'>Spring 3.1 is just around the corner, so it is time to have a look at what is coming. Honestly, I think there are so many changes in this releases, that I would have called this Spring 3.5 instead, but ok. The new features I am going to blog about today are Bean Definition Profiles and Property Sources. &lt;br /&gt;&lt;br /&gt;As a Spring 1.2 dude, I have often been in a situation where you needed a Spring bean to be different based on different environments. The most common scenario is this. Lets say you are configuring your MySQL database access like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;       xsi:schemaLocation="&lt;br /&gt;            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;bean id="properties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&amp;gt;&lt;br /&gt;        &amp;lt;property name="ignoreResourceNotFound" value="true"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="locations"&amp;gt;&lt;br /&gt;            &amp;lt;list&amp;gt;&lt;br /&gt;                &amp;lt;value&amp;gt;classpath:app.properties&amp;lt;/value&amp;gt;&lt;br /&gt;            &amp;lt;/list&amp;gt;&lt;br /&gt;        &amp;lt;/property&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&amp;gt;&lt;br /&gt;        &amp;lt;property name="driverClassName" value="com.mysql.jdbc.Driver"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="url" value="${app.db.url}"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="username" value="${app.db.username}"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="password" value="${app.db.password}"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="validationQuery" value="SELECT 1 FROM DUAL"/&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now when running local unit test, you don't want them to mess with a real MySQL server, even though this is sort of the only way to surface these nasty MySQL integration problems. However, you want unit tests to run super fast, i.e. in memory. So what you are thinking about is something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;    &amp;lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&amp;gt;&lt;br /&gt;        &amp;lt;property name="driverClassName" value="org.hsqldb.jdbcDriver"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="url" value="jdbc:hsqldb:mem:data"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="username" value="sa"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="password" value=""/&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A HSQLDB that runs in memory. Now there are several approaches to switch the Spring beans. What I like to do is to use the bean overriding feature. That is to create a second main file for the &lt;a href="http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/context/ApplicationContext.html"&gt;ApplicationContext&lt;/a&gt; which will re-use the first applicationContext.xml file. Lets call the second file testApplicationContext.xml. It will look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;       xsi:schemaLocation="&lt;br /&gt;            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;import resource="applicationContext.xml" /&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&amp;gt;&lt;br /&gt;        &amp;lt;property name="driverClassName" value="org.hsqldb.jdbcDriver"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="url" value="jdbc:hsqldb:mem:data"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="username" value="sa"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="password" value=""/&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The bean definitions in this file will overwrite the previous bean definitions. The testApplicationContext.xml file is used like this in unit tests:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;@RunWith(SpringJUnit4ClassRunner.class)&lt;br /&gt;@ContextConfiguration(locations="/testApplicationContext.xml")&lt;br /&gt;public class SomeTest {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All good. This works well whenever you can overwrite the beans. There are alternatives. In the classpath, you could have subdirectories named after your environment, i.e. integration, production etc. Then you write some intelligent bean loader mechanism that dynamically includes the correct files. The same is possible by using &lt;span style="font-weight:bold;"&gt;&amp;lt;import resource="beans-${environment}.xml" /&amp;gt;&lt;/span&gt;. Spring 3.1 is addressing the problem and comes with a solution in form of the so called bean definition profiles. It will allow you to do 2 new things. You can specify a profile attribute in a beans element and you are allowed to nest beans-elements, so you can have all profiles in one XML file.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;       xsi:schemaLocation="&lt;br /&gt;            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;bean id="properties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&amp;gt;&lt;br /&gt;        &amp;lt;property name="ignoreResourceNotFound" value="true"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="locations"&amp;gt;&lt;br /&gt;            &amp;lt;list&amp;gt;&lt;br /&gt;                &amp;lt;value&amp;gt;classpath:app.properties&amp;lt;/value&amp;gt;&lt;br /&gt;            &amp;lt;/list&amp;gt;&lt;br /&gt;        &amp;lt;/property&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;beans profile="testing"&amp;gt;&lt;br /&gt;        &amp;lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&amp;gt;&lt;br /&gt;            &amp;lt;property name="driverClassName" value="org.hsqldb.jdbcDriver"/&amp;gt;&lt;br /&gt;            &amp;lt;property name="url" value="jdbc:hsqldb:mem:data"/&amp;gt;&lt;br /&gt;            &amp;lt;property name="username" value="sa"/&amp;gt;&lt;br /&gt;            &amp;lt;property name="password" value=""/&amp;gt;&lt;br /&gt;        &amp;lt;/bean&amp;gt;&lt;br /&gt;    &amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;beans profile="production"&amp;gt;&lt;br /&gt;        &amp;lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&amp;gt;&lt;br /&gt;            &amp;lt;property name="driverClassName" value="com.mysql.jdbc.Driver"/&amp;gt;&lt;br /&gt;            &amp;lt;property name="url" value="${app.db.url}"/&amp;gt;&lt;br /&gt;            &amp;lt;property name="username" value="${app.db.username}"/&amp;gt;&lt;br /&gt;            &amp;lt;property name="password" value="${app.db.password}"/&amp;gt;&lt;br /&gt;            &amp;lt;property name="validationQuery" value="SELECT 1 FROM DUAL"/&amp;gt;&lt;br /&gt;        &amp;lt;/bean&amp;gt;&lt;br /&gt;    &amp;lt;/beans&amp;gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now you need to tell Spring which profile is active. Spring will be looking for a property called &lt;span style="font-weight:bold;"&gt;spring.profiles.active&lt;/span&gt;, which can be a single profile or a comma-separated list of profiles. In Spring 3.1 each ApplicationContext has a reference to a new Object which implements the new Environment Interface. This Environment instance knows all the active profiles and can therefore select the right beans out of the configuration files. To programmatically set the active profiles you would do:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;final ApplicationContext applicationContext = new GenericXmlApplicationContext();&lt;br /&gt;&lt;br /&gt;applicationContext.getEnvironment().setActiveProfiles("integration");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;IntelliJ 10.5 already &lt;a href="http://blogs.jetbrains.com/idea/2011/04/new-in-105-spring-31-bean-definition-profiles/"&gt;supports this&lt;/a&gt; by the way. You specify an active bean definition profile and IntelliJ will grey out the sections within the Spring configuration that are not affected by this profile - very cool. Back to the spring.profiles.active property. Spring 3.1 comes also with something new called &lt;a href="http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/core/env/PropertySource.html"&gt;PropertySource&lt;/a&gt;, which is as the name suggests a source for Properties. To identify the value for  spring.profiles.active it will go through a hierarchy of property sources. The &lt;a href="http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/core/env/StandardEnvironment.html"&gt;StandardEnvironment&lt;/a&gt; class has a PropertySource for system environment variables and JVM system properties, the latter one being more specific so it will be checked first. If you have a web application, there will also be a PropertySource for properties within the web.xml. This is done through the &lt;a href="http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/web/context/support/StandardServletEnvironment.html"&gt;StandardServletEnvironment&lt;/a&gt;. So there are different ways to set spring.profiles.active for your application. You can have this on system level:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;export spring.profiles.active=production&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or start your application using:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;-D spring.profiles.active=production&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or have a web.xml like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;servlet&amp;gt;&lt;br /&gt;    &amp;lt;servlet-name&amp;gt;dispatcher&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;    &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;    &amp;lt;init-param&amp;gt;&lt;br /&gt;        &amp;lt;param-name&amp;gt;spring.profiles.active&amp;lt;/param-name&amp;gt;&lt;br /&gt;        &amp;lt;param-value&amp;gt;production&amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/init-param&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;These PropertySources are a really great feature. I like them even more than the &lt;a href="http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/"&gt;bean definition profiles&lt;/a&gt;. I could imagine that your XML configuration can get a bit messy and hard to read if you use the profiles over excessively. I think I will stick with the bean override stuff for a while and see if the &lt;a href="http://hillert.blogspot.com/2011/04/spring-31-bean-definition-profiles-for.html"&gt;profiles&lt;/a&gt; are really better. &lt;br /&gt;&lt;br /&gt;Totally unrelated and I don't remember why exactly, but recently I needed a mechanism to copy the properties for a Spring application back into System.properties when the application was loading. I think I used these properties from Spring powered beans but there were some legacy parts that were expecting them to be system properties. Here is a class that did this for me, maybe you find this useful.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;import java.util.Properties;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * A {@link PropertyPlaceholderConfigurer} merging loaded {@link Properties} with System {@link Properties}.&lt;br /&gt; *&lt;br /&gt; * Author: reik, 3/15/11&lt;br /&gt; */&lt;br /&gt;public class SystemPropertiesMergingPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Does the same as {@link PropertyPlaceholderConfigurer#mergeProperties()} but additionally merges the properties&lt;br /&gt;     * back into {@link System#getProperties()} before returning the loaded {@link Properties}.&lt;br /&gt;     *&lt;br /&gt;     * @return Properties&lt;br /&gt;     * @throws IOException&lt;br /&gt;     */&lt;br /&gt;    @Override&lt;br /&gt;    protected Properties mergeProperties() throws IOException {&lt;br /&gt;        final Properties springProperties = super.mergeProperties();&lt;br /&gt;        System.getProperties().putAll(springProperties);&lt;br /&gt;        return springProperties;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-8569569665217574189?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/8569569665217574189/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=8569569665217574189' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8569569665217574189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8569569665217574189'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/06/bean-definition-profiles-and.html' title='Bean Definition Profiles and PropertySource in Spring 3.1'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-3332096971915842993</id><published>2011-06-16T06:03:00.000-07:00</published><updated>2011-06-16T06:10:08.171-07:00</updated><title type='text'>When a design smell couldn't be more obvious</title><content type='html'>Today I was working on a small refactoring which I applied to a &lt;a href="http://download.oracle.com/javaee/1.4/api/javax/servlet/http/HttpServlet.html"&gt;HttpServlet&lt;/a&gt; that exists in our shared codebase. This Servlet was written in a way which made it almost impossible to extend. A lot of private static methods, communicating with the database or accession filesystem resources, made this class really nice to test - ironically. In order to get anywhere, I initially decided to re-use the code by using the “copy-paste-change” pattern. A few weeks later I changed my mind and decided to make the shared code more extensible by refactoring the methods to be protected non-static. When I was done and I ran the testsuite, I saw that one test was failing. &lt;br /&gt;&lt;br /&gt;Here is a snippet of a unit test that someone had written.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;public class SomeTest {&lt;br /&gt;    private Method logMethod;&lt;br /&gt;&lt;br /&gt;    @BeforeMethod&lt;br /&gt;    public void setup() throws NoSuchMethodException {&lt;br /&gt;        logMethod = TheServlet.class.getDeclaredMethod(&lt;br /&gt;           "logEvent", new Class[] {&lt;br /&gt;                Parameter1.class, &lt;br /&gt;                Parameter2.class, &lt;br /&gt;                Parameter3.class}&lt;br /&gt;        );       &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Test&lt;br /&gt;    public void testLogging() throws Exception {&lt;br /&gt;        logMethod.setAccessible(true);&lt;br /&gt;&lt;br /&gt;        // some set-up&lt;br /&gt;&lt;br /&gt;        logMethod.invoke(null, parameter1, parameter2, parameter3);&lt;br /&gt;&lt;br /&gt;        // asserts&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Holy! I have seldom seen crappier code (and I am not even going to talk about having to catch Exception in the test method). Someone was getting a reference to the previously private static method inside the Servlet class, to be able to make it accessible via Reflection and invoke it from the test. Really, a design smell could not be more apparent. If you want to test the method, in that case it was doing some logging to the database, write a collaborator class to do the logging for you, that can be tested in isolation and is injected as a dependency. It is always good to take a step backwards and look at the million things you have to do in order to test stuff. This will most likely &lt;a href="http://www.growing-object-oriented-software.com/index.html"&gt;guide&lt;/a&gt; you to a better design of your software.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-3332096971915842993?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/3332096971915842993/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=3332096971915842993' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3332096971915842993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3332096971915842993'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/06/when-design-smell-couldnt-be-more.html' title='When a design smell couldn&apos;t be more obvious'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-799911205850897009</id><published>2011-02-01T04:50:00.000-08:00</published><updated>2011-03-04T09:36:10.935-08:00</updated><title type='text'>Continuous GUI Integration Testing</title><content type='html'>I started reading "&lt;a href="http://www.growing-object-oriented-software.com/"&gt;Growing Object-Oriented Software Guided by Tests&lt;/a&gt;" from Steve Freeman and Nat Pryce. The book is about effectively implementing Test-Driven-Development. One of the key statements in the book, is that you should always start with a (failing) end-to-end integration test also called a "walking skeleton" before you write any code. In part III the authors give a working example in form of a Java Swing application. They use a GUI test framework called &lt;a href="http://code.google.com/p/windowlicker/"&gt;Window Licker&lt;/a&gt; which can automatically test Swing applications. Nat Pryce, one of the authors, drives the Window Licker project.&lt;br /&gt;&lt;br /&gt;Since I will start to develop Facebook games for Electronic Arts in Norway in a little while, I was looking into TDD and end-to-end testing in this area. Even though I will only be responsible for server backend development, a good continuously integrated working skeleton should probably test the GUI. There are several good GUI testing frameworks like &lt;a href="http://watirmelon.com/2010/04/10/watir-selenium-webdriver/"&gt;Selenium or Watir&lt;/a&gt;. The tests can be written like standard &lt;a href="http://www.ibm.com/developerworks/java/library/j-cq04037/"&gt;unit tests&lt;/a&gt; and run automated. However, since they make use of API integration points, it is not trivial to test Flash based applications. Selenium for instance, &lt;a href="http://agiletesting.blogspot.com/2006/01/useful-tools-for-writing-selenium.html"&gt;uses the id-attributes&lt;/a&gt; to interact and validate HTML elements within a web page.&lt;br /&gt;&lt;br /&gt;I came across a really interesting new framework called &lt;a href="http://sikuli.org/"&gt;Project Sikuli&lt;/a&gt;. This library uses image recognition to identify screen elements. Sikuli is not really meant to only support GUI testing but rather to automate every-day tasks that involve a GUI. Everything that can be seen on the screen, can be scripted, not only the web browser. I can have a Sikuli script that clicks on "System &gt; Administration &gt; Nvidia X Server Settings" in Ubuntu and changes my screen resolution if I wanted to. Sikuli comes with a minimalistic IDE which allows you to take snapshot of a screen region that you want to interact with. In addition to that, using the IDE you can also test how well your snapshot region is recognized on the screen. The better it is recognized, the less often your unit tests will fail. Since the project is written in Java, there is also a &lt;a href="http://sikuli.org/docx/faq/java-dev.html"&gt;Java library&lt;/a&gt; which enables you to write unit tests using Sikuli.&lt;br /&gt;&lt;br /&gt;Let's give a working example. I want to write a integration test, that can be run automatically using Maven. The test should login to Facebook, go to the Farmville (actually a Flash game from our biggest competitor &lt;a href="http://www.zynga.com/"&gt;Zynga&lt;/a&gt;), click on the "Gifts" icon, click on "Sell" and finally click on the "Cancel" button. I am using Sikuli 0.10.2 in this example. &lt;a href="http://www.webupd8.org/2010/05/sikuli-101-released-easily-automate.html"&gt;First step&lt;/a&gt; to install all required dependencies in Ubuntu. Next step to download Sikuli 0.10.2 and add it to my local Maven repository since it is not available in any official Maven repository yet. Having Sikuli available as dependency, it is time for the first unit test.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;package lantern.day.gui;&lt;br /&gt;&lt;br /&gt;import edu.mit.csail.uid.FindFailed;&lt;br /&gt;import edu.mit.csail.uid.Screen;&lt;br /&gt;import org.junit.Before;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;&lt;br /&gt;import java.net.URL;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Verifies selling gifts can be cancelled in Farmville using&lt;br /&gt; * the Sikuli test framework.&lt;br /&gt; *&lt;br /&gt; * @author reiks, Jan 28, 2011&lt;br /&gt; */&lt;br /&gt;public class FarmvilleCancelGiftSellingTest {&lt;br /&gt;&lt;br /&gt;    private Screen _screen;&lt;br /&gt;&lt;br /&gt;    @Before&lt;br /&gt;    public void setUp() {&lt;br /&gt;        _screen = new Screen();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Test&lt;br /&gt;    public void openFacebookHomepage() throws FindFailed {&lt;br /&gt;        openChrome();&lt;br /&gt;        goToURL("http://www.facebook.com/");&lt;br /&gt;        login();&lt;br /&gt;        startFarmville();&lt;br /&gt;        cancelSellingOfGifts();&lt;br /&gt;        closeChrome();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private String fullPath(final String fileName) {&lt;br /&gt;        final URL url =  ClassLoader.getSystemResource(fileName);&lt;br /&gt;        return url.getFile();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void login() throws FindFailed {&lt;br /&gt;        _screen.type(fullPath("email.png"), "password\n", 0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void openChrome() throws FindFailed {&lt;br /&gt;        _screen.click(fullPath("chrome_icon.png"), 0);&lt;br /&gt;        _screen.wait(fullPath("new_tab.png"));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void closeChrome() throws FindFailed {&lt;br /&gt;        _screen.click(fullPath("close.png"), 0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void goToURL(final String url) throws FindFailed {&lt;br /&gt;        _screen.paste(fullPath("url_bar.png"), url);&lt;br /&gt;        _screen.type(fullPath("url_bar.png"), "\n", 0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void startFarmville() throws FindFailed {&lt;br /&gt;        _screen.click(fullPath("farmville_icon.png"), 0);&lt;br /&gt;        _screen.wait(fullPath("gift.png"), 5000);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void cancelSellingOfGifts() throws FindFailed {&lt;br /&gt;        _screen.click(fullPath("gift.png"), 0);&lt;br /&gt;        _screen.wait(fullPath("sell.png"), 1000);&lt;br /&gt;        _screen.click(fullPath("sell.png"), 0);&lt;br /&gt;        _screen.wait(fullPath("cancel.png"), 1000);&lt;br /&gt;        _screen.click(fullPath("cancel.png"), 0);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-weight:bold;"&gt;FarmvilleCancelGiftSellingTest&lt;/span&gt; will open my local Google Chrome browser, go to http://www.facebook.com/, enter some test user credentials to log in, click the small Farmville icon to the left and so on. The test requires a couple of PNG files which Sikuli will use to identify the screen elements which it needs to click and validate. In this very simple test case, I am mainly using two methods of the &lt;a href="http://sikuli.org/doc/java-x/org/sikuli/script/Screen.html"&gt;edu.mit.csail.uid.Screen&lt;/a&gt; instance - click and wait. First I click an image then I wait for another image to be present on the screen. If the image I am waiting for is not found, the test will fail. I also use the type and paste functions in this class, to enter text into HTML text fields.&lt;br /&gt;&lt;br /&gt;One important aspect of automated GUI integration testing, is the ability to check what went wrong if tests start to fail. Some developers have scripted their builds to take screen-shots during the test run, I decided to record the desktop as a video. &lt;a href="http://code.google.com/p/windowlicker/wiki/HowToRecordTheActivityOfFailingTests"&gt;An idea which I stole&lt;/a&gt; from the Window Licker website. Instead of using a JUnitResultFormatter, I wrote a RunListener that is being used from the &lt;a href="http://maven.apache.org/plugins/maven-surefire-plugin/examples/junit.html"&gt;maven-surefire-plugin&lt;/a&gt;. The code of the RunListener is almost identical to the ResultFormatter. Every test is being recorded using the Linux program &lt;a href="http://recordmydesktop.sourceforge.net/about.php"&gt;recordmydesktop&lt;/a&gt;. If the unit test is failing, the video file is kept otherwise it is deleted. Here is the video for the &lt;span style="font-weight:bold;"&gt;FarmvilleCancelGiftSellingTest&lt;/span&gt;. It is running a bit fast as a video clip. During the actual test execution it is running much slower. &lt;span style="font-weight:bold;"&gt;*Update*&lt;/span&gt; thanks to &lt;a href="http://embedplus.com/"&gt;EmbedPlus&lt;/a&gt; you can play the video in slow motion now. Just click the "Slow" button before you start playing the video. What you see in the video, is a Maven build starting a Chrome browser, executing and recording the test.&lt;br /&gt;&lt;br /&gt;&lt;!--start_raw--&gt;&lt;object type="application/x-shockwave-flash" width="600" height="512" data="http://getembedplus.com/embedplus.swf"&gt;&lt;br /&gt;&lt;param value="http://getembedplus.com/embedplus.swf" name="movie" /&gt;&lt;br /&gt;&lt;param value="high" name="quality" /&gt;&lt;br /&gt;&lt;param value="transparent" name="wmode" /&gt;&lt;br /&gt;&lt;param value="always" name="allowscriptaccess" /&gt;&lt;br /&gt;&lt;param value="true" name="allowFullScreen" /&gt;&lt;br /&gt;&lt;param name="flashvars" value="ytid=wz61YtMIWh8&amp;width=600&amp;height=480&amp;start=&amp;hd=0&amp;react=0&amp;chapters=&amp;notes=" /&gt;&lt;br /&gt;&lt;object class="cantembedplus" height="480" width="600" type="application/x-shockwave-flash"&lt;br /&gt;data="http://www.youtube.com/v/wz61YtMIWh8?fs=1"&gt;&lt;br /&gt;&lt;param name="movie" value="http://www.youtube.com/v/wz61YtMIWh8?fs=1" /&gt;&lt;br /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;br /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;br /&gt;&lt;param name="wmode" value="transparent" /&gt;&lt;br /&gt;&lt;/object&gt;&lt;br /&gt;&lt;/object&gt;&lt;br /&gt;&lt;!--[if lte IE 6]&gt; &lt;style type="text/css"&gt;.cantembedplus{display:none;}&lt;/style&gt;&lt;![endif]--&gt;&lt;!--end_raw--&gt;&lt;br /&gt;&lt;br /&gt;And finally the pom.xml I am using to run the Sikuli tests from Maven.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&amp;gt;&lt;br /&gt;    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;lantern.day&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;gui-testing&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;name&amp;gt;Automated GUI Testing using Project Sikuli&amp;lt;/name&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;project.build.sourceEncoding&amp;gt;UTF-8&amp;lt;/project.build.sourceEncoding&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;dependencies&amp;gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;org.sikuli&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;sikuli-script&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;0.10.2&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;org.apache.ant&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;ant-junit&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;1.8.2&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;4.4&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;/dependencies&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;build&amp;gt;&lt;br /&gt;        &amp;lt;plugins&amp;gt;&lt;br /&gt;            &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                &amp;lt;configuration&amp;gt;&lt;br /&gt;                    &amp;lt;source&amp;gt;1.6&amp;lt;/source&amp;gt;&lt;br /&gt;                    &amp;lt;target&amp;gt;1.6&amp;lt;/target&amp;gt;&lt;br /&gt;                    &amp;lt;showWarnings&amp;gt;false&amp;lt;/showWarnings&amp;gt;&lt;br /&gt;                    &amp;lt;showDeprecation&amp;gt;false&amp;lt;/showDeprecation&amp;gt;&lt;br /&gt;                &amp;lt;/configuration&amp;gt;&lt;br /&gt;            &amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;br /&gt;            &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                &amp;lt;version&amp;gt;2.7.2&amp;lt;/version&amp;gt;&lt;br /&gt;                &amp;lt;configuration&amp;gt;&lt;br /&gt;                    &amp;lt;properties&amp;gt;&lt;br /&gt;                        &amp;lt;property&amp;gt;&lt;br /&gt;                            &amp;lt;name&amp;gt;listener&amp;lt;/name&amp;gt;&lt;br /&gt;                            &amp;lt;value&amp;gt;lantern.day.gui.junit.RecordingListener&lt;br /&gt;    &amp;lt;/value&amp;gt;&lt;br /&gt;                        &amp;lt;/property&amp;gt;&lt;br /&gt;                    &amp;lt;/properties&amp;gt;&lt;br /&gt;                &amp;lt;/configuration&amp;gt;&lt;br /&gt;            &amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;/plugins&amp;gt;&lt;br /&gt;    &amp;lt;/build&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-799911205850897009?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/799911205850897009/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=799911205850897009' title='2 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/799911205850897009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/799911205850897009'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/02/continuous-gui-integration-testing.html' title='Continuous GUI Integration Testing'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-8873361659671974900</id><published>2011-01-11T08:00:00.000-08:00</published><updated>2011-01-11T08:14:28.152-08:00</updated><title type='text'>My favorite bug in 2011</title><content type='html'>Well, the year is still young but I thought to post my favorite bug in 2011 so far. It was a Spring related piece of code which I had added to a legacy application. Can you spot the problem?&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;bean id="deactivationDateFormat" class="java.text.SimpleDateFormat" scope="prototype"&amp;gt;&lt;br /&gt;&amp;lt;constructor-arg value="yyyy-MM-dd HH:mm:ss" /&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bean id="gamePeriodStatsService" scope="prototype" &lt;br /&gt;  class="gameperiodstats.impl.GamePeriodStatsServiceImpl"&amp;gt;&lt;br /&gt;&amp;lt;property name="dao" ref="gamePeriodStatsDAO"/&amp;gt;&lt;br /&gt;&amp;lt;property name="globalPropertyService" ref="globalPropertyService"/&amp;gt;&lt;br /&gt;&amp;lt;property name="gamePeriodStatsUpdater" ref="gamePeriodStatsUpdater"/&amp;gt;&lt;br /&gt;&amp;lt;property name="gpsDeactivationDate"&amp;gt;&lt;br /&gt;    &amp;lt;bean factory-bean="deactivationDateFormat" factory-method="parse"&amp;gt;&lt;br /&gt;        &amp;lt;constructor-arg value="${gps.deactivation.date}" /&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The change I made to the existing application was to add the &lt;span style="font-style:italic;"&gt;gpsDeactivationDate&lt;/span&gt; field into the &lt;span style="font-style:italic;"&gt;GamePeriodStatsServiceImpl&lt;/span&gt; class. I decided to make this a field of type &lt;span style="font-style:italic;"&gt;Date&lt;/span&gt; and use the &lt;span style="font-style:italic;"&gt;SimpleDateFormat&lt;/span&gt; class inside the Spring configuration to parse a String value while the &lt;span style="font-style:italic;"&gt;ApplicationContext&lt;/span&gt; is initialized. The String value has to be in the format &lt;span style="font-style:italic;"&gt;yyyy-MM-dd HH:mm:ss&lt;/span&gt; and is read from a Java properties file (not shown). The property holding the date as String is called &lt;span style="font-style:italic;"&gt;gps.deactivation.date&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;We released the code into one of our integration test systems. A few days later, I got assigned a bug in Jira from one of the testers. He copied me a stacktrace from a logfile. As you can see below, there is a lot of noise in the Exception logging from JBoss and Spring. The information you are interested in, is on the last line.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;2010-12-31 17:00:34,565 ERROR [] &lt;br /&gt;[foo.util.jboss.log.LogInterceptor] &lt;br /&gt;RuntimeException in method: public abstract void foo.util.cron.ejb.CronInvokerLocal.invokeSpring&lt;br /&gt;(java.lang.String,java.lang.String,java.lang.String) throws java.lang.ClassNotFoundException,java.lang.NoSuchMethodException,&lt;br /&gt;java.lang.reflect.InvocationTargetException,java.lang.IllegalAccessException:&lt;br /&gt; [] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'networkStatsService' defined in class path resource [service/addons/networkstats.applicationContext.xml]: Cannot resolve reference to bean 'gamePeriodStatsService' while setting bean property 'gamePeriodStatsService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gamePeriodStatsService' defined in class path resource [service/addons/gameperiodstats.applicationContext.xml]: Cannot create inner bean 'deactivationDateFormat$created#335fbef1' while setting bean property 'gpsDeactivationDate'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'deactivationDateFormat$created#335fbef1' defined in class path resource [service/addons/gameperiodstats.applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public java.util.Date java.text.DateFormat.parse(java.lang.String) throws java.text.ParseException] threw exception; nested exception is java.lang.NumberFormatException: multiple points &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The system verification department was doing heavy-load testing using bots on several machines. The error showed up only two or three times during the entire day. I started googling for the &lt;span style="font-style:italic;"&gt;java.lang.NumberFormatException: multiple points&lt;/span&gt;. It turned out it is a weird way of saying you are using &lt;span style="font-style:italic;"&gt;SimpleDateFormat&lt;/span&gt; from multiple threads on a shared instance. There &lt;a href="http://www.codefutures.com/weblog/andygrove/2007/10/simpledateformat-and-thread-safety.html"&gt;are tons&lt;/a&gt; of articles about SimpleDateFormat &lt;a href="http://life.neophi.com/danielr/2009/03/simpledateformat_is_not_thread.html"&gt;not being thread-safe&lt;/a&gt;, and I knew about it. I was a bit surprised. The way I had configured my Spring context invokes &lt;span style="font-style:italic;"&gt;SimpleDateFormat&lt;/span&gt;.parse exactly one time only, at creation of the Application Context. &lt;br /&gt;&lt;br /&gt;The problem however, is in the &lt;span style="font-style:italic;"&gt;gamePeriodStatsService&lt;/span&gt; bean, which was set to scope="prototype" for reasons I don't know. Using this scope would actually always create a new instance of the  &lt;span style="font-style:italic;"&gt;GamePeriodStatsServiceImpl&lt;/span&gt; class every time someone uses &lt;span style="font-style:italic;"&gt;applicationContext.getBean&lt;/span&gt; inside the code. I figured out that there were a lot of places in the code where getBean was used. Every time a new &lt;span style="font-style:italic;"&gt;gamePeriodStatsService&lt;/span&gt; bean was created that way, it would use my shared &lt;span style="font-style:italic;"&gt;deactivationDateFormat&lt;/span&gt; bean - invoking the parse method in the &lt;span style="font-style:italic;"&gt;SimpleDateFormat&lt;/span&gt; class. The  deactivationDateFormat bean is shared because I did not put it in the prototype scope - like you should do. Only stateful beans should use the prototype scope.&lt;br /&gt;&lt;br /&gt;We decided to do a semi-lame fix and put the &lt;span style="font-style:italic;"&gt;deactivationDateFormat&lt;/span&gt; bean also in prototype scope. The proper solution would probably be to remove the prototype scope from all other beans where it was needed. However, I was not brave enough to change this in a legacy systems having 20% test coverage :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-8873361659671974900?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/8873361659671974900/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=8873361659671974900' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8873361659671974900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8873361659671974900'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/01/my-favorite-bug-in-2011.html' title='My favorite bug in 2011'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-5968297383225829383</id><published>2011-01-11T04:56:00.000-08:00</published><updated>2011-01-11T05:00:16.346-08:00</updated><title type='text'>Keep-Alive query in HSQLDB</title><content type='html'>Today I was in the need for a good keep-alive statement that works with &lt;a href="http://hsqldb.org/"&gt;HSQLDB&lt;/a&gt;. For all the code running against MySQL we usually use: &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;SELECT 1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;but the statement is incompatible with HSQLDB. The problem came up in one of our unit-tests, where we often use a in-memory database instead of depending on a externally running MySQL instance. &lt;br /&gt;&lt;br /&gt;For me, a good keep-alive statement is one, that is not depending on a user defined schema and table structure. I came up with this one for HSQLDB: &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;SELECT * FROM INFORMATION_SCHEMA.SYSTEM_TABLES &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;which should work in every vanilla HSQLDB installation. I haven't looked thoroughly into right and permission handling but I kind of assume that every user can at least read from this schema. If you run HSQLDB in memory, you are most likely using the sa user anyways.  &lt;br /&gt;&lt;br /&gt;In our case it is semi-useful, to programmatically verify that the in-memory database is up during unit-tests. It will make more sense in production code against MySQL. You should also be able to use this as the &lt;a href="http://commons.apache.org/dbcp/apidocs/org/apache/commons/dbcp/BasicDataSource.html#validationQuery"&gt;validationQuery&lt;/a&gt; in a org.apache.commons.dbcp.BasicDataSource or as keep-alive statement for Quartz.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-5968297383225829383?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/5968297383225829383/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=5968297383225829383' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5968297383225829383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5968297383225829383'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/01/keep-alive-query-in-hsqldb.html' title='Keep-Alive query in HSQLDB'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-9205602951669301187</id><published>2011-01-05T07:11:00.000-08:00</published><updated>2011-01-06T02:13:22.374-08:00</updated><title type='text'>Riak, Protocol Buffers and Java in the Mix</title><content type='html'>Today I was using Riak for the first time, in order to compare it with Cassandra. I set up a Maven quickstart project to use Riak from Java using Google Protocol Buffers. The Riak clients come in two flavours - either using HTTP or Protobuf. The latter supposed to be a bit faster. Well, no surprise. HTTP is top level in the &lt;a href="http://en.wikipedia.org/wiki/OSI_model"&gt;OSI model&lt;/a&gt;, so there is some overhead involved. However, if performance is not your biggest concern, I would almost always go for HTTP because it is easier to use in client applications. Anyway, let's continue with the Protocol Buffers version anyways (some people &lt;a href="https://github.com/krestenkrab/riak-java-pb-client#readme"&gt;claim&lt;/a&gt; it is 10x faster).&lt;br /&gt;&lt;br /&gt;If you are running Ubuntu like me, follow the &lt;a href="http://wiki.basho.com/Riak-Search---Installation---Debian-and-Ubuntu.html"&gt;install instructions&lt;/a&gt; using the binary packages. This is actually installing Riak Search, which includes Riak core. What the guide is not telling you, is how to start the database server afterwards. Well not too hard: &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/etc/init.d/riaksearch start&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To test if it is up and running execute:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;curl http://localhost:8098/stats&lt;br /&gt;&lt;br /&gt;curl -v http://127.0.0.1:8098/riak/test &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Continue to set up a vanilla Java project using Maven:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;mvn archetype:generate&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pick the maven-archetype-quickstart type (15) and enter the remaining stuff. Next make sure, that you have the compiler for Protocol Buffers installed:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;protoc --version&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If it is not installed run &lt;span style="font-weight:bold;"&gt;sudo apt-get install protobuf-compiler&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Next download the &lt;a href="https://github.com/basho/riak-erlang-client/blob/master/src/riakclient.proto"&gt;riakclient.proto&lt;/a&gt; file, which we will use to generate us a Java version of the Riak client. Before you do this, let's create 2 new folders which we need later. In the Maven project structure create &lt;span style="font-weight:bold;"&gt;src/main/proto&lt;/span&gt;. This is the default location for all your .proto files. Furthermore create &lt;span style="font-weight:bold;"&gt;src/main/java-gen&lt;/span&gt; which we will use to output generated Protocol Buffers files. Now download riakclient.proto and put it into src/main/proto.&lt;br /&gt;&lt;br /&gt;The protobuf-compiler need to be told in which Java package you want to generate your source code files. Open riakclient.proto and add the package instructions before the first Message block:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;** 24 - RpbMapRedResp{1,}&lt;br /&gt;**&lt;br /&gt;*/&lt;br /&gt;option java_package = "my.package.riak.client";&lt;br /&gt;&lt;br /&gt;// Error response - may be generated for any Req&lt;br /&gt;message RpbErrorResp {&lt;br /&gt;    required bytes errmsg = 1;&lt;br /&gt;    required uint32 errcode = 2;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ideally, you want to generate all source code based on the Protocol Buffers files every time you build your project. This is where the &lt;a href="https://github.com/dtrott/maven-protoc-plugin"&gt;maven-protoc-plugin&lt;/a&gt; comes in handy. In order to use it, the pom.xml file needs to be tweaked. Add the plugin repository hosting the plugin:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;    &amp;lt;pluginRepositories&amp;gt;&lt;br /&gt;        &amp;lt;pluginRepository&amp;gt;&lt;br /&gt;            &amp;lt;id&amp;gt;dtrott&amp;lt;/id&amp;gt;&lt;br /&gt;            &amp;lt;url&amp;gt;http://maven.davidtrott.com/repository&amp;lt;/url&amp;gt;&lt;br /&gt;        &amp;lt;/pluginRepository&amp;gt;&lt;br /&gt;    &amp;lt;/pluginRepositories&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;then hook in the plugin when running compile:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;com.google.protobuf.tools&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;maven-protoc-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;configuration&amp;gt;&lt;br /&gt;        &amp;lt;outputDirectory&amp;gt;src/main/java-gen/&amp;lt;/outputDirectory&amp;gt;&lt;br /&gt;    &amp;lt;/configuration&amp;gt;&lt;br /&gt;    &amp;lt;executions&amp;gt;&lt;br /&gt;        &amp;lt;execution&amp;gt;&lt;br /&gt;            &amp;lt;goals&amp;gt;&lt;br /&gt;                &amp;lt;goal&amp;gt;compile&amp;lt;/goal&amp;gt;&lt;br /&gt;            &amp;lt;/goals&amp;gt;&lt;br /&gt;            &amp;lt;phase&amp;gt;generate-sources&amp;lt;/phase&amp;gt;&lt;br /&gt;        &amp;lt;/execution&amp;gt;&lt;br /&gt;    &amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With this configuration, the &lt;a href="https://github.com/dtrott/maven-protoc-plugin"&gt;maven-protoc-plugin&lt;/a&gt; will use the protoc compiler installed in your OS. This implies, that you use the same dependency version of Protocol Buffers in your project. So run protoc --version from the command line and set this version in your Maven dependencies section. If you don't do this, you might see errors like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;Riakclient.java:[118,51] boolean cannot be dereferenced&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Also note the &lt;span style="font-weight:bold;"&gt;outputDirectory&lt;/span&gt; defined in the plugin above. Unfortunately the maven-protoc-plugin cleans this directory before generating sources. This is why you cannot generate the protobuf sources into the same folder as your regular Java project files or they will be deleted.&lt;br /&gt;&lt;br /&gt;Finally we are ready to write some Java code to run against Riak. Here is an example of a TestNG unit test that invokes the &lt;a href="http://wiki.basho.com/PBC-API.html#Bucket-Operations"&gt;List Buckets&lt;/a&gt; operation:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * List all of the buckets using protocol buffers. You need to have Riak&lt;br /&gt; * up and running on port 8087.&lt;br /&gt; *&lt;br /&gt; * @author reiks, Jan 5, 2011&lt;br /&gt; */&lt;br /&gt;@Test(groups = "all", sequential = true)&lt;br /&gt;public class ListBucketsTest {&lt;br /&gt;&lt;br /&gt;    public void testListBuckets() throws IOException {&lt;br /&gt;        final Socket socket = new Socket("localhost", 8087);&lt;br /&gt;        DataOutputStream dout = null;&lt;br /&gt;        DataInputStream din = null;&lt;br /&gt;&lt;br /&gt;        try {&lt;br /&gt;            dout = new DataOutputStream(&lt;br /&gt;                        new BufferedOutputStream(&lt;br /&gt;                              socket.getOutputStream(), 1024 * 200&lt;br /&gt;                        )&lt;br /&gt;                  );&lt;br /&gt;&lt;br /&gt;            din = new DataInputStream(&lt;br /&gt;                        new BufferedInputStream(&lt;br /&gt;                              socket.getInputStream(), 1024 * 200&lt;br /&gt;                        )&lt;br /&gt;                  );&lt;br /&gt;&lt;br /&gt;            dout.writeInt(1);&lt;br /&gt;            dout.write(15); // 15 - RpbListBucketsReq&lt;br /&gt;            dout.flush();&lt;br /&gt;&lt;br /&gt;            final byte[] bytes = getData(16, din);  // 16 - RpbListBucketsResp&lt;br /&gt;            assertNotNull(bytes);&lt;br /&gt;            assertTrue(bytes.length &gt; 0);&lt;br /&gt;&lt;br /&gt;            System.out.println(Arrays.toString(bytes));&lt;br /&gt;&lt;br /&gt;        } finally {&lt;br /&gt;            IOUtils.closeQuietly(dout);&lt;br /&gt;            IOUtils.closeQuietly(din);&lt;br /&gt;            socket.close();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    byte[] getData(final int expectedCode, final DataInputStream din) throws IOException {&lt;br /&gt;        int len = din.readInt();&lt;br /&gt;        int returnCode = din.read();&lt;br /&gt;&lt;br /&gt;        byte[] data = null;&lt;br /&gt;        if (len &gt; 1) {&lt;br /&gt;            data = new byte[len - 1];&lt;br /&gt;            din.readFully(data);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        if (expectedCode != returnCode) {&lt;br /&gt;            throw new IOException("Unexpected (" + returnCode + "), expected " + expectedCode);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return data;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Double check that you run against port 8087 which is for Protocol Buffers communication. I was using port 8098 from the curl examples above for a while and got totally strange results until I figured that this is actually for HTTP communication. Stupid me!&lt;br /&gt;&lt;br /&gt;As you can see, this code is rather low-level. Not only do you need to know the different Message codes, which you can find in the riakclient.proto file, you also need to get the java.io stuff right. In a perfect world, this code should be hidden behind a facade. This is exactly what the &lt;a href="https://github.com/krestenkrab/riak-java-pb-client"&gt;riak-java-pb-client library&lt;/a&gt; is doing. A similar facade library for Cassandra is &lt;a href="https://github.com/rantav/hector"&gt;Hector&lt;/a&gt;. It let's you write application code against Riak in a convinient way and hides the low-level details. Unfortunately at this stage, the riak-java-pb-client library was only available as source files in github and they don't provide a way to build it out of the box. I have sent them a version of their code which is restructured and can be build with Maven. With a bit of luck, you can git clone and build riak-java-pb-client in a few days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-9205602951669301187?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/9205602951669301187/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=9205602951669301187' title='3 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/9205602951669301187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/9205602951669301187'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2011/01/riak-protocol-buffer-and-java-in-mix.html' title='Riak, Protocol Buffers and Java in the Mix'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-575876669433049366</id><published>2010-12-13T04:10:00.000-08:00</published><updated>2010-12-13T04:47:40.795-08:00</updated><title type='text'>Java Example with Cassandra 0.7</title><content type='html'>Last Friday release candidate 2 of the upcoming Cassandra 0.7 version saw the light of the day. It took a while to get some old Java test code working again using Thrift directly. Let's use this Maven project file:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&amp;gt;&lt;br /&gt;    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;javasplitter&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;cassandra-test&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;repositories&amp;gt;&lt;br /&gt;        &amp;lt;repository&amp;gt;&lt;br /&gt;            &amp;lt;id&amp;gt;riptano&amp;lt;/id&amp;gt;&lt;br /&gt;            &amp;lt;name&amp;gt;Riptano Repository&amp;lt;/name&amp;gt;&lt;br /&gt;            &amp;lt;url&amp;gt;http://mvn.riptano.com/content/repositories/riptano/&amp;lt;/url&amp;gt;&lt;br /&gt;        &amp;lt;/repository&amp;gt;&lt;br /&gt;    &amp;lt;/repositories&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;dependencies&amp;gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;           &amp;lt;groupId&amp;gt;org.apache.cassandra&amp;lt;/groupId&amp;gt;&lt;br /&gt;           &amp;lt;artifactId&amp;gt;apache-cassandra&amp;lt;/artifactId&amp;gt;&lt;br /&gt;           &amp;lt;version&amp;gt;0.7.0-rc2&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;           &amp;lt;groupId&amp;gt;libthrift&amp;lt;/groupId&amp;gt;&lt;br /&gt;           &amp;lt;artifactId&amp;gt;libthrift&amp;lt;/artifactId&amp;gt;&lt;br /&gt;           &amp;lt;version&amp;gt;0.5&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;/dependencies&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You want to use the Riptano repository as these guys have all the latest artifacts very fast. Here is a snippet of my new yaml based Cassandra configuration - yammi:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;...&lt;br /&gt;keyspaces:&lt;br /&gt;    - name: "javasplitter"&lt;br /&gt;      replica_placement_strategy: org.apache.cassandra.locator.SimpleStrategy&lt;br /&gt;      replication_factor: 1&lt;br /&gt;      column_families:&lt;br /&gt;        - name: author&lt;br /&gt;          compare_with: BytesType&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Straightforward, no advanced use cases. Some Java code involving Thrift that works. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;TTransport framedTransport = new TFramedTransport(new TSocket("localhost", 9160));&lt;br /&gt;TProtocol framedProtocol = new TBinaryProtocol(framedTransport);&lt;br /&gt;&lt;br /&gt;Cassandra.Client client = new Cassandra.Client(framedProtocol);&lt;br /&gt;framedTransport.open();&lt;br /&gt;&lt;br /&gt;client.set_keyspace("javasplitter");&lt;br /&gt;String columnFamily = "author";&lt;br /&gt;&lt;br /&gt;ColumnParent cp = new ColumnParent(columnFamily);&lt;br /&gt;byte[] userIDKey = "nadine".getBytes();&lt;br /&gt;client.insert(&lt;br /&gt;        ByteBuffer.wrap(userIDKey),&lt;br /&gt;        cp,&lt;br /&gt;        new Column(&lt;br /&gt;            ByteBuffer.wrap("lastname".getBytes("UTF-8")),&lt;br /&gt;            ByteBuffer.wrap("schatz".getBytes("UTF-8")),&lt;br /&gt;            System.currentTimeMillis()&lt;br /&gt;        ),&lt;br /&gt;        ConsistencyLevel.ONE);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;One new thing is the use of framed transports. Make sure your cassandra.yaml has this line (which it does by default):&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;# Frame size for thrift (maximum field length).&lt;br /&gt;# 0 disables TFramedTransport in favor of TSocket. This option&lt;br /&gt;# is deprecated; we strongly recommend using Framed mode.&lt;br /&gt;thrift_framed_transport_size_in_mb: 15&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Make really sure you are using the above code against a 0.7 Cassandra installation otherwise you will get a lot of weird errors which are not really self explaining. For instance running the Java code above against Cassandra 0.6.8 would just freeze on the line containing framedTransport.open(). It is still possible to use plain TSocket transport or even to mix. Cassandra.Client has a constructor that takes two TProtocol instances (in and out).&lt;br /&gt;&lt;br /&gt;Another thing that has changed is the use of java.nio.ByteBuffer from the Thrift based Cassandra.Client. Everything expects a ByteBuffer now (I think it took byte[] before) so the the code becomes a bit more verbose. Also make sure you are running with libthrift 0.5 (see pom.xml) otherwise you will get errors like: &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;java.lang.NoSuchMethodError: org.apache.thrift.protocol.TProtocol.writeBinary(Ljava/nio/ByteBuffer;)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I think 0.7 beta 2 used another version of libthrift (959516) so be careful. Anyway, you should probably use &lt;a href="https://github.com/rantav/hector"&gt;Hector&lt;/a&gt; from production code anyway. Should work well with 0.7 of Cassandra. I was however interested in Thrift since apparently Cassandra is moving away from &lt;a href="http://thrift.apache.org/"&gt;Thrift&lt;/a&gt; to &lt;a href="http://avro.apache.org/"&gt;Avro&lt;/a&gt;. No idea yet, why Avro is better. It can't be the &lt;a href="https://github.com/eishay/jvm-serializers/wiki/"&gt;performance&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-575876669433049366?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/575876669433049366/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=575876669433049366' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/575876669433049366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/575876669433049366'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/12/java-example-with-cassandra-07.html' title='Java Example with Cassandra 0.7'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-5330999978030170930</id><published>2010-10-29T05:16:00.000-07:00</published><updated>2010-10-29T05:39:38.909-07:00</updated><title type='text'>Having Maven create a nice zip File and separate Configuration</title><content type='html'>A co-worker and I are preparing a presentation about &lt;a href="http://aws.amazon.com/ec2/"&gt;Amazon EC2&lt;/a&gt; for other developers in my company. To show some stuff in action, we decided to write two JMS powered applications. One is sending messages, the other is receiving messages and persisting them into a database. During the presentation we will roll this out onto 3 EC2 nodes. Each application is build using Maven. To have it as convenient as possible, I changed the Maven package build phase to produce a single zip-file. The zip-file can be copied over to the EC2 node, where it is extracted. The zip-file contains one big "uber-jar" (with all the third party dependencies included) and a single properties-file to be able to set host and port for the JMS communication. We use ActiveMQ as JMS vendor in our projects.&lt;br /&gt;&lt;br /&gt;Once the big zip-file has been extracted on the EC2 nodes and the properties have been set, you can start the producer and the consumer from the Main class. (Note the little dot infront of .:consumer... - this is needed so that the properties-file is found) &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;java -cp .:consumer-1.0-SNAPSHOT-final.jar package.MessageReceiver&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For the packaging of the big zip-files, I use the &lt;a href="http://maven.apache.org/plugins/maven-assembly-plugin/"&gt;Maven Assembly plugin&lt;/a&gt; during the package phase. The configuration looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"&lt;br /&gt;          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"&amp;gt;&lt;br /&gt;    &amp;lt;id&amp;gt;final&amp;lt;/id&amp;gt;&lt;br /&gt;    &amp;lt;formats&amp;gt;&lt;br /&gt;        &amp;lt;format&amp;gt;jar&amp;lt;/format&amp;gt;&lt;br /&gt;    &amp;lt;/formats&amp;gt;&lt;br /&gt;    &amp;lt;includeBaseDirectory&amp;gt;false&amp;lt;/includeBaseDirectory&amp;gt;&lt;br /&gt;    &amp;lt;dependencySets&amp;gt;&lt;br /&gt;        &amp;lt;dependencySet&amp;gt;&lt;br /&gt;            &amp;lt;unpack&amp;gt;true&amp;lt;/unpack&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;&lt;br /&gt;            &amp;lt;useProjectArtifact&amp;gt;false&amp;lt;/useProjectArtifact&amp;gt;&lt;br /&gt;        &amp;lt;/dependencySet&amp;gt;&lt;br /&gt;    &amp;lt;/dependencySets&amp;gt;&lt;br /&gt;    &amp;lt;fileSets&amp;gt;&lt;br /&gt;        &amp;lt;fileSet&amp;gt;&lt;br /&gt;            &amp;lt;directory&amp;gt;${project.build.outputDirectory}&amp;lt;/directory&amp;gt;&lt;br /&gt;            &amp;lt;outputDirectory&amp;gt;/&amp;lt;/outputDirectory&amp;gt;&lt;br /&gt;            &amp;lt;excludes&amp;gt;&lt;br /&gt;                &amp;lt;exclude&amp;gt;consumer.properties&amp;lt;/exclude&amp;gt;&lt;br /&gt;            &amp;lt;/excludes&amp;gt;&lt;br /&gt;        &amp;lt;/fileSet&amp;gt;&lt;br /&gt;    &amp;lt;/fileSets&amp;gt;&lt;br /&gt;&amp;lt;/assembly&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;src/main/assembly/jar.xml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This explodes all third party dependency jar files and merges them into one big uber-jar file. The properties-file is excluded from the uber-jar (this name sounds hilarious if you are from Germany by the way).&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"&lt;br /&gt;          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"&amp;gt;&lt;br /&gt;    &amp;lt;id&amp;gt;bin&amp;lt;/id&amp;gt;&lt;br /&gt;    &amp;lt;formats&amp;gt;&lt;br /&gt;        &amp;lt;format&amp;gt;zip&amp;lt;/format&amp;gt;&lt;br /&gt;    &amp;lt;/formats&amp;gt;&lt;br /&gt;    &amp;lt;includeBaseDirectory&amp;gt;false&amp;lt;/includeBaseDirectory&amp;gt;&lt;br /&gt;    &amp;lt;fileSets&amp;gt;&lt;br /&gt;        &amp;lt;fileSet&amp;gt;&lt;br /&gt;            &amp;lt;directory&amp;gt;${project.basedir}/src/main/resources&amp;lt;/directory&amp;gt;&lt;br /&gt;            &amp;lt;outputDirectory/&amp;gt;&lt;br /&gt;            &amp;lt;includes&amp;gt;&lt;br /&gt;                &amp;lt;include&amp;gt;consumer.properties&amp;lt;/include&amp;gt;&lt;br /&gt;            &amp;lt;/includes&amp;gt;&lt;br /&gt;        &amp;lt;/fileSet&amp;gt;&lt;br /&gt;        &amp;lt;fileSet&amp;gt;&lt;br /&gt;            &amp;lt;directory&amp;gt;${project.build.directory}&amp;lt;/directory&amp;gt;&lt;br /&gt;            &amp;lt;outputDirectory/&amp;gt;&lt;br /&gt;            &amp;lt;includes&amp;gt;&lt;br /&gt;                &amp;lt;include&amp;gt;*-final.jar&amp;lt;/include&amp;gt;&lt;br /&gt;            &amp;lt;/includes&amp;gt;&lt;br /&gt;        &amp;lt;/fileSet&amp;gt;&lt;br /&gt;    &amp;lt;/fileSets&amp;gt;&lt;br /&gt;&amp;lt;/assembly&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;src/main/assembly/zip.xml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This creates a zip-archive containing the "uber-jar" and the properties-file. Notice that the "uber-jar" has the suffix of "-final" equal to the id-attribute in the jar.xml file.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;maven-assembly-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;    &amp;lt;archive&amp;gt;&lt;br /&gt;        &amp;lt;manifest&amp;gt;&lt;br /&gt;            &amp;lt;mainClass&amp;gt;package.MessageReceiver&amp;lt;/mainClass&amp;gt;&lt;br /&gt;        &amp;lt;/manifest&amp;gt;&lt;br /&gt;    &amp;lt;/archive&amp;gt;&lt;br /&gt;    &amp;lt;descriptorRefs&amp;gt;&lt;br /&gt;        &amp;lt;descriptorRef&amp;gt;jar-with-dependencies&amp;lt;/descriptorRef&amp;gt;&lt;br /&gt;    &amp;lt;/descriptorRefs&amp;gt;&lt;br /&gt;    &amp;lt;descriptors&amp;gt;&lt;br /&gt;        &amp;lt;descriptor&amp;gt;src/main/assembly/jar.xml&amp;lt;/descriptor&amp;gt;&lt;br /&gt;        &amp;lt;descriptor&amp;gt;src/main/assembly/zip.xml&amp;lt;/descriptor&amp;gt;&lt;br /&gt;    &amp;lt;/descriptors&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt;    &amp;lt;execution&amp;gt;&lt;br /&gt;        &amp;lt;id&amp;gt;make-assembly&amp;lt;/id&amp;gt;&lt;br /&gt;        &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;&lt;br /&gt;        &amp;lt;goals&amp;gt;&lt;br /&gt;            &amp;lt;goal&amp;gt;single&amp;lt;/goal&amp;gt;&lt;br /&gt;        &amp;lt;/goals&amp;gt;&lt;br /&gt;    &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;pom.xml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This code snippet runs the maven-assembly-plugin during the package phase.&lt;br /&gt;&lt;br /&gt;Everything went well when we finished the producer application last week. Today I ran into some weird errors when I worked on the consumer end. Trying to start the MessageReceiver main class gave me the following error:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;Caused by: org.xml.sax.SAXParseException: cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'amq:broker'.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I was able to resolve this error with the help of the &lt;a href="http://activemq.apache.org/xml-reference.html"&gt;ActiveMQ XML reference page&lt;/a&gt;, only to stumble into the next problem:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace http://www.springframework.org/schema/context&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It did not really jump me at first why this was happening. There a unit tests which load the Spring Context, they run fine. Maven runs the test in the package phase, they passed fine. So this was odd. After doing some research, I found out that the maven-assembly-plugin is responsible for this. Apparently Spring needs the spring.handlers and spring.schemas files to be present in the META-INF directory of the "uber-jar". &lt;a href="http://jira.codehaus.org/browse/MASSEMBLY-360"&gt;A lot&lt;/a&gt; of &lt;a href="http://www.eorlovsky.com/2010/03/maven-shade-spring-core-handlers_27.html"&gt;other people&lt;/a&gt; had already hit the same problem before me. Some of them &lt;a href="http://www.rimple.com/tech/2010/6/24/kickin-butt-with-spring-roo-at-the-command-line-with-maven-s.html"&gt;recommend&lt;/a&gt; the use of the maven-shade-plugin with the following setup:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;&amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;maven-shade-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;version&amp;gt;1.3.1&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt;    &amp;lt;execution&amp;gt;&lt;br /&gt;        &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;&lt;br /&gt;        &amp;lt;goals&amp;gt;&lt;br /&gt;            &amp;lt;goal&amp;gt;shade&amp;lt;/goal&amp;gt;&lt;br /&gt;        &amp;lt;/goals&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;            &amp;lt;finalName&amp;gt;${artifactId}-${version}-final&amp;lt;/finalName&amp;gt;&lt;br /&gt;            &amp;lt;transformers&amp;gt;&lt;br /&gt;                &amp;lt;transformer implementation="&lt;br /&gt;org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"&amp;gt;&lt;br /&gt;                    &amp;lt;mainClass&amp;gt;&lt;br /&gt;com.sabre.newgermanrail.dbitool.DbiTool&lt;br /&gt;&amp;lt;/mainClass&amp;gt;&lt;br /&gt;                &amp;lt;/transformer&amp;gt;&lt;br /&gt;                &amp;lt;transformer implementation="&lt;br /&gt;org.apache.maven.plugins.shade.resource.AppendingTransformer"&amp;gt;&lt;br /&gt;                    &amp;lt;resource&amp;gt;META-INF/spring.handlers&amp;lt;/resource&amp;gt;&lt;br /&gt;                &amp;lt;/transformer&amp;gt;&lt;br /&gt;                &amp;lt;transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"&amp;gt;&lt;br /&gt;                    &amp;lt;resource&amp;gt;META-INF/spring.schemas&amp;lt;/resource&amp;gt;&lt;br /&gt;                &amp;lt;/transformer&amp;gt;&lt;br /&gt;  &amp;lt;transformer implementation="&lt;br /&gt;org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer"&amp;gt;&lt;br /&gt;                    &amp;lt;resource&amp;gt;consumer.properties&amp;lt;/resource&amp;gt;&lt;br /&gt;                &amp;lt;/transformer&amp;gt;&lt;br /&gt;            &amp;lt;/transformers&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;    &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;pom.xml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;With the help of Transformers, the spring.handlers and spring.schemas files are added. If you are using Spring 3.x, there are many small spring-xyz.jar files and each of these comes with a spring.handlers and spring.schemas file. The maven-shade-plugin will append the content of each of these files using the &lt;a href="http://maven.apache.org/plugins/maven-shade-plugin/apidocs/org/apache/maven/plugins/shade/resource/AppendingTransformer.html"&gt;AppendingTransformer&lt;/a&gt;. As you can see in the example above, I am again excluding my properties-file using the &lt;a href="http://maven.apache.org/plugins/maven-shade-plugin/apidocs/org/apache/maven/plugins/shade/resource/DontIncludeResourceTransformer.html"&gt;DontIncludeResourceTransformer&lt;/a&gt;. I decided to keep the zip-archiving part from the maven-assembly-plugin. Maybe this is something the &lt;a href="http://maven.apache.org/plugins/maven-shade-plugin/"&gt;maven-shade-plugin&lt;/a&gt; could do for me as well, not sure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-5330999978030170930?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/5330999978030170930/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=5330999978030170930' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5330999978030170930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5330999978030170930'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/10/having-maven-create-nice-zip-file-and.html' title='Having Maven create a nice zip File and separate Configuration'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-1440424337277613035</id><published>2010-10-06T23:53:00.000-07:00</published><updated>2010-10-06T23:55:37.533-07:00</updated><title type='text'>Interviewed at Google Pt.1</title><content type='html'>Today I want to blog about an on-site interview which I had at Google a while ago. Since I did not sign a non-disclosure agreement and only agreed on not taking photos in their office, I hope it is okay to write about this interview. Going to an on-site interview, is like reaching the next level, if Google is satisfied with your previous telephone interview(s). Due to summer-time and a lot of vacations, I had my on-site interview more than 1,5 months after doing the initial phone interview. This was very good, because it gave me extra time to brush up on some stuff. I read some books about data-structures and algorithms and practiced white-board coding a bit. I coded through a lot of sample questions from software interviews, which I was able to find on the net. However, all the questions during the interview were new to me, so I had to be spontaneous.&lt;br /&gt;&lt;br /&gt;The job I was interviewed for, was Software Engineer in Test and the interview was held in Zürich, Usually the candidates are flying to the interview location one day in advance. That did not work for me, because I was already on another flight a day earlier. Instead Google booked two flights on the same day for me. which was OK. I arrived in time and signed in at the reception. As stated, you have to agree on not taking photos and you have to put some label identifying yourself on your shirt. Some minutes later I was picked up by my HR contact. She gave me a short office tour and set me up in one of the interview rooms. You could tell that Google is doing a lot for their employees. The Zürich office had a big fitness room with a personal coach. Free soft drinks everywhere, video gaming rooms, pool tables all that kind of stuff. My interview room was very small, maybe 3 times 3 meters and had a white-board. She handed me my interview schedule and I was surprised that it was six interviews, each 45 minutes long with a lunch break in between.&lt;br /&gt;&lt;br /&gt;After some minutes the first interviewer came and we got into action right away. This first interview went really well. We talked a bit about continuous integration, my contribution to the Hudson project and about testing in general. Then the interviewer switched to a question about bash in Linux. We talked about how piping works under the hood. We spoke about the case where the first command is non-stopping one like "yes" or "tail -f". I learned that Linux is not executing the commands sequentially, like I thought it would. Rather it sends the output of a command to a buffer and the following command would use read and write blocks to work on the buffer. Time went and the next two interviewers came.&lt;br /&gt;&lt;br /&gt;For some of the interviews, there are actually two people in the room. One of them being just a observer, that need to learn how to interview candidates. For the second interview, the interviewer directly put up a matrix on the white-board. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-4  -1   4   5&lt;br /&gt;-3   0   6   10&lt;br /&gt; 1   8   11  15&lt;br /&gt;17   19  22  30&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I did not realize, that the matrix was set up in a way that each row and each column was ascending - from negative into positive numbers. My task then, was to come up with an algorithm that, given any number, would return true or false if the number was contained in the matrix. The first idea I had was looking at the upper left number, reading the right and lower neighbor  and select the neighbor which would bring me closer to the target number. Surprisingly this worked out but the interviewer was able to find a negative example. For the next attempts I tried starting from the lower right corner, starting from the middle element looking at all 4 neighbors and even go row by row running binary search. The binary search algorithm would have worked but the interviewer indicated that this is not the best solution and that I should try a different starting location for my first approach. After some discussion we agreed that it would be possible to start lower left, so that the row would be ascending and the column would be descending. If the number, we were looking for, was bigger than the current item in the matrix (lower left at the start) I would go to the right neighbor. If it was lower I would go to the upper neighbor. This neighbor becomes the next item and the algorithm would again check right and upper neighbors until either the element was found or there was no way to go further. Finally I wrote some Java code for this and the second interview finished.&lt;br /&gt;&lt;br /&gt;It was lunchtime and someone from Brazil picked me up for a lunch-date. We went to the Google cafeteria and I got a free lunch. We talked about different things and it was nice to relax a little bit from coding exercises.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-1440424337277613035?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/1440424337277613035/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=1440424337277613035' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/1440424337277613035'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/1440424337277613035'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/10/interviewed-at-google-pt1.html' title='Interviewed at Google Pt.1'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-8885836164227085875</id><published>2010-10-06T13:24:00.000-07:00</published><updated>2010-10-06T13:25:51.670-07:00</updated><title type='text'>Subversion Changes to Archive File</title><content type='html'>Just a simple one-liner that I want to share with you. Do you know this problem: you have made changes to one of your projects, some files have changed, some images were added. Now you need to move this to your live server. Most often I moved the files one by one based on their change dates. Today, just before committing the changes into Subversion, I had the idea to use the Subversion changes for creating a Tarball which I could copy over to and extract on my server.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;svn st | grep -v '?' | awk '{ print $2 }' | xargs tar rvfz changes.tar&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;svn st&lt;/span&gt; - show Subversion changes (assuming that you have done all you svn add stuff before)&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;grep -v '?'&lt;/span&gt; - filter files which are not versioned, ie. IntelliJ project files&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;awk '{ print $2 }'&lt;/span&gt; - print only the file path and name&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;xargs tar rvfz changes.tar&lt;/span&gt; - add these files into changes.tar&lt;br /&gt;&lt;br /&gt;All that is left is to transfer the file via SCP or FTP and extract it in the right location.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-8885836164227085875?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/8885836164227085875/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=8885836164227085875' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8885836164227085875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8885836164227085875'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/10/subversion-changes-to-archive-file.html' title='Subversion Changes to Archive File'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-6630248837947313347</id><published>2010-10-03T05:41:00.000-07:00</published><updated>2010-10-03T05:44:53.917-07:00</updated><title type='text'>Google Phone Interview</title><content type='html'>A couple of months ago, I got contacted from a recruiter working at Google. It was about a Software Engineer in Test position in &lt;a href="http://www.google.se/intl/sv/jobs/software-engineer-in-test-stockholm/index.html"&gt;Stockholm&lt;/a&gt;. I was a bit surprised because this position has been on the net for a long time and it was more than a year ago since I sent them my CV. Even though I am not pro-actively looking for a new job, you cannot say no if Google is asking. I replied back that I was interested and she called me back two days later. Google's recruiting process is very different compared to other companies I applied at. First there will be a one or more interviews over the telephone, and if you are good at those, you will be invited to an on-site interview. The on-site interview is a whole day where you will meet 5 to 7 interviewers each for a 45 min interview. Each interviewer will then write together an evaluation of your interview. All of the evaluations are reviewed by the hiring committee and if they decide to hire you, as one of the last steps, your documents including CV is sent over to the US headquarter for the final go or no-go. &lt;br /&gt;&lt;br /&gt;So when the recruiter called me, this was actually the first step in a long recruiting process. The only thing she was interested during the fist call, was the length of my notice period and if it was negotiable. After this she asked me two technical questions. First question for the &lt;a href="http://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms"&gt;worst case time complexity&lt;/a&gt; of Quicksort. Second question something about Radixsort complexity, but she could not read the question, so she asked what the difference between a HashMap and a HashSet was. The recruiter is not really a technical person. She was probably given a list of questions and answers to filter out the very bad candidates. My answers were okay and she told me that she would set up a telephone interview. &lt;br /&gt;&lt;br /&gt;A week or two passed. Since I did not hear from her, I wrote a mail asking for the status of the telephone interview. Due to vacations it took a bit longer to set up the interview. My recruiter told me that a confirmation would be sent soon. To prepare myself, I should be looking at the Google Testing blog. Also she wrote, that the interviewer would be interested in my testing background and that he would be asking questions relevant to my coding and problem solving skills, algorithms, core computer science concepts, OOP and datastructures. It could also be, that he asked me to write a test plan or how to test an arbitrary Google product like Maps or how I would design a cache. Also we would be talking about my projects, problems I had found, tested and fixed and also what I would do with my Google 20%  time. It would also be good to know some stuff about the company, like the founders, the products, the business model etc.&lt;br /&gt;&lt;br /&gt;The interview however, went completely different. Someone else sent me a confirmation mail including a link to a Google Docs document. which I could share with the interviewer. It was also suggested, that I "warm" up a bit on topcoder.com in the "Software Competitions - Algorithms" &lt;a href="http://www.topcoder.com/tc"&gt;arena&lt;/a&gt;, which I did. On the day of my phone interview, I was called exactly at 11am. The interviewer was very friendly and explained everything very carefully. &lt;br /&gt;&lt;br /&gt;For the first task I was given two Lists of  Integers, one sorted ascending the other sorted descending. I should write an algorithm (Java) in the Google docs document, which would take both Lists and return a combined List that is sorted. I remembered that in the merge phase of the Mergesort, you do a similar thing. Have a pointer on the first element of the first list and a pointer on the last element in the second list. Then copy back the smaller of the two elements and increase or decrease the appropriate pointer.&lt;br /&gt;&lt;br /&gt;The second task was about anagrams. Given a list of words, I was asked for a datastructure in which you could store anagrams. I suggested to use a Hashtable. Each word is effectively a character array that could be sorted. So sort the characters and use this as the key for the Hash function. That way, elements having the same key are anagrams of each other.&lt;br /&gt;&lt;br /&gt;In the last task I was introduced to a Skip List, which I never heard of before. My interviewer explained the Skip List a couple of times and I was asked to write an algorithm for finding an element in the List. I did okay I think and then he asked me if I had any questions. I asked a bit about the Stockholm office, what he was working with at Google, if they used Git for version controlling (they use Perforce) and some other questions. I asked about feedback but he said, he is never giving feedback directly. Instead the interviewer said, he would write an evaluation of the interview in the next couple of days. Also he said, if later on I was asked to do another phone interview, it did not mean I was good or bad in the first one. &lt;br /&gt;&lt;br /&gt;One week or so passed. My recruiter called me and said that they liked my interview and want to meet me for an on-site interview. Because Stockholm was not big enough and not so many test managers worked there, they would like to have the interview in Zürich. I would be given further details and date suggestions later on. Google pays the flight upfront. The hotel must be paid by the candidate but the money can be reimbursed by sending an expense form to Google in Poland. For those candidates staying overnight, Google also pays the food (30 Euro, US-Dollar or Pound depending on where the interview was held). Rental car fees can also be reimbursed. I decided to pay for everything myself, since I was not staying over night. Sending some reimbursement form to Poland, seemed complicated. I was given 4 days to choose from for the interview. I picked one but they set up the time on another day anyways - weird. So I was flying on-site to Google in Switzerland, roughly two months after the initial contact.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-6630248837947313347?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/6630248837947313347/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=6630248837947313347' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6630248837947313347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6630248837947313347'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/10/google-phone-interview.html' title='Google Phone Interview'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-2640773146984968356</id><published>2010-09-24T07:29:00.000-07:00</published><updated>2010-09-24T07:44:12.309-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Spring Maven Jetty Classloading'/><title type='text'>Jetty7, Spring, Testing and Classloading</title><content type='html'>Currently working in a project where Jetty is configured in a Spring Context, that is started for unit tests. I was permanently hitting: "Context attribute is not of type WebApplicationContext". However, in the debugger I could see it was given a &lt;a href="http://static.springsource.org/spring/docs/2.5.6/api/org/springframework/web/context/support/XmlWebApplicationContext.html"&gt;XmlWebApplicationContext&lt;/a&gt; - WTF? I figured it must be some classloading issue. Maybe something that was different when comparing Jetty 6 and 7? In previous Spring projects I have always used Jetty 6. This was the first time I &lt;a href="http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-server/7.0.1.v20091125/"&gt;tried Jetty 7&lt;/a&gt; - which is still not final I think.&lt;br /&gt;&lt;br /&gt;Anyway, what you want to do is this in your Spring applicationContext.xml file:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&lt;bean class="org.eclipse.jetty.webapp.WebAppContext"&gt;&lt;br /&gt;    &lt;property name="contextPath" value="/[PATH]" /&gt;&lt;br /&gt;    &lt;property name="war" value="/[WAR]" /&gt;&lt;br /&gt;    &lt;property name="parentLoaderPriority" value="true" /&gt;&lt;br /&gt;&lt;/bean&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Previously I never had to use the parentLoaderPriority property but this made my tests working.&lt;br /&gt;&lt;br /&gt;One (unrelated) question mark remains though. This is a Maven based project and the deploy artifact is a WAR file. There was one unit test that manually started a Jetty server in-process to do some testing. My initial idea was to use the maven-jetty-plugin to start Jetty before the test suite runs using the Maven command-line. However in that case it would not have been possible to run this test isolated in the IDE. I decided to make the test a Spring powered unit test and have the Spring Context start up Jetty. Unfortunately this required an existing WAR file, correctly set in the war property of the WebAppContext (see above). Maven builds the WAR file after running the test. To work around this, I told Maven to construct the WAR file before the tests are run:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;    &lt;build&gt;&lt;br /&gt;        &lt;plugins&gt;&lt;br /&gt;            &lt;plugin&gt;&lt;br /&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;&lt;br /&gt;                &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;&lt;br /&gt;                &lt;executions&gt;&lt;br /&gt;                    &lt;execution&gt;&lt;br /&gt;                        &lt;id&gt;war-it&lt;/id&gt;&lt;br /&gt;                        &lt;phase&gt;generate-test-resources&lt;/phase&gt;&lt;br /&gt;                        &lt;goals&gt;&lt;br /&gt;                            &lt;goal&gt;war&lt;/goal&gt;&lt;br /&gt;                        &lt;/goals&gt;&lt;br /&gt;                    &lt;/execution&gt;&lt;br /&gt;                &lt;/executions&gt;&lt;br /&gt;            &lt;/plugin&gt;&lt;br /&gt;        &lt;/plugins&gt;&lt;br /&gt;    &lt;/build&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Anyone else has solved this scenario differently?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-2640773146984968356?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/2640773146984968356/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=2640773146984968356' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2640773146984968356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2640773146984968356'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/09/jetty7-spring-testing-and-classloading.html' title='Jetty7, Spring, Testing and Classloading'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-7190102327977418356</id><published>2010-09-22T05:53:00.000-07:00</published><updated>2010-09-22T05:58:14.477-07:00</updated><title type='text'>Spring Insight and Google Speed Tracer</title><content type='html'>I am sitting in a session here at &lt;a href="http://disruptivecode.com/"&gt;Disruptive Code&lt;/a&gt; called "From Zero to Cloud" which is presented by &lt;a href="http://se.linkedin.com/in/adamskogman"&gt;Adam Skogman&lt;/a&gt; from SpringSource. The session was actually split in the middle, with lunch in between. While the talk itself did not give me much of a big WOW effect, simply because I have used the Amazon cloud services before, Adam mentioned a very cool tool called &lt;a href="http://static.springsource.com/projects/tc-server/2.0/devedition/htmlsingle/devedition.html#using-speedtracer-integration"&gt;Spring Insight&lt;/a&gt;. He spoke about Spring Insight just under a minute. It sounded like an extension to the Spring tc server, which makes it possible to do performance analysis for web applications. It can measure and display information about the execution time of a HTTP request, a query execution in the database or even a single Spring bean invocation. Spring Insight can furthermore be integrated with &lt;a href="http://code.google.com/webtoolkit/speedtracer/"&gt;Google Speed Tracer&lt;/a&gt;, which is apparently a Chrome plugin that I did not know of just a couple of minutes ago.&lt;br /&gt;&lt;br /&gt;Spring Insight is very interesting project for me. A while ago a former colleague and I had a similar idea for an open-source project. We were planning to implement a language independent framework to measure execution time of web applications. In Java, the idea was to implement this using Annotations and Servlet Filters. In PHP, we were planning to have the same outcome using explicit method calls, which the PHP developer would have to add to the code manually. While the application was executed, it would then write a report file which users could then upload online to visualize the collected data. It is this part, that Google Speed Racer is doing now in the setup together with Spring Insight. Unfortunately we never had the time to work on our project, so it ended up just being an idea.&lt;br /&gt;&lt;br /&gt;Anyway, I googled around a bit. The biggest point of criticism for Spring Insight is apparently that it is tightly coupled to &lt;a href="http://www.springsource.com/products/tcserver"&gt;SpringSource's tc Server&lt;/a&gt;. Even though there a millions of Spring Framework powered applications, only a fraction of them is running in Spring tc Server. Doing a quick research, it seems like the main reason to use Spring tc Server for Spring Insight, is the usage of custom Container deployers to enable the functionality. The good news is that someone else has already started to work on a third party library, to enable Spring Insight functionality without actually forcing the user to go with Spring tc Server. The library is called &lt;a href="http://code.google.com/p/spring4speedtracer/"&gt;spring4speedtracer&lt;/a&gt;. Even though it is not as powerful as the original Spring Insight  - for instance JDBC query execution times cannot be measured - it is a promising project. When I get home, I will have a closer look at this library, maybe I can contribute to the project (and put my own project idea to rest for good).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-7190102327977418356?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/7190102327977418356/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=7190102327977418356' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7190102327977418356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7190102327977418356'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/09/spring-insight-and-google-speed-tracer.html' title='Spring Insight and Google Speed Tracer'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-7984329599064862175</id><published>2010-09-22T03:12:00.000-07:00</published><updated>2010-09-24T00:47:41.810-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Cassandra NoSQL'/><title type='text'>Auto Secondary Indexes in Cassandra</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_BYGcLbgH8o0/TJnYLUw9RZI/AAAAAAAAADQ/yWA6JX3VeuM/s1600/DSC06071.JPG"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_BYGcLbgH8o0/TJnYLUw9RZI/AAAAAAAAADQ/yWA6JX3VeuM/s320/DSC06071.JPG" alt="" id="BLOGGER_PHOTO_ID_5519680507383465362" border="0" /&gt;&lt;/a&gt;Twenty minutes ago, Eric Evans talk about Cassandra ended at &lt;a href="http://www.disruptivecode.com/"&gt;Disruptive Code&lt;/a&gt;. In the first 25 minutes or so, I was quite disappointed because it seemed to be exactly the &lt;a href="http://javasplitter.blogspot.com/2010/06/big-buzz-in-berlin.html"&gt;same presentation&lt;/a&gt;, which I saw in June at the &lt;a href="http://berlinbuzzwords.de/"&gt;Berlin Buzzwords&lt;/a&gt; conference. Even the funny Bigtable-Dynamo lovechild slide was still there, though I believe the laughter was greater in Berlin than it was in Stockholm. Well I guess it's not so easy to get a Swede laughing.&lt;br /&gt;&lt;br /&gt;Anyway, what I realised during Eric's presentation, was that he already added some stuff from the next Cassandra release 0.7. First of all, every time he was showing configuration, he had an excerpt from the a cassandra.yaml file. For instance this snippet from his timeseries example:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;#conf/cassandra.yaml&lt;br /&gt;keyspaces:&lt;br /&gt;  -name: Sites&lt;br /&gt;   column_families:&lt;br /&gt;     -name Stats&lt;br /&gt;      compare_with: LongType&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;new yaml configuration in Cassandra&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Apparently as of version 0.7, the cassandra.yaml file is &lt;a href="http://wiki.apache.org/cassandra/StorageConfiguration"&gt;replacing&lt;/a&gt; the cassandra.xml file. I have not come in contact with yaml really, I believe it is common in the Ruby world. Another very cool feature is the addition of secondary indexes to Cassandra. In previous versions, Cassandra did not have indexes out of the box. To mimic the behavior of a secondary index, what you could have done is to create another Column Family (I believe it was called). This new Column Family would then be sorted differently and contain a key to the "original" entry. As a example, imagine having a Column Family to store addresses. To be able to search by the city, you could create another Column Family called "byCity" with two properties, "city" and "address key". Every time you insert or update an address, your code has to alter the byCity Column Family.&lt;br /&gt;&lt;br /&gt;It looks like Cassandra will do this for you from version 0.7 on. There two new per-column settings called index_name and index_type. If I understood Eric correctly, adding this to your configuration will create you an inverted index, which can be used as a secondary access path. I think this is a very nice,  yet very &lt;a href="http://wiki.apache.org/cassandra/SecondaryIndexes"&gt;undocumented&lt;/a&gt;, feature. No clue when version 0.7 is going to be released but I hope it will be very soon, because we are only weeks away from starting a very big Cassandra project in my company.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-7984329599064862175?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/7984329599064862175/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=7984329599064862175' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7984329599064862175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7984329599064862175'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/09/auto-secondary-indexes-in-cassandra.html' title='Auto Secondary Indexes in Cassandra'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_BYGcLbgH8o0/TJnYLUw9RZI/AAAAAAAAADQ/yWA6JX3VeuM/s72-c/DSC06071.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-112920158417779191</id><published>2010-09-21T12:32:00.000-07:00</published><updated>2010-09-21T12:37:38.939-07:00</updated><title type='text'>Disruptive Code Party</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_BYGcLbgH8o0/TJkJdIQYj2I/AAAAAAAAADI/vzzzB3nW8Qs/s1600/party.JPG"&gt;&lt;img style="float: right; margin: 0pt 0pt 10px 10px; cursor: pointer; width: 200px; height: 150px;" src="http://4.bp.blogspot.com/_BYGcLbgH8o0/TJkJdIQYj2I/AAAAAAAAADI/vzzzB3nW8Qs/s200/party.JPG" alt="" id="BLOGGER_PHOTO_ID_5519453214356311906" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_BYGcLbgH8o0/TJkJWtc8h7I/AAAAAAAAADA/9Uw9XyC2Ua8/s1600/groena_lund.JPG"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 240px; height: 320px;" src="http://2.bp.blogspot.com/_BYGcLbgH8o0/TJkJWtc8h7I/AAAAAAAAADA/9Uw9XyC2Ua8/s320/groena_lund.JPG" alt="" id="BLOGGER_PHOTO_ID_5519453104082028466" border="0" /&gt;&lt;/a&gt;Seriously, who needs Java One when you can go partying with Disruptive Code people at Gröna Lund? Okay, Weather might be a bit nicer in California :)&lt;br /&gt;&lt;br /&gt;Day 1 was great I think. Great sessions, especially the ones about HTML5. Two things I did not like: Adam Skogmans "Designing For NoSQL" talk started earlier than it was printed on the badges or written on &lt;a href="http://disruptivecode.com/program"&gt;disruptivecode.com&lt;/a&gt; = missed it :( Also WIFI quality in the Big Hall was really bad. Nevertheless great stuff! Looking forward to day two.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-112920158417779191?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/112920158417779191/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=112920158417779191' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/112920158417779191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/112920158417779191'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/09/disruptive-code-party.html' title='Disruptive Code Party'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_BYGcLbgH8o0/TJkJdIQYj2I/AAAAAAAAADI/vzzzB3nW8Qs/s72-c/party.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-973206250845412778</id><published>2010-09-21T05:12:00.001-07:00</published><updated>2010-09-21T12:24:56.318-07:00</updated><title type='text'>Choosing wrong track</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_BYGcLbgH8o0/TJkGfxe8GfI/AAAAAAAAACg/HLag99P77GY/s1600/disruptive_code.JPG"&gt;&lt;img style="float: right; margin: 0pt 0pt 10px 10px; cursor: pointer; width: 200px; height: 150px;" src="http://3.bp.blogspot.com/_BYGcLbgH8o0/TJkGfxe8GfI/AAAAAAAAACg/HLag99P77GY/s200/disruptive_code.JPG" alt="" id="BLOGGER_PHOTO_ID_5519449961248070130" border="0" /&gt;&lt;/a&gt;A problem that keeps following me on &lt;a href="http://www.disruptivecode.com/"&gt;conferences&lt;/a&gt;, is picking the wrong talks. Often a session sounds nicer on the agenda, than it is in reality. For the first track I selected PayPal over the HTML5 session. I was hoping to get some insights into the PayPal API. How to use it? How to integrate it with some practical examples? The session however turned out to be not that detailed. It felt more like a sales talk. By the way, PayPal is one of the main sponsors of Disruptive Code. The fact, that the organisers put up all conference &lt;a href="http://twitter.com/search#search?q=dcode"&gt;tweets&lt;/a&gt; during the talk, and it seemed to be really exciting over at the HTML5 track, made things worse.&lt;br /&gt;&lt;br /&gt;The only good thing I could take away from this talk, are some ideas to possibly integrate payment into my projects. The first of the two PayPal speakers, gave some interesting project examples. ie. a person to persons send money application, a game where you can buy ammo or crowd-sourcing (paying users for uploading pictures, entering recipes etc.). There is also a portal called &lt;a href="https://www.x.com/"&gt;PayPal X&lt;/a&gt;, where developers can develop applications and tools on top of the PayPal API. Similar to the iPhone, these applications have to be approved by PayPal before they are available to everyone.&lt;br /&gt;&lt;br /&gt;So it is likely I will embed PayPal in my applications in the future. This session just did not show me how to really. The only slide having code on it, wasn't helping there much either and it certainly was not PHP code like the speakers said.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-973206250845412778?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/973206250845412778/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=973206250845412778' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/973206250845412778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/973206250845412778'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/09/choosing-wrong-track.html' title='Choosing wrong track'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BYGcLbgH8o0/TJkGfxe8GfI/AAAAAAAAACg/HLag99P77GY/s72-c/disruptive_code.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-8608503117600659315</id><published>2010-09-21T05:12:00.000-07:00</published><updated>2010-09-21T12:24:15.880-07:00</updated><title type='text'>HTML5 Web Workers and Geolocation</title><content type='html'>After having missed the first session about upcoming HTML5 features, I decided to go to Peter Lubbers talk "HTML5 Web Sockets, Web Workers and Geolocation Unleashed". Peter is the author of the recently published Apress book "&lt;a href="http://apress.com/book/view/1430227907"&gt;Pro Html 5 Programming&lt;/a&gt;". He works for a company called &lt;a href="http://www.kaazing.com/"&gt;Kaazing&lt;/a&gt; which I think is based in the Netherlands. Some time ago, my boss forwarded me a mail which was from Kaazing. It was about a Web Sockets presentation which they wanted to held at our office, since game clients are one of the primary use cases where Web Sockets can come in handy. I have to admit that back then I did not want to meet them. Primarily because I do not work with client products. In addition to that, I thought it was immature, but it was rather that I did not know so much about it back then and did not care.&lt;br /&gt;&lt;br /&gt;Anyway, Peters talk covered three of the most interesting API's around HTML5 - Web Workers, Geolocation and Web Sockets. These API's have initially been part of the HTML5 spec but have now been removed and put into their own specification. The idea behind all three is to make life simpler for the developers. With the current generation of browsers and HTML4, developers have to come up with complicated hacks or they have to use plugins in order to mimic bi-directional communication. What HTML5 is aiming for, is to support this natively powered through the browser instead of building something similar based on a bad foundation.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://robertnyman.com/2010/03/25/using-html5-web-workers-to-have-background-computational-power/"&gt;Web Workers&lt;/a&gt; are a new feature which brings back UI responsiveness while long running, heavy Javascript is executed. It enables background processing of such script while the user can still use the browser. Peter had an excellent example of this and hopefully I can put this up here on my blog later on. In his example he had a webform with two buttons. Each of the buttons would fire a busy-keeping Javascript for 10 seconds. One button would do this without, the other one with using a Web Worker. Clicking the first button, it was impossible to use the dropdown element or even open a new tab in Firefox. All this worked with Web Workers. Currently this feature is available in Firefox, Chrome, Safari and Opera but not in Internet Explorer. Actually it would be fun to write a web application using Web Workers, where you print a message to the IE users like "if you cannot navigate right now, consider switching to another browser". Web Workers are an incentive that comes for free if you use anything else than Internet Explorer.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_BYGcLbgH8o0/TJkGSswyBZI/AAAAAAAAACY/dvaxcnbTZE8/s1600/geolocation.JPG"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 150px;" src="http://4.bp.blogspot.com/_BYGcLbgH8o0/TJkGSswyBZI/AAAAAAAAACY/dvaxcnbTZE8/s200/geolocation.JPG" alt="" id="BLOGGER_PHOTO_ID_5519449736642430354" border="0" /&gt;&lt;/a&gt;The second API Peter talked about was &lt;a href="http://html5demos.com/geo"&gt;Geolocation&lt;/a&gt;. Again, Geolocation is only supported in some browsers right now. You want to check out &lt;a href="http://caniuse.com/"&gt;caniuse.com&lt;/a&gt; to see if your browser supports it. Also &lt;a href="http://html5test.com/"&gt;html5test.com&lt;/a&gt; is a great site to check HTML5 compatibility. Geolocation is a name that stands for native support of user location inside a browser. There are really only two methods that the API supports, getCurrentPosition() and watchPosition(). The first one doing a one time call, the latter constantly receiving the location of the user. This of course makes much more sense on mobile devices than from withing a fixed network. What the two calls return is simply longitude, latitude and accuracy. It is up to the developer how he uses this information within the web application, ie. by displaying it using the Google Maps API. Along with the API calls, you can also request additional metadata but if your browser can not give it to you (like altitude, heading, speed) you might end up getting NULL instead. Looking under the hood, Geolocation is implemented by the browser vendors by using an external location service. The browser asks this service for the location and returns this to the user. I was thinking, the watchPosition() method from the API is probably a candidate where you want to use a Web Worker, unless it is already implemented on top of a Web Worker. Have to find this out.&lt;br /&gt;&lt;br /&gt;Would like to blog more about Web Sockets but the next session about CSS3 has already started...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-8608503117600659315?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/8608503117600659315/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=8608503117600659315' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8608503117600659315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8608503117600659315'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/09/html5-web-workers-and-geolocation.html' title='HTML5 Web Workers and Geolocation'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_BYGcLbgH8o0/TJkGSswyBZI/AAAAAAAAACY/dvaxcnbTZE8/s72-c/geolocation.JPG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-4704238856441735652</id><published>2010-09-21T01:14:00.000-07:00</published><updated>2010-09-21T12:23:18.820-07:00</updated><title type='text'>Conference kickoff</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_BYGcLbgH8o0/TJkGHNVhkxI/AAAAAAAAACQ/0kPLW94rsLg/s1600/pre_disruptive.JPG"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 150px;" src="http://1.bp.blogspot.com/_BYGcLbgH8o0/TJkGHNVhkxI/AAAAAAAAACQ/0kPLW94rsLg/s200/pre_disruptive.JPG" alt="" id="BLOGGER_PHOTO_ID_5519449539228046098" border="0" /&gt;&lt;/a&gt;For me, it's rather hard to get annoyed on public transport in Stockholm. However this morning was different. It looked like all the Kindergartens and school classes in Sweden were out for a field trip. &lt;a href="http://sv.wikipedia.org/wiki/Stockholms_pendelt%C3%A5g"&gt;Pendeltåg&lt;/a&gt; was packed, so were the buses. I took the Bus 69 from the central station to the technical museum, where conference is taking place. I have never been in this area of Stockholm before, even though we live here for more than 2 years now. Wondering why they claim the &lt;a href="http://www.tekniskamuseet.se/"&gt;Tekniska Museet&lt;/a&gt; is on Djurgården? This is totally the wrong island. Anyway, the museum is quite an amazing place. It's like &lt;a href="http://www.tomtit.se/english/"&gt;Tom Tits Experiment&lt;/a&gt; with the limitation of you are not allowed to touch and try the stuff.&lt;br /&gt;&lt;br /&gt;A bunch of people exited the bus with me and headed for the conference. Someone handed me my badge at registration without checking my id. Last name misspelled, did I screw this up in the blogger pass registration form? Actually it was good that my last name was spelled wrong. My company had booked a &lt;a href="http://www.disruptivecode.com/"&gt;Disruptive Code&lt;/a&gt; ticket for me before I got elected as a Blogger. I promised the ticket to someone else in the office since I didn't know that the badges came with a name. To make a long story short, you will meet two Reik Schatz on the conference now, one with the last name spelled right.&lt;br /&gt;&lt;br /&gt;Conference is about to start now, let's see how it goes. Could already grab Eric Evans over a coffee.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-4704238856441735652?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/4704238856441735652/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=4704238856441735652' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4704238856441735652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4704238856441735652'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/09/conference-kickoff.html' title='Conference kickoff'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BYGcLbgH8o0/TJkGHNVhkxI/AAAAAAAAACQ/0kPLW94rsLg/s72-c/pre_disruptive.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-7369357512177978763</id><published>2010-09-20T12:44:00.001-07:00</published><updated>2010-09-20T12:44:54.300-07:00</updated><title type='text'>How to select a data-store</title><content type='html'>I have probably mentioned a couple of times. My company is currently in the process of selecting a new data-store which is supposed to replace MySQL for some applications that produce a lot of data. Cassandra is right now the hottest candidate and favored by my development team and also by the system administrators. Since replacing the database is obviously something bigger, we had to present this to some of the managers. They seemed to be interested as well and decided to make this a venture. This means we are getting hardware, people, resources etc. but it also means we have to follow a certain venture process that starts with a pre-study. To make it even more complicated (or bureaucratic) there is even a pre-study for the pre-study. Actually it is not as bad as it sounds. One of the architects called for a meeting today. The purpose was to find all the open questions that we have to answer in the pre-study document. It will then be this document which will be presented to the people who decided about the venture.&lt;br /&gt;&lt;br /&gt;The meeting was actually very productive. Here is some stuff that is worth thinking about if you are in a similar situation.&lt;br /&gt;&lt;br /&gt;Alternatives: this is almost a 100% question you will get. What are the alternatives? Why have you selected product X? I was thinking that maybe we could come up with some sort of comparison matrix from which it will be obvious why we favor Cassandra (otherwise we have to ask us why our selfs probably).&lt;br /&gt;&lt;br /&gt;Product: The product you are evaluating. What tools does it have to offer? Which changes are required for the development and the test environments? For instance many of our testers look up and compare results directly in the database using MySQL query browser. What can we give them instead? Also an interesting aspect is competence. How do you build it up? Are there any trainings you can participate or is there a company from which you can buy professional support? In the case of open-source software, how active is the community and how certain is it that the product is not gonna die within two years?&lt;br /&gt;&lt;br /&gt;Operations: What hardware setup do we need? How do we backup and restore? How do you monitor in the system and what do you monitor? What are the requirements on high-availability and scalability? Talking about scalability: can we add and removes nodes on the fly and how long does it take to replicate / re-balance our data onto these nodes? Do we have a disaster recovery strategy?&lt;br /&gt;&lt;br /&gt;Impact: The most interesting part for me. How do we have to adapt existing applications in order to integrate with Cassandra? What client library is to prefer? How flexible is the new data-store when it comes to changes? For instance we always have big-time trouble if we need to alter our MySQL schema's without downtime - a process for which Facebook even has a special name: &lt;a href="http://www.facebook.com/note.php?note_id=430801045932"&gt;Online Schema Change&lt;/a&gt;. Another interesting question, how can you effectively unit test an application using Cassandra. I guess running an in-process Cassandra, that starts up inside a unit test on a single node, is not catching all errors. Is it realistic to believe, that we can come up with a comprehensive list of use-cases to describe how the data is used in our system. Such a list would greatly influence or data-model. Since there really is only one physical way to store data, how do we handle alternative access. Do we retain a bunch of MySQL indexes to support Cassandra or do we also store these secondary access paths in the main data-store?&lt;br /&gt;&lt;br /&gt;I do not remember all the open questions we came up with during the meeting. This is a good start at least. I hope we can create a great pre-study document to get everyone in the company on board.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-7369357512177978763?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/7369357512177978763/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=7369357512177978763' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7369357512177978763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7369357512177978763'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/09/how-to-select-data-store.html' title='How to select a data-store'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-2678280621744631897</id><published>2010-09-10T08:17:00.000-07:00</published><updated>2010-09-10T08:19:58.996-07:00</updated><title type='text'>Blogging at Disruptive Code</title><content type='html'>Good news everyone - I have been selected as a blogger for the &lt;a href="http://disruptivecode.com/"&gt;Disruptive Code&lt;/a&gt; conference in Stockholm in September. Two weeks ago, a co-worker of mine sent me a link to the dcode website. I have not heard of this conference before but the topics as well as the location seemed very cool. My company is currently evaluating long-time storage prototype based on Cassandra as a replacement for our not-so-long-time MySQL solution. My main interest is therefore the NoSQL sessions and talks about Apache Cassandra. Nice to see, that Eric Evans from Rackspace decided to come visit Scandinavia and talk about Cassandra insights. I saw him &lt;a href="http://javasplitter.blogspot.com/2010/06/big-buzz-in-berlin.html"&gt;earlier&lt;/a&gt; this year in Berlin at the &lt;a href="http://berlinbuzzwords.de/"&gt;Berlin Buzzwords&lt;/a&gt; conference. Looking forward to two exciting days on the Djurgården island.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-2678280621744631897?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/2678280621744631897/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=2678280621744631897' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2678280621744631897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2678280621744631897'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/09/blogging-at-disruptive-code.html' title='Blogging at Disruptive Code'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-3030522799133644787</id><published>2010-06-10T01:02:00.000-07:00</published><updated>2010-06-10T01:16:59.516-07:00</updated><title type='text'>Big Buzz in Berlin</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_BYGcLbgH8o0/TBCcmcPvQgI/AAAAAAAAACA/FlTP-iv8P_k/s1600/dynamo_lovechild.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_BYGcLbgH8o0/TBCcmcPvQgI/AAAAAAAAACA/FlTP-iv8P_k/s320/dynamo_lovechild.jpg" alt="" id="BLOGGER_PHOTO_ID_5481052930741060098" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Flying home from Berlin to Stockholm, I decided to blog about my visit at the &lt;a href="http://berlinbuzzwords.de/"&gt;BerlinBuzzwords&lt;/a&gt; conference. Buzzwords is a conference dedicated to data storage at a high-scale. It was the first time the conference was held and I will definitely come back next year! BerlinBuzzwords was organized as a 2-days event (Monday and Tuesday) plus a Barcamp on Sunday night. The first day centered around Apache Lucene and Solr as well as NoSQL databases using a different data model than relational databases one like MongoDB or CouchDB. The second day was almost entirely dedicated to Hadoop as well as the large-scale NoSQL databases Cassandra and Hypertable.&lt;br /&gt;&lt;br /&gt;The conference started off a bit unorganized, handing out the badges seemed to be problematic and I ended up waiting in a queue for some minutes. Apparently the badges were not alphabetically sorted which made it difficult to find the right badge and impossible to have multiple lines. Single threaded and non-indexed, pretty bad start for a data storage but this was not really a big deal. BerlinBuzzwords was organized in a way that you also could choose from 2 concurrent tracks. Lunch was served, two coffee-breaks were included in the agenda. Drinks between the sessions not marked as coffee-break or lunch had to be paid extra, otherwise they were included. Surprisingly the organizers managed to come up with a really good speaker list. Eric Evans, the author of Domain Driven Design, introduced Apache Cassandra. Michael Busch from Twitter talked about upcoming improvements in Lucene regarding real time search.&lt;br /&gt;&lt;br /&gt;Surprisingly my favorite talk was the one about Hive. It was the last talk of the conference given by &lt;a href="http://sarahdba.blogspot.com/"&gt;Sarah Sproehnle&lt;/a&gt; from Cloudera, who sat next to me during the initial keynote without me knowing who she was. Hive is a client side extension to Hadoop which makes it possible to run SQL-like queries against a HDFS storage. Hive comes with a parser or compiler that will take your SQL and turn it into Map/Reduce jobs. To get started with Hive, install Hadoop as usual. In the next step you need to create the schema for your data. Hive stores it's schema definition like table and column names and data types in a relation database aside from Hadoop. Out of the box this is Derby but you can use a different vendor instead. Tables can be created from the Hive command line utility using the mentioned SQL-like syntax. Once the schema is ready, you load data into Hive. This is done using the LOAD DATA command in the shell, specifying data files that can either exists in- or outside of HDFS. Contrary to normal databases, Hive will not validate the data against the schema before inserting. The validation is done when reading the data which can give you some big errors.&lt;br /&gt;&lt;br /&gt;A nice shortcut for schema creation and data loading is the Cloudera tool &lt;a href="http://www.cloudera.com/developers/downloads/sqoop/"&gt;Sqoop&lt;/a&gt;, which comes with the Cloudera distribution of Hadoop. BerlinBuzzwords also had a session about Sqoop. The tool is run from the command-line. Using Sqoop, you can dump tables from a relational database directly into HDFS. With the --hive-import option, the data is imported in a way usable for Hive. Sqoop can not only dump entire tables but also only an X amount of rows.&lt;br /&gt;&lt;br /&gt;Once your data is in Hive/HDFS you can query it with HiveQL. The syntax is very similar to SQL with a few Hive specific extensions. There is direct support for partitioning and bucketing. User defined functions can be invoked from a HiveQL query. As Hive will take a query and turn it into a Map/Reduce job, you have to remember that there will always be a overhead due to a startup phase. It will take at least 30 seconds before the jobs are executed. Surprisingly, the first example Sarah had in the presentation returned the result immediately. I believe Hive is able to detect that it can go into HDFS directly for very simple queries, without running the whole Map/Reduce thinggie.&lt;br /&gt;&lt;br /&gt;One problem is, now that Hive brought the schema back to a schema-less NoSQL system, of course schema evolution. What happens if you add or drop columns? Hive supports the ALTER TABLE statement but it will only change the information in Metastore if I understood Sarah right. In the easiest case, adding a column at the end of a Table, this might not be a bis issue as Hive will return NULL values for the new column. However, if you add or remove a column in the middle (not sure Hive can do that today), your data will be corrupted and you have to fix it, ie. by writing a Map/Reduce job. Not sure how ALTER TABLE is implemented in Hive but hypothetically, the framework should be able to create this "clean-up" job for you.&lt;br /&gt;&lt;br /&gt;Anyway, very interesting stuff. Here is a &lt;a href="http://www.rklophaus.com/articles/20100607-BerlinBuzzwordsRecap.html"&gt;great blog post&lt;/a&gt; if you want to read more about BerlinBuzzwords 2010.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-3030522799133644787?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/3030522799133644787/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=3030522799133644787' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3030522799133644787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3030522799133644787'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/06/big-buzz-in-berlin.html' title='Big Buzz in Berlin'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BYGcLbgH8o0/TBCcmcPvQgI/AAAAAAAAACA/FlTP-iv8P_k/s72-c/dynamo_lovechild.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-941203676113853380</id><published>2010-05-21T05:48:00.000-07:00</published><updated>2010-05-21T05:55:50.323-07:00</updated><title type='text'>Evaluating Cassandra</title><content type='html'>In the last few months I had the chance to play with Hadoop for a bit. I did some prototyping and unit-testing to learn the framework and see, of it is something we can use in production in my current company. My team is re-designing an existing application which must be able to store 5 years of Poker related data. Five years does probably not sound too bad but given that our system deals about 500 poker hands at peak time, this can be challenging.&lt;br /&gt;&lt;br /&gt;I did a presentation on Hadoop a couple of weeks ago but we decided, that we will not use it as data storage. There are a couple of reasons to it. First of all, the framework is going through a lot of changes. The API has changed a lot between version 0.18.3 and 0.20.2. Often the developer has to deal with code examples, documentation and libraries, that are not updated to the latest Hadoop API. Furthermore with Hadoop you have to tame the underlying HDFS file system and you have to tweak your Map Reduce jobs to make them run optimal. Also the Namenode is like Achilles heel in Hadoop. If the Namenode has a problem you have to have a great knowledge about how to fix and restore it, otherwise you are in trouble.&lt;br /&gt;&lt;br /&gt;We ended up talking about Cassandra, which is also a Apache top-level project. On a very high level, it reminds me of a schema-less database, whereby Hadoop is more of a distributed file storage. I spent a day to familiarize myself with Cassandra. Here are my first thoughts. &lt;br /&gt;&lt;br /&gt;Cassandra does not know any indexes. The data must be stored in an intelligent way, so that it can be retrieved with good performance using the primary key. What does that imply? It means you roughly need to know, how you will access the data in the future and design for it. Otherwise you might end up with uses cases that you cannot serve efficiently, ie. find all players having had Pocket Jacks pre-flop. The good thing about Cassandra is that the data is truly distributed over all nodes. You can read and write from each node at any given time. No single-point of failure like in Hadoop. On the other hand, Cassandra is not processing anything in parallel. If you want to access your data in a distributed, parallel fashion, you need to write a concurrent application talking to several nodes. Alternatively you could use the Hadoop-Cassandra integration, which was added in the latest release. It allows you to write Hadoop Map Reduce Jobs using Cassandra as their InputFormat. Fancy.&lt;br /&gt;&lt;br /&gt;Another impression I also had, is that Cassandra hides a lot of the low level details that you come in contact with when using Hadoop. I also looked at HBase but it was rather complicated to get it running compared to Cassandra. Another feature I like is that it uses JSON a lot. It is easy to visualize your data model or even backing-up and restoring your entire database using JSON. I have not written any test code that actually uses Cassandra. We will see about that. I am looking forward to the &lt;a href="http://berlinbuzzwords.de/"&gt;Berlin Buzzwords&lt;/a&gt; conference in June, where they have a talk about Cassandra and a lot of sessions about Hadoop.&lt;br /&gt;&lt;br /&gt;If you want to know more about Cassandra, I can recommend these great links:&lt;br /&gt;&lt;a href="http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model"&gt;http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.sodeso.nl/?p=80"&gt;http://www.sodeso.nl/?p=80&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/"&gt;http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-941203676113853380?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/941203676113853380/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=941203676113853380' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/941203676113853380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/941203676113853380'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/05/evaluating-cassandra.html' title='Evaluating Cassandra'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-2182803754734871979</id><published>2010-05-06T07:21:00.000-07:00</published><updated>2010-05-06T07:24:46.690-07:00</updated><title type='text'>Tomcat and java.net.SocketException: Too many open files</title><content type='html'>God bless monitoring. An hour ago I received a &lt;a href="http://site24x7.com/index.html"&gt;SMS&lt;/a&gt; from one of my servers that one of my sites was not available anymore. It is a dedicated server that runs 4 Tomcats in parallel. To track down the problem I started looking at the Tomcat logfiles. Whoo whats that? The fourth Tomcat was spamming logfiles like crazy. For the past four days it had created me 4 logfiles having a combined size of 600 GB. I was hitting a java.net.SocketException for too many open files. &lt;br /&gt;&lt;br /&gt;First I thought I had a leak somewhere, which prevented files and sockets from getting closed properly. Actually this was not the main problem. Since all Tomcats were running as the same user, and I had not touched the open file limit for this user, the default maximum of 1024 in Ubuntu 9.10 server was way too little. I checked how many files I had open for this user.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;ps aux | grep tomcat&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then for every PID I ran &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;lsof -p PID | wc -l&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I had cleaned the logs and rebooted already. The combined result was that I already was scratching the 1000 mark for all Tomcats after rebooting. Very thin ice. To make a long story short, here is how to change the maximum open file limit on Ubuntu 9.10 server. &lt;br /&gt;&lt;br /&gt;First you edit &lt;span style="font-weight:bold;"&gt;/etc/security/limits.conf&lt;/span&gt; and add your new limit for the user running Tomcat. In my case the user was called virtual:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;virtual         hard    nofile  5120&lt;br /&gt;virtual         soft    nofile  4096&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In addition to that, edit the file &lt;span style="font-weight:bold;"&gt;/etc/pam.d/common-session&lt;/span&gt; and add&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;session required        pam_limits.so&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;done! Reboot the machine, then verify the changes running &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;su virtual&lt;br /&gt;ulimit -n&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-2182803754734871979?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/2182803754734871979/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=2182803754734871979' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2182803754734871979'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2182803754734871979'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/05/tomcat-and-javanetsocketexception-too.html' title='Tomcat and java.net.SocketException: Too many open files'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-4754157607931164724</id><published>2010-04-30T16:41:00.000-07:00</published><updated>2010-04-30T16:43:27.350-07:00</updated><title type='text'>glftpd trouble after upgrading to Ubuntu 10.04</title><content type='html'>Today I upgraded three computers running Ubuntu 8.04 LTS to the latest version 10.04. On one of the computers I had glftpd running and it did not work anymore after the upgrade. When I checked for the open ports&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;netstat -anp --tcp --udp | grep LISTEN&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;the port glftpd was previously running on, was not in the list anymore and also ps aux | grep glftpd did not show the process. The error "&lt;span style="font-weight:bold;"&gt;service/protocol combination not in /etc/services: glftpd/tcp&lt;/span&gt;" could be seen when restarting xinetd&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;sudo /etc/init.d/xinetd restart&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;while tailing syslog&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;tail -100f /var/log/syslog&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All that was missing was a entry in /etc/services at the end.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;# Local services&lt;br /&gt;glftpd          10087/tcp                       # glftpd&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;First I thought the 10.04 upgrade process was flawed but then I remembered that Ubuntu actually asked me to keep or overwrite some files which I had modified in 8.04. I almost always decided to overwrite the files, except for some local Apache modifications. Apparently /etc/services was one of the files that had changed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-4754157607931164724?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/4754157607931164724/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=4754157607931164724' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4754157607931164724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4754157607931164724'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/04/glftpd-trouble-after-upgrading-to.html' title='glftpd trouble after upgrading to Ubuntu 10.04'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-4358257601464771889</id><published>2010-04-13T06:08:00.000-07:00</published><updated>2010-04-13T06:09:30.821-07:00</updated><title type='text'>Dependencies clashing with Maven Overlays</title><content type='html'>Last year I &lt;a href="http://javasplitter.blogspot.com/2009/08/loving-maven-webapp-overlays-and-jetty.html"&gt;wrote&lt;/a&gt; about a Maven feature which I had discovered back then, that made it possible to "merge" two web-applications using overlays. Unfortunately I discovered a very annoying problem with &lt;a href="http://maven.apache.org/plugins/maven-war-plugin/overlays.html"&gt;overlays&lt;/a&gt; today. In my current project I am using the decode method in the Base64 class in commons-codec. The method was added in commons-codec 1.4. One of the overlay WAR files comes with an older version of commons-codec. What Maven does is that it just throws the dependencies from the overlay project together with your referring project. Make sure you have a look in the lib folder after running &lt;span style="font-weight:bold;"&gt;mvn package&lt;/span&gt;. When I looked into my lib directory in my WEB-INF folder, I realized that I had commons-codec-1.4.jar as well as commons-codec-1.3.jar (the one coming with the overlay) in there. When the web-application loads, version 1.3 is picked up causing a Runtime Exception because the decode method was missing.&lt;br /&gt;&lt;br /&gt;This is pretty serious I think. First of all, I did not realize that the 1.3 dependency slipped in with the overlays. I ran &lt;span style="font-weight:bold;"&gt;mvn dependency:tree -Dverbose -Dincludes=commons-codec&lt;/span&gt; to see what happened but it did not show me any library using commons-codec 1.3. It took a while until I realized what the problem was and that the Maven dependency plugin would not help me here. I went into my local repository and ran a &lt;span style="font-weight:bold;"&gt;find . -name '*.pom' -exec grep -nH 'commons-codec' {} \;&lt;/span&gt; to be able to spot projects using commons-codec. I would like to see a Maven plugin where it can find you libraries using a certain version of a dependency. Anyway, I was lucky. The overlay projects could be upgraded to use codec 1.4 instead and the dependency clash went away.&lt;br /&gt;&lt;br /&gt;Unfortunately one of the WAR overlays uses dom4j-1.6.1.jar which has a dependency to xml-apis-1.0.b2.jar. In the project where I refer to the overlay it depends on xms-apis-1.3.04.jar - so here I am having two jar's of the same type in the classpath and no easy way to fix this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-4358257601464771889?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/4358257601464771889/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=4358257601464771889' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4358257601464771889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4358257601464771889'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/04/dependencies-clashing-with-maven.html' title='Dependencies clashing with Maven Overlays'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-4439489648594282790</id><published>2010-03-12T08:56:00.000-08:00</published><updated>2010-03-12T08:59:23.979-08:00</updated><title type='text'>First Walk in the Clouds</title><content type='html'>During the week I tried the Hadoop framework for the first time. I wrote a proof of concept prototype for an application that we are likely going to develop. I managed to test my code using unit test (mrunit), local integration test starting embedded Hadoop and running it pseudo-distributed on my local Hadoop cluster. The final step was to test it in a real cluster in Amazon EC2.&lt;br /&gt;&lt;br /&gt;I had never started any AMI in EC2 before, so everything was brand new for me. Access to your AWS account as well as you instances is well protected. Setting up proper access to my EC2 instances was very bumpy, especially since I made a mistake with one of the private key files. Unfortunately the error message I got, was not very helpful and I spent quite some time finding the problem.&lt;br /&gt;&lt;br /&gt;If you want to use EC2 you need the following security credentials. Sign-in Credentials: this is basically a email address and a password protecting your AWS account. You need to keep this really safe. &lt;br /&gt;&lt;br /&gt;Access Credentials: they consist of three different sub-groups. First there are the Access Keys. Each EC2 user can have up to two Access Keys. Each Access Key has a Access Key Id and a Secret Access Key. In your system environment variables system environment variables, you add them as &lt;span style="font-weight:bold;"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;. The next subgroup are the X.509 Certificates. Again, you can generate two X.509 Certificates at a time for each EC2 account. Create a new certificate in the AWS management console and download the public and private key. The public key will be in a file that starts with cert-xxxx, the private key will be in a file that starts with pk-xxxx. Copy these two files somewhere and add the full location to your system environment variables as &lt;span style="font-weight:bold;"&gt;EC2_PRIVATE_KEY&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;EC2_CERT&lt;/span&gt;. The last subgroup are the Key Pairs. A key pair is used when you install a AMI executing the ec2-run-instances command. This is a additional protection to restrict access to you running instance. A Key Pair also has a private and a public part. Amazon will keep the public key of the key pair and store it with your instance. To connect to the instance you need the private key part of the Key Pair. &lt;br /&gt;&lt;br /&gt;Run the command: "&lt;span style="font-style:italic;"&gt;ec2-add-keypair foo&lt;/span&gt;" to create a Key Pair named foo. This will return you the private key part which you will have to copy into a file. This is where I made a stupid mistake. I copied only the parts between BEGIN and END into the file but the file needs to contain the whole output. So it is much much better to run this instead: "&lt;span style="font-style:italic;"&gt;ec2-add-keypair foo &gt; ~/.ssh/foo.keypair.ssh&lt;/span&gt;". This will automatically sent the output to a new file in the .ssh directory. Finally give your new file the right permissions using "chmod 0700 ~/.ssh/foo.keypair.ssh". For further reading I recommend &lt;a href="http://wiki.smartfrog.org/wiki/display/sf/EC2+Security"&gt;this page&lt;/a&gt; which I helped me fixing my problem. So if you try to ssh -i into your instance and it asks you for a passphrase, something is not correct with the private key part of your Key Pair. Another manifestation of the same problem if you do not use ssh to connect to your instance but the Cloudera scripts instead. If you are following the Cloudera guide for running Cloudera Distribution AMI for Hadoop, and you are on &lt;a href="http://archive.cloudera.com/docs/_running_jobs.html"&gt;chapter 2.3 Running Jobs&lt;/a&gt; and execute: "hadoop fs -ls /" to get this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;WARN conf.Configuration: DEPRECATED: hadoop-site.xml found in the classpath. Usage of hadoop-site.xml is deprecated. Instead use core-site.xml, mapred-site.xml and hdfs-site.xml to override properties of core-default.xml, mapred-default.xml and hdfs-default.xml respectively &lt;br /&gt;10/03/12 15:09:31 INFO ipc.Client: Retrying connect to server: ec2-184-73-44-221.compute-1.amazonaws.com/184.73.44.221:8020. Already tried 0 time(s). &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It was the same problem for me. Having the correct private key part of the Key pair fixed this for me.&lt;br /&gt;&lt;br /&gt;The last bit of EC2 protection are the Account Identifiers. I think they are only relevant if you plan to share AWS resources with different accounts - not sure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-4439489648594282790?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/4439489648594282790/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=4439489648594282790' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4439489648594282790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4439489648594282790'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2010/03/first-walk-in-clouds.html' title='First Walk in the Clouds'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-6185685680594423030</id><published>2009-12-13T04:01:00.000-08:00</published><updated>2009-12-13T04:35:30.537-08:00</updated><title type='text'>Product Import with Spring Batch - Part1</title><content type='html'>I have &lt;a href="http://www.kanzelbahn.de/Projekte.html"&gt;two websites&lt;/a&gt;, which on a regular basis import products belonging to affiliate programs. The websites were developed in 2005 and 2006. In the process of moving the applications from a Windows to a Linux server, I decided to rewrite and modularize a lot of code that was duplicated or poorly performing. For the product import, I selected &lt;a href="http://static.springsource.org/spring-batch/"&gt;Spring Batch&lt;/a&gt; as new framework. Spring Batch forces you to write little code chunks instead huge jobs, which will then make up your whole batch. Also, there is a &lt;a href="http://blog.springsource.com/2009/11/10/introducing-spring-batch-admin/"&gt;ready-to-use tool for monitoring&lt;/a&gt; and I am familiar with the standard Spring Framework.&lt;br /&gt;&lt;br /&gt;Since the full batch might be complex later, I decided to publish my experiences here while I implement. In the first part, I will use Spring Batch to download a product data file (csv) that belongs to an affiliate program. To build the application, I use Maven 2. In the version for this part, only 5 dependencies are needed. Spring Batch of course, commons-io and commons-lang to help me with some utility stuff, junit and log4j. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&gt;&lt;br /&gt;&lt;br /&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;&lt;br /&gt;    &lt;groupId&gt;com.kanzelbahn.utils&lt;/groupId&gt;&lt;br /&gt;    &lt;artifactId&gt;product-import&lt;/artifactId&gt;&lt;br /&gt;    &lt;packaging&gt;jar&lt;/packaging&gt;&lt;br /&gt;    &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;&lt;br /&gt;    &lt;name&gt;Product Import Library&lt;/name&gt;&lt;br /&gt;&lt;br /&gt;    &lt;properties&gt;&lt;br /&gt;        &lt;spring.batch.version&gt;2.0.3.RELEASE&lt;/spring.batch.version&gt;&lt;br /&gt;        &lt;spring.version&gt;2.5.6&lt;/spring.version&gt;&lt;br /&gt;        &lt;skipJunitTests&gt;false&lt;/skipJunitTests&gt;&lt;br /&gt;    &lt;/properties&gt;&lt;br /&gt;&lt;br /&gt;    &lt;dependencies&gt;&lt;br /&gt;&lt;br /&gt;        &lt;!-- Commons --&gt;&lt;br /&gt;        &lt;dependency&gt;&lt;br /&gt;            &lt;groupId&gt;commons-io&lt;/groupId&gt;&lt;br /&gt;            &lt;artifactId&gt;commons-io&lt;/artifactId&gt;&lt;br /&gt;            &lt;version&gt;1.4&lt;/version&gt;&lt;br /&gt;        &lt;/dependency&gt;&lt;br /&gt;        &lt;dependency&gt;&lt;br /&gt;            &lt;groupId&gt;commons-lang&lt;/groupId&gt;&lt;br /&gt;            &lt;artifactId&gt;commons-lang&lt;/artifactId&gt;&lt;br /&gt;            &lt;version&gt;2.4&lt;/version&gt;&lt;br /&gt;        &lt;/dependency&gt;&lt;br /&gt;&lt;br /&gt;        &lt;!-- Spring Batch --&gt;&lt;br /&gt;        &lt;dependency&gt;&lt;br /&gt;            &lt;groupId&gt;org.springframework.batch&lt;/groupId&gt;&lt;br /&gt;            &lt;artifactId&gt;spring-batch-core&lt;/artifactId&gt;&lt;br /&gt;            &lt;version&gt;${spring.batch.version}&lt;/version&gt;&lt;br /&gt;        &lt;/dependency&gt;&lt;br /&gt;        &lt;dependency&gt;&lt;br /&gt;            &lt;groupId&gt;org.springframework.batch&lt;/groupId&gt;&lt;br /&gt;            &lt;artifactId&gt;spring-batch-test&lt;/artifactId&gt;&lt;br /&gt;            &lt;version&gt;${spring.batch.version}&lt;/version&gt;&lt;br /&gt;        &lt;/dependency&gt;&lt;br /&gt;&lt;br /&gt;        &lt;!-- Junit --&gt;&lt;br /&gt;        &lt;dependency&gt;&lt;br /&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;&lt;br /&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;&lt;br /&gt;            &lt;version&gt;4.4&lt;/version&gt;&lt;br /&gt;            &lt;scope&gt;test&lt;/scope&gt;&lt;br /&gt;        &lt;/dependency&gt;&lt;br /&gt;&lt;br /&gt;        &lt;!-- log4j --&gt;&lt;br /&gt;        &lt;dependency&gt;&lt;br /&gt;            &lt;groupId&gt;log4j&lt;/groupId&gt;&lt;br /&gt;            &lt;artifactId&gt;log4j&lt;/artifactId&gt;&lt;br /&gt;            &lt;version&gt;1.2.9&lt;/version&gt;&lt;br /&gt;        &lt;/dependency&gt;&lt;br /&gt;&lt;br /&gt;    &lt;/dependencies&gt;&lt;br /&gt;&lt;br /&gt;    &lt;build&gt;&lt;br /&gt;        &lt;plugins&gt;&lt;br /&gt;            &lt;plugin&gt;&lt;br /&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;&lt;br /&gt;                &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;&lt;br /&gt;                &lt;configuration&gt;&lt;br /&gt;                    &lt;skip&gt;${skipJunitTests}&lt;/skip&gt;&lt;br /&gt;                    &lt;argLine&gt;-Xms128m -Xmx256m -XX:PermSize=128m -XX:MaxPermSize=256m&lt;/argLine&gt;&lt;br /&gt;                    &lt;parallel&gt;false&lt;/parallel&gt;&lt;br /&gt;                &lt;/configuration&gt;&lt;br /&gt;            &lt;/plugin&gt;&lt;br /&gt;&lt;br /&gt;            &lt;plugin&gt;&lt;br /&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;&lt;br /&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;&lt;br /&gt;                &lt;configuration&gt;&lt;br /&gt;                    &lt;source&gt;1.5&lt;/source&gt;&lt;br /&gt;                    &lt;target&gt;1.5&lt;/target&gt;&lt;br /&gt;                    &lt;showWarnings&gt;false&lt;/showWarnings&gt;&lt;br /&gt;                    &lt;showDeprecation&gt;false&lt;/showDeprecation&gt;&lt;br /&gt;                &lt;/configuration&gt;&lt;br /&gt;            &lt;/plugin&gt;&lt;br /&gt;        &lt;/plugins&gt;&lt;br /&gt;    &lt;/build&gt;&lt;br /&gt;&lt;br /&gt;&lt;/project&gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;pom.xml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One big disadvantage of Spring Batch 2.0, is that you cannot unit test it together with TestNG. The problem is rather in the &lt;a href="http://static.springsource.org/spring/docs/2.5.6/reference/testing.html"&gt;Spring Framework&lt;/a&gt; than Spring Batch. When you write a Spring powered TestNG unit test, you need to extend AbstractTestNGSpringContextTests. There is no Runner to use in the @RunWith annotation, like &lt;a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.html"&gt;SpringJunit4ClassRunner&lt;/a&gt;. This alone is not a problem, but since your Spring Batch test also need to extend from AbstractJobTests, and you cannot inherit twice, TestNG is out of the loop. This will be fixed in Spring Batch 2.1 because then you will not have to extend from AbstractJobTests anymore. I did not use version 2.1 because it was not release at the point of writing this post.&lt;br /&gt;&lt;br /&gt;Let's have a look at the job configuration.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;&lt;beans:beans xmlns="http://www.springframework.org/schema/batch"&lt;br /&gt;     xmlns:beans="http://www.springframework.org/schema/beans"&lt;br /&gt;     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;     xsi:schemaLocation="&lt;br /&gt;           http://www.springframework.org/schema/beans&lt;br /&gt;           http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&lt;br /&gt;           http://www.springframework.org/schema/batch&lt;br /&gt;           http://www.springframework.org/schema/batch/spring-batch-2.0.xsd"&gt;&lt;br /&gt;&lt;br /&gt;    &lt;job id="import"&gt;&lt;br /&gt;        &lt;step id="step1" next="csv_exists"&gt;&lt;br /&gt;            &lt;tasklet ref="initializerTasklet"/&gt;&lt;br /&gt;        &lt;/step&gt;&lt;br /&gt;&lt;br /&gt;        &lt;decision id="csv_exists" decider="doesCsvExistDecision"&gt;&lt;br /&gt;            &lt;next on="FAILED" to="step2" /&gt;&lt;br /&gt;            &lt;next on="COMPLETED" to="step3" /&gt;&lt;br /&gt;        &lt;/decision&gt;&lt;br /&gt;&lt;br /&gt;        &lt;step id="step2" next="step3"&gt;&lt;br /&gt;            &lt;tasklet ref="downloaderTasklet"/&gt;&lt;br /&gt;        &lt;/step&gt;&lt;br /&gt;        &lt;step id="step3"&gt;&lt;br /&gt;            &lt;tasklet ref="finishingTasklet"/&gt;&lt;br /&gt;        &lt;/step&gt;&lt;br /&gt;    &lt;/job&gt;&lt;br /&gt;&lt;br /&gt;&lt;/beans:beans&gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;jobs.xinc&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As you can see, it has only three (well three and a half) steps. Step 1 is implemented in the InitializingTasklet and all it really does is logging the start time. The next step is called csv_exists and is a decision step. If the csv-File for the current day exists, I move on to Step 3, otherwise Step 2 is invoked. Step 2 is implemented in the DownloaderTasklet. This Tasklet will download the csv-File of the current day. Step 3 is implemented in the FinishingTasklet and also performs basic logging. Let's look at the three different Tasklet's and the JobExecutionDecider.&lt;br /&gt;&lt;br /&gt;The InitializingTasklet for Step 1 is pretty much self explaining. On a side note, see how I use FastDateFormat instead of SimpleDateFormatter because it is not thread-safe.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Performs initialization tasks.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 11, 2009&lt;br /&gt; */&lt;br /&gt;public class InitializingTasklet implements Tasklet {&lt;br /&gt;    private static final Logger LOGGER = Logger.getLogger(InitializingTasklet.class);&lt;br /&gt;&lt;br /&gt;    private static final FastDateFormat DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");&lt;br /&gt;    &lt;br /&gt;    public RepeatStatus execute(final StepContribution stepContribution, final ChunkContext chunkContext) throws Exception {&lt;br /&gt;        LOGGER.debug("Initializing at " + DATE_FORMAT.format(new Date()) + ".");&lt;br /&gt;        return RepeatStatus.FINISHED;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;InitializingTasklet.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The JobExecutionDecider for the csv_exists decision is implemented in a class called DoesCsvExistDecision. When constructing the bean, you need to specify a CsvFileFacade to handle the access to the csv-File. CsvFileFacade is an Interface and the my only implementation is the class CsvFileFacadeImpl. The implementation expects a ImportSettings instance upon creation. Everything is wired together by Spring. Using the ImportSettings instance, the CsvFileFacade knows about the root directory, to which the csv-Files shall be downloaded to, the affiliate program id and the location of the csv-File on the Internet. I used the German affiliate program Bakker as a sample implementation.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * A {@link CsvFileFacade} wraps the handling of &lt;code&gt;csv&lt;/code&gt; files.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 11, 2009&lt;br /&gt; */&lt;br /&gt;public interface CsvFileFacade {&lt;br /&gt;&lt;br /&gt;    File getCsvFile();&lt;br /&gt;&lt;br /&gt;    URL getDataFileURL();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;CsvFileFacade.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * A {@link CsvFileFacade} which retrieves informations about the &lt;code&gt;csv&lt;/code&gt; file&lt;br /&gt; * location from a {@link ImportSettings} instance.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 11, 2009&lt;br /&gt; */&lt;br /&gt;public class CsvFileFacadeImpl implements CsvFileFacade {&lt;br /&gt;    private static final Logger LOGGER = Logger.getLogger(CsvFileFacadeImpl.class);&lt;br /&gt;&lt;br /&gt;    private final ImportSettings _settings;&lt;br /&gt;&lt;br /&gt;    public CsvFileFacadeImpl(final ImportSettings settings) {&lt;br /&gt;        _settings = settings;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public File getCsvFile() {&lt;br /&gt;        final String fileName = _settings.getImportable().getProgramId() + ".csv";&lt;br /&gt;        final File dailyDirectory = _settings.getDirectory();&lt;br /&gt;        return new File(dailyDirectory, fileName);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public URL getDataFileURL() {&lt;br /&gt;        return _settings.getImportable().getDataFile();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;CsvFileFacadeImpl.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Wraps all settings for the current import run.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 13, 2009&lt;br /&gt; */&lt;br /&gt;public interface ImportSettings {&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Get's the directory to which the datafile shall be imported to.&lt;br /&gt;     *&lt;br /&gt;     * @return File&lt;br /&gt;     */&lt;br /&gt;    File getDirectory();&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Returns the {@link Importable} which shall be used.&lt;br /&gt;     *&lt;br /&gt;     * @return Importable&lt;br /&gt;     */&lt;br /&gt;    Importable getImportable();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;ImportSettings.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Encapsulates settings of for a single import run.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 13, 2009&lt;br /&gt; */&lt;br /&gt;public class StandardSettings implements ImportSettings {&lt;br /&gt;&lt;br /&gt;    private final File _rootDirectory;&lt;br /&gt;    private final Importable _importable;&lt;br /&gt;&lt;br /&gt;    public StandardSettings(final File importDirectory, final Importable importable) {&lt;br /&gt;        _importable = importable;&lt;br /&gt;&lt;br /&gt;        if (importDirectory == null || !importDirectory.exists()) {&lt;br /&gt;            final String path = importDirectory == null ? "" : importDirectory.getPath();&lt;br /&gt;            throw new IllegalArgumentException("Given importDirectory (" + path + ") does not exist.");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        _rootDirectory = importDirectory;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /** @inheritDoc **/&lt;br /&gt;    public File getDirectory() {&lt;br /&gt;        final Date now = new Date();&lt;br /&gt;        final FastDateFormat df = FastDateFormat.getInstance("yyyy-MM-dd");&lt;br /&gt;        final String day = df.format(now);&lt;br /&gt;&lt;br /&gt;        final File importableDataFileDirectory = new File(_rootDirectory, day);&lt;br /&gt;        if (!importableDataFileDirectory.exists()) {&lt;br /&gt;            try {&lt;br /&gt;                FileUtils.forceMkdir(importableDataFileDirectory);&lt;br /&gt;            } catch (IOException e) {&lt;br /&gt;                throw new IllegalStateException("Unable to create daily import directory (" + day + ")", e);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return importableDataFileDirectory;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /** @inheritDoc **/&lt;br /&gt;    public Importable getImportable() {&lt;br /&gt;        return _importable;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;StandardSettings.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Represents a importable program.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 13, 2009&lt;br /&gt; */&lt;br /&gt;public interface Importable {&lt;br /&gt;    &lt;br /&gt;    public int getProgramId();&lt;br /&gt;&lt;br /&gt;    public URL getDataFile();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;Importable.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * A {@link Importable} which wraps all parameters for the german affiliate program Bakker.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 13, 2009&lt;br /&gt; */&lt;br /&gt;public class Bakker implements Importable, Serializable {&lt;br /&gt;&lt;br /&gt;    private static final long serialVersionUID = 7526472295622776147L;&lt;br /&gt;&lt;br /&gt;    private final int _programId;&lt;br /&gt;    private final URL _dataFile;&lt;br /&gt;&lt;br /&gt;    public Bakker(final int programId, final String dataFileLocation) {&lt;br /&gt;        _programId = programId;&lt;br /&gt;        try {&lt;br /&gt;            _dataFile = new URL(dataFileLocation);&lt;br /&gt;        } catch (MalformedURLException e) {&lt;br /&gt;            throw new IllegalArgumentException("Given dataFileLocation " + dataFileLocation + " is not a valid URL");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getProgramId() {&lt;br /&gt;        return _programId;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public URL getDataFile() {&lt;br /&gt;        return _dataFile;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public boolean equals(final Object o) {&lt;br /&gt;        if (this == o) return true;&lt;br /&gt;        if (o == null || getClass() != o.getClass()) return false;&lt;br /&gt;&lt;br /&gt;        final Bakker bakker = (Bakker) o;&lt;br /&gt;&lt;br /&gt;        if (_programId != bakker._programId) return false;&lt;br /&gt;&lt;br /&gt;        return true;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public int hashCode() {&lt;br /&gt;        return _programId;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String toString() {&lt;br /&gt;        return "Bakker{" +&lt;br /&gt;                ", _programId=" + _programId +&lt;br /&gt;                ", _dataFile=" + _dataFile +&lt;br /&gt;                '}';&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;Bakker.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Every JobExecutionDecider must implement the decide method. I get the csv-File from the  CsvFileFacade, which will be a different file depending on the day you run the job and the affiliate program. If the csv-File exists, I return FlowExecutionStatus.COMPLETED which will invoke Step 3. Otherwise I return FlowExecutionStatus.FAILED which will invoke Step 2 – to download the file.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Tests for the existence of the &lt;code&gt;csv&lt;/code&gt; file in the specified&lt;br /&gt; * {@link CsvFileFacade}.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 11, 2009&lt;br /&gt; */&lt;br /&gt;public class DoesCsvExistDecision implements JobExecutionDecider {&lt;br /&gt;&lt;br /&gt;    private final CsvFileFacade _csvFileFacade;&lt;br /&gt;&lt;br /&gt;    public DoesCsvExistDecision(final CsvFileFacade csvFileFacade) {&lt;br /&gt;        _csvFileFacade = csvFileFacade;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public FlowExecutionStatus decide(final JobExecution jobExecution, final StepExecution stepExecution) {&lt;br /&gt;        final File csvFile = _csvFileFacade.getCsvFile();&lt;br /&gt;        if (csvFile.isFile()) {&lt;br /&gt;            return FlowExecutionStatus.COMPLETED;&lt;br /&gt;        } else {&lt;br /&gt;            return FlowExecutionStatus.FAILED;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;Bakker.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The file download is wrapped in the DownloaderTasklet. The Tasklet again is injected with a reference to the CsvFileFacade. Using the Facade and FileUtils from commons-io, I download the csv-File and store it physical on disc.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Downloads the csv file.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 11, 2009&lt;br /&gt; */&lt;br /&gt;public class DownloaderTasklet implements Tasklet {&lt;br /&gt;&lt;br /&gt;    private final CsvFileFacade _csvFileFacade;&lt;br /&gt;&lt;br /&gt;    public DownloaderTasklet(final CsvFileFacade csvFileFacade) {&lt;br /&gt;        _csvFileFacade = csvFileFacade;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public RepeatStatus execute(final StepContribution stepContribution, final ChunkContext chunkContext) throws Exception {&lt;br /&gt;        final File csvFile = _csvFileFacade.getCsvFile();&lt;br /&gt;        final URL location = _csvFileFacade.getDataFileURL();&lt;br /&gt;        try {&lt;br /&gt;            FileUtils.copyURLToFile(location, csvFile);&lt;br /&gt;        } catch (IOException e) {&lt;br /&gt;            throw new IllegalStateException("Unable to download csv file.", e);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        return RepeatStatus.FINISHED;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;DownloaderTasklet.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The job ends for now in Step 3, which simply invokes log4j one more time.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Contains actions to be done when a Job is finishing.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 11, 2009&lt;br /&gt; */&lt;br /&gt;public class FinishingTasklet implements Tasklet {&lt;br /&gt;    private static final Logger LOGGER = Logger.getLogger(InitializingTasklet.class);&lt;br /&gt;&lt;br /&gt;    private static final FastDateFormat DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");&lt;br /&gt;&lt;br /&gt;    public RepeatStatus execute(final StepContribution stepContribution, final ChunkContext chunkContext) throws Exception {&lt;br /&gt;        LOGGER.debug("Finished at " + DATE_FORMAT.format(new Date()) + ".");&lt;br /&gt;&lt;br /&gt;        return RepeatStatus.FINISHED;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;FinishingTasklet.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Unit testing could not be easier. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Tests the &lt;code&gt;import&lt;/code&gt; job.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz Dec 11, 2009&lt;br /&gt; */&lt;br /&gt;@RunWith(SpringJUnit4ClassRunner.class)&lt;br /&gt;@ContextConfiguration(locations = { "/applicationContext.xml" })&lt;br /&gt;public class ImportJobTest extends AbstractJobTests {&lt;br /&gt;&lt;br /&gt;    @Autowired&lt;br /&gt;    private CsvFileFacade _csvFileFacade;&lt;br /&gt;&lt;br /&gt;    @Transactional&lt;br /&gt;    @Test&lt;br /&gt;    public void testChain() throws Exception {&lt;br /&gt;        final JobExecution jobExecution = this.launchJob();&lt;br /&gt;        assertEquals(jobExecution.getExitStatus(), ExitStatus.COMPLETED);&lt;br /&gt;        assertTrue(_csvFileFacade.getCsvFile().exists());&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;ImportJobTest.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can download the &lt;a href="http://groups.google.com/group/javasplitter/web/product-import.zip"&gt;full source code from Google Groups&lt;/a&gt;. The zip-archive will also contain the remaining parts of the Spring configuration, which is needed to wire all beans together.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-6185685680594423030?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/6185685680594423030/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=6185685680594423030' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6185685680594423030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6185685680594423030'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/12/product-import-with-spring-batch-part1.html' title='Product Import with Spring Batch - Part1'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-5601639862944151574</id><published>2009-11-06T06:09:00.000-08:00</published><updated>2009-11-06T06:13:56.464-08:00</updated><title type='text'>Whats new in Maven 3</title><content type='html'>Yesterday evening I went to a Java event in Stockholm called Java Forum. This was actually the first time I was there, even though the Java Forum meeting is held every month and at different locations in Stockholm. &lt;a href="http://www.javaforum.se/jf/archive.jsp#m53"&gt;Yesterday's meeting&lt;/a&gt; was very interesting for me because it was all about Maven.&lt;br /&gt;&lt;br /&gt;The first presentation was held by Jason van Zyl and was all about the new features in &lt;a href="http://www.sonatype.com/people/2009/04/jason-van-zyl-on-the-future-of-maven-maven-3/"&gt;Maven 3&lt;/a&gt;. Jason is sort of the brain behind Maven. He is CTO at Sonatype, the Maven company. &lt;br /&gt;&lt;br /&gt;The second speech was given by Dennis Lundberg, a guy who helps developing a lot of Maven plug-ins. His talk was about the Maven Site plug-in. Dennis spoke in Swedish, which was fine by me. However, since Jason was present, I think it would have been more polite, if he had talked English too - especially since he had an (unanswered) Maven 3 question which Jason maybe could have answered. Finally Jason took over again and talked about his idea of a next generation infrastructure build up from Maven, M2Eclipse, Nexus and Hudson. Unfortunately there was enough time left to talk about Hudson, so he could only cover M2Eclipse and Nexus. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://m2eclipse.sonatype.org/"&gt;M2Eclipse&lt;/a&gt; looked promising, as it will be the first working Maven integration plug-in for the Eclipse IDE. It wont be out until January 2010 however. Not that I care much, since I am using IntelliJ, but they had some nice features in M2Eclipse. One of them being some extra XML meta-data in the Maven POM, which is only picked up by M2Eclipse and ignored by command-line Maven. This meta-data will speed up the builds in Eclipse when using M2Eclipse. A build which took minutes before can be run in seconds that way. M2Eclipse will download all Sources automatically, this isn't something new, but it also with a single click create you a new project for any of your dependencies. This can be helpful if you project has a dependency and you need to patch something in that dependency very quick.&lt;br /&gt;&lt;br /&gt;Anyway, for me the most interesting presentation was the one about Maven 3 - which will not be released until next year. So what are the big improvements?&lt;br /&gt;&lt;br /&gt;Probably the biggest visible change is the polyglot POM support. You can write your POM files now in different languages. Jason has examples for Groovy, Yaml and Raven. I found some sneak previews &lt;a href="http://www.wakaleo.com/blog/236-writing-your-pom-files-in-groovy-a-sneek-preview-of-maven-3s-polyglot-features"&gt;here&lt;/a&gt; and &lt;a href="http://weblogs.java.net/blog/johnsmart/archive/2009/10/21/writing-your-pom-files-groovy-sneek-preview-maven-3s-polyglot-feat"&gt;here&lt;/a&gt;. It was a little bit funny when Jason had presented the  polyglot feature of Maven 3 and then asked in the audience if anyone thought the original XML format was annoying. No one of the 80 people thought it was annoying. So maybe this feature will not be used very often.&lt;br /&gt;&lt;br /&gt;Those of you who have worked in &lt;a href="http://tomionsoftware.blogspot.com/2005/12/maven-2-how-to-multiple-module-flat.html"&gt;multi-module&lt;/a&gt; or multi-pom projects in Maven2 might have asked themselves, why do I have to specify the parent version in every sub module. Maven 3 will remove this redundancy and add version-less parent elements.&lt;br /&gt;&lt;br /&gt;Another big problem in Maven2 is to find out for an effective POM, which dependency or POM supplied which artifact to the final outcome. Maven3 will address this and it will be easier to see who contributed which artifact. In connection with M2Eclipse it will then for the developer be possible to deselect a certain contribution and select another one instead. All this is only possible because Maven3 decouples execution plan and execution. You POM defines an execution plan which is then brought to execution. Users can make changes to the execution plan before execution. In general, will Maven 3 come with a lot of extensions points, which can be used to statically and dynamically alter the POM. This can for example be leveraged by companies, who have their dependencies and versions in different formats, that want to use parts of Maven 3.&lt;br /&gt;&lt;br /&gt;Extension points seems to be the next big thing in Maven 3. This is actually something where Jason confirmed they stole from Eclipse. Instead of sub-classing a plug-in, like you would do in Maven 2, developers can hook up to different extension points to alter the plug-in behavior. For instance, you might have an extension point to alter the way the web.xml is processed by the WAR plug-in. You don't have to inherit anymore to get customized behavior.&lt;br /&gt;&lt;br /&gt;Error messages will not be as cryptic anymore. Most of the 40+ something error messages will come with a link to the Maven 3 wiki where the error is explained in detail. A state of the art Maven 3 client is currently developed by the Jetty people. They have created their own asynchronous HTTP client library which will be used in the M3 client. Internally, the new Maven uses a micro OSGI container but only for classloading and bundle management. The Maven 3 source code uses Google Guice for dependency injection and a library called &lt;a href="http://code.google.com/p/peaberry/"&gt;Peaberry&lt;/a&gt; which extends Guice with OSGI capabilities.&lt;br /&gt;&lt;br /&gt;Finally, the whole dependency resolution is re-factored by Sonatype into a standalone product. The software will be called &lt;a href="http://www.sonatype.com/people/category/mercury-maven/"&gt;Mercury&lt;/a&gt; and Maven 3 will be a client who uses Mercury. Software companies and developers might as well use Mercury to integrate dependency resolution into their own solutions.&lt;br /&gt;&lt;br /&gt;I got some impressions about Maven 3. It was not so much different on the surface, except for the  polyglot stuff and the extension points. A lot of stuff is happening under the hood. Maven 3 is fully backwards compatible to Maven 2. It runs much faster though and the code base is 1/3 smaller. &lt;br /&gt;&lt;br /&gt;I liked Jason's two presentations in Stockholm. Too bad that time was running out. I would have liked to see more Maven 3 in action from the command line or some extension point code examples in Eclipse.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-5601639862944151574?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/5601639862944151574/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=5601639862944151574' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5601639862944151574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5601639862944151574'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/11/whats-new-in-maven-3.html' title='Whats new in Maven 3'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-7941075426239432915</id><published>2009-10-28T01:38:00.000-07:00</published><updated>2009-10-28T03:03:46.146-07:00</updated><title type='text'>Pimp ma JDBC ResultSet</title><content type='html'>Last week I had to work on an interesting problem. My team was working on some sort of reporting application which creates csv like reports based on JDBC &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html"&gt;ResultSet's&lt;/a&gt; returned from querying a database. Earlier this year, I refactored some code sections which created the report files, to make them testable by unit tests. Since the application was already using Spring 2.5, I decided to refactor the plain old JDBC code and use the Spring &lt;a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/jdbc/core/JdbcTemplate.html"&gt;JdbcTemplate&lt;/a&gt; instead.&lt;br /&gt;&lt;br /&gt;My unit tests passed and I was happy. The code never went live though, as other stuff got a higher priority. After a while the application was put on release schedule but (of course while I was away from work) system verification found a big problem. When creating the report the application crashed with a &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/OutOfMemoryError.html"&gt;OutOfMemoryError&lt;/a&gt;. Another developer started looking at my refactored code. First of all, I was not aware that the reports could contain million of rows. The one report that caused the  OutOfMemoryError had 16 million rows. It was pretty naive that I used the query method in the &lt;a href="http://static.springsource.org/spring/docs/2.5.6/api/org/springframework/jdbc/core/simple/SimpleJdbcTemplate.html"&gt;SimpleJdbcTemplate&lt;/a&gt; passing a ParameterizedRowMapper as argument. Obviously the returned list would contain 16 millions entries and never fit into memory. &lt;br /&gt;&lt;br /&gt;Since I was not in the office, the developer who looked at my code wrote me a mail. I don't remember the exact words but he asked me, if I had a particular reason to use SimpleJdbcTemplate instead of the old code. I felt challenged. Of course it would be madness, not to use JdbcTemplate or  SimpleJdbcTemplate in a Spring powered application. However he had one good argument - the old code worked! I started investigating how to archive the same performance using only Spring classes. I suggested to use the &lt;a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/jdbc/core/JdbcTemplate.html#query(org.springframework.jdbc.core.PreparedStatementCreator,%20org.springframework.jdbc.core.RowCallbackHandler)"&gt;query&lt;/a&gt; method of the JdbcTemplate instead. When using this method, you have the opportunity to supply a &lt;a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/jdbc/core/RowCallbackHandler.html"&gt;RowCallbackHandler&lt;/a&gt; as argument. The processRow method of the  RowCallbackHandler is then invoked for every row in the ResultSet and we could directly write a line in our report.&lt;br /&gt;&lt;br /&gt;We changed the code once more. The unit test still ran. However, we quite soon discovered that we did not really fix the main issue. Even though it could handle more records now, it would still fail with an  OutOfMemoryError. Instead of building up a huge List as before, it created a huge ResultSet in memory. Another big problem became apparent. Processing the rows was now very slow. Compared to before, a report with 16 Million rows which took 7 minutes to create before would now be created in 90 minutes. Now I felt really challenged! I did not want to go back to the old code and use good 'ol plain JDBC again. &lt;br /&gt;&lt;br /&gt;I downloaded the Spring source code and compared our previous implementation with the way we run now. Soon I found out about the problem. The old code created something which I call a streaming ResultSet. This was done by specifying flags java.sql.ResultSet.TYPE_FORWARD_ONLY and java.sql.ResultSet.CONCUR_READ_ONLY in the createStatement method of the Connection and also specifying a fetch size of Integer.MIN_VALUE. I compared this with what was JdbcTemplate was doing. Spring also used the createStatement method of the Connection class but without specifying extra flags. This was fine, since TYPE_FORWARD_ONLY and CONCUR_READ_ONLY are used by default. The JdbcTemplate also had a &lt;a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/jdbc/core/JdbcTemplate.html#setFetchSize(int)"&gt;setFetchSize&lt;/a&gt; method, cool. However, by looking at the source, I saw that it would completely ignore negative fetch sizes. This is pretty bad. I think it would be much nicer to throw an exception here, since the client calling setFetchSize with a negative value will now know that his fetch size is ignored. On the other hand it was easy enough to create a new subclass which allowed negative fetch sizes. I called it StreamingResultSetEnabledJdbcTemplate.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * A {@link JdbcTemplate} which will make it possible to mimic streaming Resultset's by allowing negative fetch sizes&lt;br /&gt; * to be set on the {@link Statement}.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz&lt;br /&gt; */&lt;br /&gt;public class StreamingResultSetEnabledJdbcTemplate extends JdbcTemplate&lt;br /&gt;{&lt;br /&gt;    public StreamingResultSetEnabledJdbcTemplate(final DataSource dataSource)&lt;br /&gt;    {&lt;br /&gt;        super(dataSource);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public StreamingResultSetEnabledJdbcTemplate(final DataSource dataSource, final boolean lazyInit)&lt;br /&gt;    {&lt;br /&gt;        super(dataSource, lazyInit);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;  * Prepare the given JDBC Statement (or PreparedStatement or CallableStatement),&lt;br /&gt;  * applying statement settings such as fetch size, max rows, and query timeout.&lt;br /&gt;     * Unlike in {@link JdbcTemplate} you can also specify a negative fetch size.&lt;br /&gt;     *&lt;br /&gt;  * @param stmt the JDBC Statement to prepare&lt;br /&gt;  * @throws java.sql.SQLException if thrown by JDBC API&lt;br /&gt;  * @see #setFetchSize&lt;br /&gt;  * @see #setMaxRows&lt;br /&gt;  * @see #setQueryTimeout&lt;br /&gt;  * @see org.springframework.jdbc.datasource.DataSourceUtils#applyTransactionTimeout&lt;br /&gt;  */&lt;br /&gt;    @Override&lt;br /&gt;    protected void applyStatementSettings(final Statement stmt) throws SQLException&lt;br /&gt;    {&lt;br /&gt;  int fetchSize = getFetchSize();&lt;br /&gt;        stmt.setFetchSize(fetchSize);&lt;br /&gt;&lt;br /&gt;  int maxRows = getMaxRows();&lt;br /&gt;  if (maxRows &gt; 0) {&lt;br /&gt;   stmt.setMaxRows(maxRows);&lt;br /&gt;  }&lt;br /&gt;  DataSourceUtils.applyTimeout(stmt, getDataSource(), getQueryTimeout());&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Using my new class killed all the issues we had. Memory was not a problem anymore and the speed was back. One drawback, if you use my solution, is that some methods like &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html#isLast()"&gt;isLast&lt;/a&gt; or &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html#isFirst()"&gt;isFirst&lt;/a&gt; are not supported on the ResultSet anymore. If your code invokes them and the ResultSet was created using the described approach, an Exception is thrown.&lt;br /&gt;&lt;br /&gt;To come up with some numbers, I created a &lt;a href="http://groups.google.com/group/javasplitter/web/resultsets.zip"&gt;simple test project&lt;/a&gt; using Maven. Feel free to &lt;a href="http://groups.google.com/group/javasplitter/web/resultsets.zip"&gt;download&lt;/a&gt; and test for yourself. You need a local &lt;a href="http://dev.mysql.com/downloads/mysql/"&gt;MySQL database&lt;/a&gt;, a schema and a database user who can write to this schema. Download the zip file and extract to any directory. Go in src/main/resources and apply the correct database settings in &lt;span style="font-weight:bold;"&gt;applicationContext.xml&lt;/span&gt;. After that open a command prompt, go into the directory where you extracted the zip file to and run &lt;span style="font-weight:bold;"&gt;mvn test&lt;/span&gt;. &lt;a href="http://maven.apache.org/download.html"&gt;Maven 2&lt;/a&gt; must be installed of course.&lt;br /&gt;&lt;br /&gt;This will run two TestNG unit tests. The first test is called JdbcTemplateTest. The test creates 1,5 million rows in the MySQL database and executes the same retrieval code first using a StreamingResultSetEnabledJdbcTemplate then using a JdbcTemplate. I could not write the unit test with more records as you will hit a OutOfMemoryError for JdbcTemplate otherwise. Here is the  JdbcTemplateTest.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Tests and measures the {@link JdbcTemplate} and {@link StreamingResultSetEnabledJdbcTemplate}.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz&lt;br /&gt; */&lt;br /&gt;public class JdbcTemplateTest extends AbstractJdbcTemplateTest&lt;br /&gt;{&lt;br /&gt;    @Test(groups = "unit")&lt;br /&gt;    public void testRun()&lt;br /&gt;    {&lt;br /&gt;        runTestUsingTemplate(getStreamingResultSetEnabledJdbcTemplate());&lt;br /&gt;        runTestUsingTemplate(getJdbcTemplate());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void runTestUsingTemplate(final JdbcTemplate jdbcTemplate)&lt;br /&gt;    {&lt;br /&gt;        final String selectStatement = getQuery();&lt;br /&gt;&lt;br /&gt;        final AtomicLong count = new AtomicLong();&lt;br /&gt;&lt;br /&gt;        final Date before = new Date();&lt;br /&gt;&lt;br /&gt;        final String className = jdbcTemplate.getClass().getSimpleName();&lt;br /&gt;        System.out.println("Testing " + className);&lt;br /&gt;&lt;br /&gt;        jdbcTemplate.query(selectStatement, new RowCallbackHandler()&lt;br /&gt;        {&lt;br /&gt;            public void processRow(ResultSet resultSet) throws SQLException&lt;br /&gt;            {&lt;br /&gt;                final long i = count.incrementAndGet();&lt;br /&gt;                if (i % 500000 == 0) System.out.println("Iterated " + i + " rows");&lt;br /&gt;            }&lt;br /&gt;        });&lt;br /&gt;&lt;br /&gt;        final Date after = new Date();&lt;br /&gt;        final long duration = after.getTime() - before.getTime();&lt;br /&gt;&lt;br /&gt;        System.out.println(className + ".query method took " + duration + " ms.");&lt;br /&gt;&lt;br /&gt;        assertEquals(count.get(), getNumberOfRecords());&lt;br /&gt;&lt;br /&gt;        renderSeperator();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected JdbcTemplate getJdbcTemplate()&lt;br /&gt;    {&lt;br /&gt;        final JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());&lt;br /&gt;        jdbcTemplate.setFetchSize(Integer.MIN_VALUE);&lt;br /&gt;        return jdbcTemplate;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected JdbcTemplate getStreamingResultSetEnabledJdbcTemplate()&lt;br /&gt;    {&lt;br /&gt;        final JdbcTemplate jdbcTemplate = new StreamingResultSetEnabledJdbcTemplate(getDataSource());&lt;br /&gt;        jdbcTemplate.setFetchSize(Integer.MIN_VALUE);&lt;br /&gt;        return jdbcTemplate;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The test data is created in the abstract base class AbstractJdbcTemplateTest.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;/**&lt;br /&gt; * Inserts the test data.&lt;br /&gt; *&lt;br /&gt; * @author reik.schatz&lt;br /&gt; */&lt;br /&gt;@ContextConfiguration(locations = "/applicationContext.xml")&lt;br /&gt;public abstract class AbstractJdbcTemplateTest extends AbstractTestNGSpringContextTests&lt;br /&gt;{&lt;br /&gt;    @Autowired&lt;br /&gt;    private DataSource m_dataSource;&lt;br /&gt;&lt;br /&gt;    protected DataSource getDataSource()&lt;br /&gt;    {&lt;br /&gt;        return m_dataSource;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected String getQuery()&lt;br /&gt;    {&lt;br /&gt;        return "SELECT * FROM rounds";&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @BeforeClass&lt;br /&gt;    protected void setUp()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("\n\n " + getClass().getSimpleName() + ": \n");&lt;br /&gt;&lt;br /&gt;        final JdbcTemplate jdbcTemplate = new JdbcTemplate(m_dataSource);&lt;br /&gt;        &lt;br /&gt;        renderSeperator();&lt;br /&gt;        System.out.println("Dropping table");&lt;br /&gt;        jdbcTemplate.update("DROP TABLE IF EXISTS rounds;");&lt;br /&gt;&lt;br /&gt;        System.out.println("Creating table");&lt;br /&gt;        jdbcTemplate.update("CREATE TABLE rounds (round_id INT, player_id INT DEFAULT 0, gaming_center INT DEFAULT 1, last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP);");&lt;br /&gt;        jdbcTemplate.update("ALTER TABLE rounds DISABLE KEYS;");&lt;br /&gt;        jdbcTemplate.update("LOCK TABLES rounds WRITE;");&lt;br /&gt;&lt;br /&gt;        final Date now = new Date();&lt;br /&gt;&lt;br /&gt;        final StringBuilder sb = new StringBuilder();&lt;br /&gt;        final long records = getNumberOfRecords();&lt;br /&gt;&lt;br /&gt;        for (int i = 0; i &lt; records; i++)&lt;br /&gt;        {&lt;br /&gt;            if (i % 100000 == 0)&lt;br /&gt;            {&lt;br /&gt;                sb.append("INSERT INTO rounds(round_id) VALUES(" + i + ")");&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;                 sb.append(",(" + i + ")");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            if (i % 100000 == 99999 || i == (records - 1))&lt;br /&gt;            {&lt;br /&gt;                jdbcTemplate.update(sb.toString());&lt;br /&gt;                sb.setLength(0);&lt;br /&gt;&lt;br /&gt;                System.out.println("Inserted " + i + " rows");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        jdbcTemplate.update("UNLOCK TABLES;");&lt;br /&gt;        jdbcTemplate.update("ALTER TABLE rounds ENABLE KEYS;");&lt;br /&gt;&lt;br /&gt;        System.out.println("Insertion took " + (new Date().getTime() - now.getTime()) + " ms");&lt;br /&gt;&lt;br /&gt;        renderSeperator();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected long getNumberOfRecords()&lt;br /&gt;    {&lt;br /&gt;        return 1500000L;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected void renderSeperator()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("============================================================");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Even though it is only iterating 1.500.000 million records, you already see a difference between JdbcTemplate and StreamingResultSetEnabledJdbcTemplate. Using the  StreamingResultSetEnabledJdbcTemplate the iteration runs for 1526 ms. Using the JdbcTemplate the iteration runs for 5192 ms. Don't forget, you cannot even use the JdbcTemplate if you have 2, 3 or 4 million records in the ResultSet. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;JdbcTemplateTest: &lt;br /&gt;&lt;br /&gt;Testing StreamingResultSetEnabledJdbcTemplate&lt;br /&gt;Iterated 500000 rows&lt;br /&gt;Iterated 1000000 rows&lt;br /&gt;Iterated 1500000 rows&lt;br /&gt;StreamingResultSetEnabledJdbcTemplate.query method took 1526 ms.&lt;br /&gt;&lt;br /&gt;Testing JdbcTemplate&lt;br /&gt;Iterated 500000 rows&lt;br /&gt;Iterated 1000000 rows&lt;br /&gt;Iterated 1500000 rows&lt;br /&gt;JdbcTemplate.query method took 5192 ms.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally I wrote another unit test. The FastInsertionTest iterates 16 million rows using  StreamingResultSetEnabledJdbcTemplate. The iteration runs for only 9507 ms. Not bad. &lt;br /&gt;&lt;br /&gt;Summary: I did a very very small change with a gigantic effect. I recommend two things to the Spring development team. First, in the setFetchSize method an Exception should be thrown when someone sents in a negative fetch size. Second, in future Spring versions the JdbcTemplate should enable the use of negative fetch sizes, so that the StreamingResultSetEnabledJdbcTemplate becomes obsolete. Maybe something is coming with Spring 3.0.&lt;br /&gt;&lt;br /&gt;On a side note, each of the two unit tests creates a lot of test data. In the first version, I wrote a for-loop that fired an Insert statement for every iteration. This was incredibly slow, about 20 seconds for just 100.000 Inserts. I checked a few good resources on the web, like the &lt;a href="http://dev.mysql.com/doc/refman/5.1/en/insert-speed.html"&gt;MySQL documentation&lt;/a&gt; or &lt;a href="http://kevin.vanzonneveld.net/techblog/article/improve_mysql_insert_performance/"&gt;this blog post&lt;/a&gt;, and refactored my code.&lt;br /&gt;&lt;br /&gt;The JdbcTemplateTest inserts the test data now using a MySQL feature called &lt;a href="http://dev.mysql.com/doc/refman/5.1/en/insert.html"&gt;multiple value Insert&lt;/a&gt;. Instead of firing an Insert statement every iteration in the for-loop, I add a new value to multiple value Insert statement. Then every 100.000 iterations I fire the statement. So for 1.5 million rows, I fire only 15 Insert statements. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;final StringBuilder sb = new StringBuilder();&lt;br /&gt;final long records = getNumberOfRecords();&lt;br /&gt;&lt;br /&gt;for (int i = 0; i &lt; records; i++)&lt;br /&gt;{&lt;br /&gt;    if (i % 100000 == 0)&lt;br /&gt;    {&lt;br /&gt;        sb.append("INSERT INTO rounds(round_id) VALUES(" + i + ")");&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;         sb.append(",(" + i + ")");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    if (i % 100000 == 99999 || i == (records - 1))&lt;br /&gt;    {&lt;br /&gt;        jdbcTemplate.update(sb.toString());&lt;br /&gt;        sb.setLength(0);&lt;br /&gt;&lt;br /&gt;        System.out.println("Inserted " + i + " rows");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This runs very fast as you can see in the test output. The 1.500.000 records are inserted in only 2601 ms.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;Dropping table&lt;br /&gt;Creating table&lt;br /&gt;Inserted 99999 rows&lt;br /&gt;Inserted 199999 rows&lt;br /&gt;Inserted 299999 rows&lt;br /&gt;Inserted 399999 rows&lt;br /&gt;Inserted 499999 rows&lt;br /&gt;Inserted 599999 rows&lt;br /&gt;Inserted 699999 rows&lt;br /&gt;Inserted 799999 rows&lt;br /&gt;Inserted 899999 rows&lt;br /&gt;Inserted 999999 rows&lt;br /&gt;Inserted 1099999 rows&lt;br /&gt;Inserted 1199999 rows&lt;br /&gt;Inserted 1299999 rows&lt;br /&gt;Inserted 1399999 rows&lt;br /&gt;Inserted 1499999 rows&lt;br /&gt;Insertion took 2601 ms&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The FastInsertionTest uses another feature of MySQL called &lt;a href="http://dev.mysql.com/doc/refman/5.1/en/load-data.html"&gt;INFILE insertion&lt;/a&gt;. This time, the for-loop in my code builds up a gigantic text file which I then import into my MySQL database using the LOAD DATA INFLIE syntax. One drawback of using of this approach is that the number of columns in the file must match the columns in the table you are trying to insert to. In other words, you cannot use the DEFAULT feature of a column. In my table rounds, I have 4 columns but column 2, 3 and 4 have a DEFAULT value. It would be nice if my file would only contain the first column values, as the file would be much smaller in this case. This however is not possible. I have to add column values for column 2, 3 and 4 as well. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;final File javaIoTmpDir = SystemUtils.getJavaIoTmpDir();&lt;br /&gt;assertNotNull(javaIoTmpDir);&lt;br /&gt;assertTrue(javaIoTmpDir.exists());&lt;br /&gt;&lt;br /&gt;final File dumpFile = new File(javaIoTmpDir, "dump.txt");&lt;br /&gt;if (dumpFile.exists())&lt;br /&gt;{&lt;br /&gt;    assertTrue(dumpFile.delete());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Writer out = null;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;    out = new BufferedWriter(new FileWriter(dumpFile));&lt;br /&gt;}&lt;br /&gt;catch (IOException e)&lt;br /&gt;{&lt;br /&gt;    fail();&lt;br /&gt;}&lt;br /&gt;assertNotNull(out);&lt;br /&gt;&lt;br /&gt;final long records = getNumberOfRecords();&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;    for (int i = 0; i &lt; records; i++)&lt;br /&gt;    {&lt;br /&gt;        out.write("1");&lt;br /&gt;        out.write('\t');&lt;br /&gt;        out.write("1");&lt;br /&gt;        out.write('\t');&lt;br /&gt;        out.write("1");&lt;br /&gt;        out.write('\t');&lt;br /&gt;        out.write("0000-00-00 00:00:00");&lt;br /&gt;        out.write('\n');&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;catch (IOException e)&lt;br /&gt;{&lt;br /&gt;    fail();&lt;br /&gt;}&lt;br /&gt;finally&lt;br /&gt;{&lt;br /&gt;    out.close();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;jdbcTemplate.update("LOAD DATA INFILE '" + dumpFile.getPath() + "' INTO TABLE rounds");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see in the test output, the 16.000.000 rows are inserted into the MySQL database in only 24852 ms. Awesome.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;FastInsertionTest: &lt;br /&gt;============================================================&lt;br /&gt;Dropping table&lt;br /&gt;Creating table&lt;br /&gt;Inserting 16000000 rows took 24852 ms&lt;br /&gt;============================================================&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-7941075426239432915?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/7941075426239432915/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=7941075426239432915' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7941075426239432915'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/7941075426239432915'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/10/pimp-ma-jdbc-resultset.html' title='Pimp ma JDBC ResultSet'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-3198420903450984990</id><published>2009-09-23T23:48:00.000-07:00</published><updated>2009-09-23T23:52:01.676-07:00</updated><title type='text'>Parsing Tomcat Access Log for 404 Errors</title><content type='html'>Yesterday I set up a new dedicated server for a couple of domains. I have Apache with mod_proxy running in front of a Tomcat. It was pretty easy to set up. Since these were quite old domains, I have not really worked with them in a while. I was interested, if I get a lot of 404 errors for these websites. I came up with a nice looking Linux command. Something I remembered from my current job.&lt;br /&gt;&lt;br /&gt;Given that you have logging enabled in your Tomcat server.xml configuration, probably like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;Valve className="org.apache.catalina.valves.FastCommonAccessLogValve" directory="/etc/tomcats/logs" prefix="access." suffix=".log" pattern="common" resolveHosts="false" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Prefix and suffix could be different of course but this does not matter. This will create you a daily log file like access.2009-09-24.log. Now to get a nice overview and detect 404 errors fast, run this command:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;cat access.2009-09-24.log | cut -f 7,8,9 -d \ | sort | uniq -c | sort -gr&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here are the details. First you display the file contents using cat. This is piped through the cut command. -f 7,8,9 -d \ specifies that you are interested in the fields 7,8 and 9 and the delimiter shall be a whitespace. The syntax for the whitespace delimiter only works that way because another pipe follows. The sort applies some alphabetical sorting. Next pipe is uniq -c which will eliminated duplicates but also adds a count for each unique row. Finally sort -gr will apply numerical sorting based on the result of uniq -c and in reverse order, having the highest number first. Here is some sample output:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;6 /includes/css/schufafreie.css HTTP/1.1" 200&lt;br /&gt;6 /images/spacer.gif HTTP/1.1" 200&lt;br /&gt;6 /images/linksline.gif HTTP/1.1" 200&lt;br /&gt;6 /images/banner_oben.jpg HTTP/1.1" 200&lt;br /&gt;6 /favicon.ico HTTP/1.1" 404&lt;br /&gt;5 /includes/js/schufafreie.js HTTP/1.1" 200&lt;br /&gt;5 /images/pfeil_r_grau.gif HTTP/1.1" 200&lt;br /&gt;5 / HTTP/1.1" 200&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-3198420903450984990?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/3198420903450984990/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=3198420903450984990' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3198420903450984990'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3198420903450984990'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/09/parsing-tomcat-access-log-for-404.html' title='Parsing Tomcat Access Log for 404 Errors'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-6992779566737063337</id><published>2009-08-31T23:09:00.000-07:00</published><updated>2009-08-31T23:33:49.566-07:00</updated><title type='text'>Loving Maven Webapp Overlays and Jetty Plugin</title><content type='html'>Alright maybe this is so basic for most of you that I should not blog about this, but yesterday I found out about a Maven feature which I really like. I guess most of you are familiar with the so called "&lt;a href="http://maven.apache.org/pom.html#Inheritance"&gt;multi-pom&lt;/a&gt;" or "&lt;a href="http://maven.apache.org/pom.html#Aggregation"&gt;multi-module&lt;/a&gt;" projects in Maven. This is a Maven project structure, where you have one root pom.xml file defined as parent and then a couple of sub-projects, each with it's own pom.xml. Each of the sub projects, can then be used to create their own build artifacts. This is a nice way to separate the logic of an application into small and reusable deployment artifacts.&lt;br /&gt;&lt;br /&gt;Let's say you are writing a standard web-application. To maintain the website content, you have also added some jsp files and classes which function as a "semi-CMS". Additionally you have written a nice database access layer and some useful helper classes for Spring. The straightforward approach would be to create one single Maven project of archetype &lt;span style="font-weight:bold;"&gt;maven-archetype-webapp&lt;/span&gt;. This will produce a WAR file as deployment artifact and you are fine. However, it would be much nicer to have separate deployment artifacts for better maintainability and reuseability. This could be: one JAR file (A) containing all the Spring helper and database classes, one WAR file (B) containing the CMS part and one WAR file (C) containing the real web-application but also referencing the other two deploy artifacts. This setup would have been very easy and common, if A and B produced two JAR deploy artifacts. Fortunately it is also possible to reference one Maven project that produces a WAR file from another Maven project which &lt;span style="font-weight:bold;"&gt;also&lt;/span&gt; produces a WAR file. This is then called &lt;a href="http://maven.apache.org/plugins/maven-war-plugin/overlays.html"&gt;WAR overlay&lt;/a&gt;. For those interested in the source code, &lt;a href="http://javasplitter.googlegroups.com/web/overlay.zip?gda=hEClxz0AAAAh1iYCBL0jyWuJTChQV__Roju8xj5LzxwrcfQ5pjF8Uu1o1RqxhhJyebmkG_i2QjHlNv--OykrTYJH3lVGu2Z5"&gt;here is a very basic prototype&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Given the above scenario, all you have to do really is to add a dependency in your project C to project B like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;javasplitter&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;webappB&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;&lt;br /&gt;    &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will merge the folder structure of your webappB into the webappC folder structure. The final WAR file, will then be a merge of all static resources (Images, JSP's, CSS, Javascript) of the two combined WAR files from webappB and C. It will also contain all classes of the two Maven projects in the WEB-INF/classes directory of the final WAR. However, in a real life project I had the problem, that if a class within webappC also uses a class from webappB, these classes were not found anymore. I fixed this by adding an additional dependency in webappC like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;javasplitter&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;webappB&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;type&amp;gt;jar&amp;lt;/type&amp;gt;&lt;br /&gt;    &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This might not be the preferred way to fix this but it worked for me. Now for the part, why I like the above setup so much and blog about it. The &lt;a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin"&gt;Maven Jetty Plugin&lt;/a&gt; gives you the opportunity to immediately test your web-application within a container. When you run &lt;span style="font-weight:bold;"&gt;mvn jetty:run&lt;/span&gt; it will start a Jetty that loads your webapplication. All the changes done to the static resources (JSP files, Images, CSS, Javascript etc.) are immediately visible when you reload the page in your browser. If your IDE project is set up to compile classes in target/classes (which will be the case if you use IntelliJ and Maven project type), the web application context reloads automatically when you recompile a single class. You can define how often you want the Maven Jetty Plugin to scan the classpath for changes before reloading. Given all this, you can do some real rapid development without long build-deploy cycles between every code change. In my previous set up I had used the &lt;a href="http://cargo.codehaus.org/Maven2+plugin"&gt;Maven Cargo Plugin&lt;/a&gt; instead and had it deploy the WAR file into a running Tomcat somewhere else on my computer. This was a big problem, as every time I changed a single character in one of my JSP files, I had to rebuild and redeploy the WAR file. I lost a lot of time.&lt;br /&gt;&lt;br /&gt;Here is how I have configured the Maven Jetty Plugin in webappC:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;build&amp;gt;&lt;br /&gt;&amp;lt;plugins&amp;gt;&lt;br /&gt;    &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.mortbay.jetty&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-jetty-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;6.1.12&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;            &amp;lt;scanIntervalSeconds&amp;gt;2&amp;lt;/scanIntervalSeconds&amp;gt;&lt;br /&gt;            &amp;lt;webAppConfig&amp;gt;&lt;br /&gt;                &amp;lt;contextPath&amp;gt;/&amp;lt;/contextPath&amp;gt;&lt;br /&gt;                &amp;lt;baseResource implementation="org.mortbay.resource.ResourceCollection"&amp;gt;&lt;br /&gt;                    &amp;lt;resourcesAsCSV&amp;gt;src/main/webappC,../cms/src/main/webappB&amp;lt;/resourcesAsCSV&amp;gt;&lt;br /&gt;                &amp;lt;/baseResource&amp;gt;&lt;br /&gt;            &amp;lt;/webAppConfig&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;    &amp;lt;/plugin&amp;gt;&lt;br /&gt;&amp;lt;/plugins&amp;gt;&lt;br /&gt;&amp;lt;/build&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Some things worth mentioning. I set the classpath scan interval manually to 2 seconds. I use the root context to reach my webapplication in the browser. You have to pass in the two webapp directories containing the static resources as a Resource in the webAppConfig element. The order in which you do this might be important. I have a Servlet in my webappC which loaded on startup and read a file path out of the ServletConfig (ServletContext). If I had webappB before webappC in the above example, it would load my Servlet using the webappB ServletConfig which was a big problem because all the file paths were wrong that way. Finally note the resourcesAsCSV element. In the &lt;a href="http://docs.codehaus.org/display/JETTY/Multiple+WebApp+Source+Directory"&gt;documentation of the Maven Jetty Plugin&lt;/a&gt; you are being told to use just a resources element but this will not work properly. You will end up with an error similar to &lt;span style="font-weight:bold;"&gt;Cannot assign configuration entry 'resources' to 'class [Lorg.mortbay.resource.Resource;'&lt;/span&gt; - so use resourcesAsCSV instead.&lt;br /&gt;&lt;br /&gt;I would also like to add that developing a Grail webapplication using Maven gives you an even faster rapid development experience. I used the &lt;a href="http://forge.octo.com/maven/sites/mtg/grails-maven-plugin/"&gt;Maven Grails Plugin&lt;/a&gt; for one project, which also uses a Jetty (&lt;span style="font-weight:bold;"&gt;mvn grails:run-app&lt;/span&gt;) to test the deployment artifact. This Jetty however, was able to detect class changes automatically and much faster. I had not to manually compile in my IntelliJ IDEA anymore, just saving the modified source file in IntelliJ would immediately update my web-application context and the changes were visible. I have not checked how this behavior was implemented but obviously some very smart Grails people came up with a great idea.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-6992779566737063337?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/6992779566737063337/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=6992779566737063337' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6992779566737063337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6992779566737063337'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/08/loving-maven-webapp-overlays-and-jetty.html' title='Loving Maven Webapp Overlays and Jetty Plugin'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-4993471936054825444</id><published>2009-07-31T01:09:00.000-07:00</published><updated>2011-11-14T02:09:42.021-08:00</updated><title type='text'>Where to host your Grails application</title><content type='html'>As I wrote recently, I have joined the Grails and Groovy crowd. I finished my first simple web application, which was actually more than just a local prototype, but I needed to host it somewhere. As with all Java based web-application, it is much harder to find a good and cheap hosting provider. It is much easier with PHP. So I started to look for a Grails hosting provider and ended up where every Grails developer will be looking sooner or later - &lt;a href="http://docs.codehaus.org/display/GRAILS/Hosting"&gt;this page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I scrolled down the list and nothing really suited me. I have to admit that I stopped reading carefully after a couple of hosting providers. Since this was just my own web-application to play with, I did not want to spent much for hosting every month. I did another search in Google and came to &lt;a href="http://www.k-oo.de/blog/2009/01/21/hosting-von-grails-anwendungen/"&gt;this German blog entry&lt;/a&gt;. The guy basically recommended 3 different hosting providers for Grails applications: &lt;a href="http://s156.eatj.com/plans.jsp"&gt;eatj.com&lt;/a&gt;, &lt;a href="http://javaprovider.net/"&gt;javaprovider.net&lt;/a&gt; and &lt;a href="http://mor.ph/"&gt;mor.ph&lt;/a&gt;. Out of these he liked mor.ph the most. So I decided to try them first.&lt;br /&gt;&lt;br /&gt;Unfortunately I could not find anything related to hosting on their website. I have no idea what they are offering but web-hosting did not jump me off the screen. Next I tried javaprovider.net. This provider has a 30-days trial offer, where you can test your web-application for free basically. Exactly what I wanted. You choose between shared Tomcat or private Tomcat. In the private Tomcat you have 32MB heap memory, in the shared version the heap memory is shared with other applications. I signed up for a shared Tomcat trial account. First of all, the trial account in javaprovider.net is not entirely free anymore. I had to pay $0.50 when signing up. This is to scare idiots off. The account was created immediately. However, they set up a private Tomcat account even though I wanted a shared one. The private account plan would cost me $9.99 every month. Way to much for my little toy website. I selected some stupid sub domain, like &lt;a href="http://tv3.javaprovider.net/"&gt;tv3.javaprovider.net&lt;/a&gt; - it will probably not work anymore when you read this. I entered the MySQL details into the production environment block of my &lt;a href="http://www.grails.org/doc/1.0.x/guide/3.%20Configuration.html"&gt;DataSource.groovy&lt;/a&gt; file.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 9px; line-height: 9px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;dataSource {&lt;br /&gt;    pooled = false                          &lt;br /&gt;    driverClassName = "org.hsqldb.jdbcDriver" &lt;br /&gt;    username = "sa"&lt;br /&gt;    password = ""    &lt;br /&gt;}&lt;br /&gt;environments {&lt;br /&gt;    development {&lt;br /&gt;        dataSource {&lt;br /&gt;            dbCreate = "create-drop" // one of 'create', 'createeate-drop','update'&lt;br /&gt;            url = "jdbc:hsqldb:mem:devDB"&lt;br /&gt;        }&lt;br /&gt;    }   &lt;br /&gt;    test {&lt;br /&gt;        dataSource {&lt;br /&gt;            dbCreate = "update"&lt;br /&gt;            url = "jdbc:hsqldb:mem:testDb"&lt;br /&gt;        }&lt;br /&gt;    }   &lt;br /&gt;    production {&lt;br /&gt;        dataSource {&lt;br /&gt;            pooled = true                          &lt;br /&gt;            driverClassName = "com.mysql.jdbc.Driver"&lt;br /&gt;            dbCreate = "update"&lt;br /&gt;            url = "...." &amp;lt;--- Enter here&lt;br /&gt;            username = "...." &amp;lt;--- Enter here&lt;br /&gt;            password = "...." &amp;lt;--- Enter here&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then I packaged everything again using the &lt;a href="http://forge.octo.com/maven/sites/mtg/grails-maven-plugin/"&gt;Maven 2 Grails plugin&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 9px; line-height: 9px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;mvn package -Dgrails.env=production&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For some reason the WAR file was not build when I ran &lt;strong&gt;mvn grails:package -Dgrails.env=production&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Finally I deployed the WAR file into my javaprovider.net Tomcat. It worked out of the box! However, as I started to click around for a bit it stopped worked. I checked my Tomcat logfiles and saw a nasty OutOfMemoryError. Obviously 32MB heap is way to little, and this was even the better account plan in javaprovider.net. I opened a ticket and asked them about Grails hosting. They got back to me after a day, saying the I needed at least 256MB heap for running a Grails application and it would cost me around $30/month. This is simply not true! Read on.&lt;br /&gt;&lt;br /&gt;While waiting for the ticket reply, I signed up with the last Grails hosting provider that was mentioned in the original blog post - eatj.com. They have a free trial account too, great for testing. The trial account has even 64MB heap. However, their cheapest commercial offer is $9.85/month, so I knew from the start that I would not use them. To make a long story short, I used their MySQL details, repackaged, deployed and it worked fine without any memory issues. Now I knew at least, that 64MB heap would be enough for my Grails app.&lt;br /&gt;&lt;br /&gt;In search for a cheaper alternative to host a Grail web application, I saw an offer from a German hosting provider called Netcup. They are &lt;a href="http://www.netcup.de/bestellen/produkt.php?produkt=88"&gt;offering a vserver&lt;/a&gt; with 100MB of guaranteed memory. The price is very low. You pay one time 10€ which is about $14 and 1,69€ per month ($2.40). Since it is a vserver, you have to install everything yourself, like Java, Tomcat, MySQL etc. When you order the account, they set up a Debian Etch for you, including pre-installed Apache and MySQL. I used this image for a bit but their /etc/apt/sources.list file was pretty limited and I struggled to install Java. I switched to Ubuntu Hardy, which I knew. You can switch between images with a few click in a web console. Their Ubuntu image also had a weird sources.list file but I changed it they way how I had it locally and it worked. I installed Java, MySQL, Tomcat 6 and deployed my Grails webapplication. It worked like a charm.&lt;br /&gt;&lt;br /&gt;You get a static ip-adress, which is enough for now. No domain needed for testing. You can &lt;a href="http://188.40.209.102:8080/"&gt;check it out here&lt;/a&gt;. Log in with (reik/schatz). I am watching tons of TV series like Lost, Heroes, True Blood, 24, Prison Break, Friday Night Lights, Supernatural, Dexter etc. Every time I forgot which episode I saw last, so I wrote this little Grails application where you can save the last episode you have seen.  &lt;br /&gt;&lt;br /&gt;For me the netcup.de vserver is the best option if you want to host a Java based web application using Grails and Groovy. Here is a comparison of the annual prices including one time fees:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;eatj.com&lt;/strong&gt; Basic: $98.50&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;javaprovider.net&lt;/strong&gt; Private: $119.88&lt;/li&gt;&lt;br /&gt;&lt;li&gt;mor.ph ?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;netcup.de&lt;/strong&gt; vserver Aluminium: 30.28€ (&lt;span style="color: blue;"&gt;$42.71&lt;/span&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-4993471936054825444?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/4993471936054825444/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=4993471936054825444' title='6 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4993471936054825444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4993471936054825444'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/07/where-to-host-your-grails-application.html' title='Where to host your Grails application'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-6909641945107354679</id><published>2009-07-15T00:56:00.000-07:00</published><updated>2009-07-15T01:03:46.316-07:00</updated><title type='text'>JSON in Grails with nested collections</title><content type='html'>I have totally fallen in love with Grails and Groovy. I am probably the last Java developer in the world to try out Groovy and Grails but it has never been my top priority. So I started to write a little web application for myself, which I will host later on Google App Engine.&lt;br /&gt;&lt;br /&gt;One common scenario is that you have nested domain classes. In my case, I have a Show class. A Show is basically a TV series like Lost or Deperate Housewives. Each Show has a list of Season's. These seasons are strictly in order, like Lost has Season 1, 2, 3, 4 and 5 so far. Each Season has a number of Episode's, which are also stricly ordered. Then finally each Episode can be aired in different formats like HDTV, 720p or Standard. This makes up a nice class hierarchie having 1:n relations.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;class Show {&lt;br /&gt;&lt;br /&gt;    String name&lt;br /&gt;&lt;br /&gt;    static hasMany = [ seasons : Season ]&lt;br /&gt;&lt;br /&gt;    static mapping  = {&lt;br /&gt;   table  'ct_show'&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;      name(size:1..100,blank:false)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Season {&lt;br /&gt;&lt;br /&gt;    Integer seasonNumber&lt;br /&gt;&lt;br /&gt;    static hasMany = [ episodes : Episode ]&lt;br /&gt;&lt;br /&gt;    static mapping  = {&lt;br /&gt;   table  'ct_season'&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;      seasonNumber(size:1..100,blank:false)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Episode {&lt;br /&gt;&lt;br /&gt;    Integer episodeNumber&lt;br /&gt;&lt;br /&gt;    static hasMany = [ formats : Format ]&lt;br /&gt;&lt;br /&gt;    static mapping  = {&lt;br /&gt;   table  'ct_episode'&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;      episodeNumber(size:1..100,blank:false)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Format {&lt;br /&gt;&lt;br /&gt;    String name&lt;br /&gt;&lt;br /&gt;    static mapping  = {&lt;br /&gt;   table  'ct_format'&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;      name(size:1..100,blank:false)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now I had a typical use case, that when you want to use Ajax within you web application, you want the Controller classes to return you domain objects as JSON. In Grails this is easy to accomplish, just read &lt;a href="http://www.grails.org/AJAX-Driven+SELECTs+in+GSP"&gt;this example&lt;/a&gt;. However, I had the big problem that my domain class hierarchy heavily uses nested collections. This will not work when you just do this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;render Season.get(1) as JSON&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In &lt;a href="http://memo.feedlr.com/?p=6"&gt;this blog post&lt;/a&gt;, the last example offers a solution to my problem but it is a rather static example. The idea is to use my root object (Season in my particular case) to produce a JSON string in the format I want and then return it via render as JSON. Building up this String would be quite a big chunk of code in Java probably involving StringBuilder, but Groovy has this great method .collect for Collections. Here is the Groovy code. Try this in Java.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;        def selectedSeason = Season.get(1)&lt;br /&gt;        def seasonJSON = [&lt;br /&gt;              id: selectedSeason.id,&lt;br /&gt;              seasonNumber: selectedSeason.seasonNumber,&lt;br /&gt;              episodes: selectedSeason.episodes.collect{&lt;br /&gt;                [&lt;br /&gt;                        id: it.id,&lt;br /&gt;                        episodeNumber: it.episodeNumber,&lt;br /&gt;                        formats: it.formats.collect{&lt;br /&gt;                          [&lt;br /&gt;                                  id: it.id ,&lt;br /&gt;                                  name: it.name&lt;br /&gt;                          ]&lt;br /&gt;                        }&lt;br /&gt;                ]&lt;br /&gt;              }&lt;br /&gt;      ]&lt;br /&gt;      &lt;br /&gt;      render seasonJSON as JSON&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-6909641945107354679?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/6909641945107354679/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=6909641945107354679' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6909641945107354679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/6909641945107354679'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/07/json-in-grails-with-nested-collections.html' title='JSON in Grails with nested collections'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-8768100113900503148</id><published>2009-06-12T15:47:00.000-07:00</published><updated>2009-06-12T15:59:13.665-07:00</updated><title type='text'>Struggling with Servlet 3.0</title><content type='html'>A couple of days ago, I wrote a blog post about a session which I had attended during JavaOne. It was a session about the upcoming Servlet 3.0 specification, also known as JSR-315. Back at work, I thought it might be fun to try some of the new features myself. We have this one application running in our production site, which stores events that occur during Poker games. The application uses a Service based on Hessian, which clients can call to store the events. The Hessian service is exposed using the &lt;a href="http://www.caucho.com/resin-javadoc/com/caucho/hessian/server/HessianServlet.html"&gt;HessianServlet&lt;/a&gt; from Caucho, so that it may be invoked from HTTP. The Servlet runs in Jetty 6 container. The application is heavily used and around 20 to 30 calls are made per second.&lt;br /&gt;&lt;br /&gt;My idea was to rewrite some parts within the application, so that everything is based on Servlet 3.0. I have written a test case where I measure the execution time of 30 parallel Threads persisting 30 Poker events. I am hoping that using Servlet 3.0 asynchronous requests, I can see a performance improvement. I know that this is not the perfect use case where asynchronous requests can shine as there is nothing that can be optimized using parallel processing within a single Thread. Anyway, we will see how it goes. I am curious about the results anyway.&lt;br /&gt;&lt;br /&gt;The first step towards Servlet 3.0 is to use a JSR-315 compliant Servlet container. At JavaOne everyone was talking about the upcoming Jetty 7 release and that it supports Servlet 3.0. This was my disappointment. Jetty 7 is &lt;a href="http://it-republik.de/jaxenter/news/Neue-Jetty-Roadmap-Servlet-3.0-erst-in-Jetty-8-049111.html"&gt;not built&lt;/a&gt; on top of Servlet 3.0 but still only Servlet 2.5 compatible. &lt;a href="http://blogs.webtide.com/gregw/entry/jetty_6_jetty_7_and"&gt;The semiofficial reason&lt;/a&gt; is that Jetty has moved from Codehaus to Eclipse and JSR-315 is delayed anyways. My next pick would have been Tomcat 7 as I have seen a comparison matrix that indicated, that the next Tomcat would support Servlet 3.0 as well. Unfortunately I don't think development is that far. I found some source code in SVN but I don't know if it was official and it was also only Servlet 2.5 based. So my last resort was Glassfish v3 which is the reference implementation for Java EE6. The preview release of &lt;a href="https://glassfish.dev.java.net/downloads/v3-preview.html"&gt;Glassfish v3&lt;/a&gt; comes with a Servlet container that implements JSR-315. Perfect.&lt;br /&gt;&lt;br /&gt;It was the first time I installed Glassfish. It was very easy. The application server ships with a web administration interface and is easy to maintain. Currently there are not so many tutorials and examples for Servlet 3.0 on the Web, so I looked forward to check some samples which ship with Glassfish. "After installation, samples are located in install-dir/glassfish/samples/javaee6" - well this directory just does not exist. Not in the  standard preview nor in the web profile. Too bad, they were &lt;a href="https://glassfish-samples.dev.java.net/source/browse/*checkout*/glassfish-samples/ws/javaee6/docs/list.html"&gt;supposed to have&lt;/a&gt; a sample for asynchronous requests as well as adding Servlet's dynamically.&lt;br /&gt;&lt;br /&gt;Anyway, I changed my application from a standalone jar distribution that starts a Jetty 6 container to a war distribution that is deployed in Glassfish v3. To deploy something in Glassfish, just copy it into the autodeploy directory of your domain in the glassfish directory. Since the old version uses the HessianServlet directly, I had to download the source from Caucho and modify it, so that it uses asynchronous requests from Servlet 3.0. Unfortunately the HessianServlet is not really built for extensibility, so I just got a copy of the whole file to play with. To use another Sevlet 3.0 feature, I decided to add the Servlet at runtime using the new ServletContext.addServlet method. I looked up a sample on how to write a ServletContextListener. Some &lt;a href="http://blogs.sun.com/swchan/entry/servlet_3_0_annotations"&gt;old documentation&lt;/a&gt; about JSR-315 indicated that you had to annotate the Listener with the @WebServletContextListener annotation. This annotation does not exist anymore in the &lt;a href="http://blogs.webtide.com/gregw/entry/servlet_3_0_proposed_final"&gt;final draft&lt;/a&gt; of &lt;a href="http://weblogs.java.net/blog/mode/archive/2009/04/servlet_30_pfd.html"&gt;JSR-315&lt;/a&gt;. Instead you do it the oldschool way. Write a class that implements ServletContextListener and add it to the web.xml as a context-listener. Then in the contextInitialized method, I added my AsynchronousHessianServlet.&lt;br /&gt;&lt;br /&gt;In the next posting I will write about asynchronous requests and if this really makes an existing application faster.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Update&lt;/span&gt;: the javaee6 samples will be downloaded and installed using the Glassfish updater tool. In my first install attempt, the updater would not work with my companies firewall, so I never got the samples folder. It works fine if your updater tools works. Would have been nice to mention on the &lt;a href="https://glassfish.dev.java.net/downloads/v3-preview.html"&gt;Glassfish&lt;/a&gt; or &lt;a href="http://java.sun.com/javaee/downloads/preview/index.jsp"&gt;Sun website&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-8768100113900503148?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/8768100113900503148/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=8768100113900503148' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8768100113900503148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8768100113900503148'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/06/struggling-with-servlet-30.html' title='Struggling with Servlet 3.0'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-5664037186977236585</id><published>2009-06-04T22:07:00.000-07:00</published><updated>2009-06-04T22:27:44.621-07:00</updated><title type='text'>Session of the day: Java NIO2 in JDK7</title><content type='html'>Today has been a good day at the JavaOne. I have seen quite a few great and useful talks. For the session of the day I have picked a talk by &lt;a href="http://blogs.sun.com/alanb/"&gt;Alan Bateman&lt;/a&gt; and Carl Quinn from Netflix about the &lt;a href="http://java.sun.com/developer/technicalArticles/javase/nio/"&gt;new IO API&lt;/a&gt; (JSR203) that will be available in JDK7.&lt;br /&gt;&lt;br /&gt;In my own private projects I still use the old Java IO API and I guess that's perfectly fine if your application is not IO critical. At work however, we have multiple projects that make use of java.nio and are very much defendant on a good performance when it comes to files and directories. So what can JSR-203 do for us?&lt;br /&gt;&lt;br /&gt;First of all there will be a class Path which is an abstraction to a physical file or directory resource. Path is basically what File used to be in plain Java IO. To create a Path instance you have a bunch of options. You can call FileSystems.getDefault().getPath("/foo/bar") or just Paths.get("/foo/bar"). One nice thing is that Path will implement &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Iterable.html"&gt;java.lang.Iterable&lt;T&gt;&lt;/a&gt; so that you can iterate over a physical path from root to current directory. If you want to know at which depth you currently are from the root just call Path.getNameCount(). Another nice thing, when you iterate over Path using the legacy Iterator idiom and you invoke iterator.remove, then the physical file gets deleted.&lt;br /&gt;&lt;br /&gt;In the example code above you already saw something called &lt;a href="http://openjdk.java.net/projects/nio/javadoc/java/nio/file/FileSystem.html"&gt;FileSystem&lt;/a&gt;. This is the a of all Paths in NIO2. In JDK7 there will also be something called a Provider which you can leverage to create your own FileSystem. It will be possible to create a memory based FileSystem, a Desktop FS or a &lt;a href="http://hadoop.apache.org/core/"&gt;Hadoop&lt;/a&gt; FileSystem or anything else you can think of. You can even make your FileSystem the default FileSystem so that whenever your application calls FileSystems.getDefault() will return your custom FileSystem.&lt;br /&gt;&lt;br /&gt;Another cool thing is the possibility to traverse a directory tree. NIO2 contains a Interface called &lt;a href="http://openjdk.java.net/projects/nio/javadoc/java/nio/file/FileVisitor.html"&gt;FileVisitor&lt;/a&gt;. The Interface has a bunch of methods like preVisitDirectory, postVisitDirectory, visitFile, visitFileFailed etc. Each of the methods will be invoked at certain stages when traversing a file tree. For convinced JSR-203 ships with a bunch of implementations of FileVisitor like SimpleFileVisitor or InvokeFileVisitor. You can use one of these FileVisitor's and then only overwrite the methods that are interesting for you. To kick off traversal of the file tree you would call Files.walkFileTree(Path path, FileVisitor fileVisitor).&lt;br /&gt;&lt;br /&gt;This becomes really handy when you use it in conjunction with another new class in JDK7 called &lt;a href="http://openjdk.java.net/projects/nio/javadoc/java/nio/file/PathMatcher.html"&gt;PathMatcher&lt;/a&gt;. This is an Interface similar to FileFilter in old Java IO maybe. This is how to create a PathMatcher: FileSystems.getDefault().getPathMatcher("glob:*.log"). In this example it will select all files matching *.log. You can also use regular expressions instead of glob syntax. &lt;br /&gt;&lt;br /&gt;If you look at the method signature of visitFile in the FileVisitor Interface you will notice that the second parameter is of type &lt;a href="http://openjdk.java.net/projects/nio/javadoc/java/nio/file/attribute/BasicFileAttributes.html"&gt;BasicFileAttributes&lt;/a&gt;, which are the attributes of the current file that visitFile is invoked with. So let's say you create your FileVisitor with a PathMather that selects *.log files. What you could do in the visitFile method, is to invoke PathMatcher.match and if it is a log file, check the file size attribute using the given BasicFileAttributes. If the file is bigger than a certain size, delete it. Pretty handy or? A piece of very short Java code that traverses a File tree and deleted logfiles of a certain size.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.{java,class}");&lt;br /&gt;&lt;br /&gt;Path filename = ...;&lt;br /&gt;if (matcher.matches(filename)) {&lt;br /&gt;    System.out.println(filename);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A entirely different use case can be covered with &lt;a href="http://openjdk.java.net/projects/nio/javadoc/java/nio/file/WatchService.html"&gt;WatchService&lt;/a&gt;, &lt;a href="http://openjdk.java.net/projects/nio/javadoc/java/nio/file/Watchable.html"&gt;Watchable&lt;/a&gt;, &lt;a href="http://openjdk.java.net/projects/nio/javadoc/java/nio/file/WatchEvent.html"&gt;WatchEvent&lt;/a&gt; and &lt;a href="http://openjdk.java.net/projects/nio/javadoc/java/nio/file/WatchKey.html"&gt;WatchKey&lt;/a&gt;. These guys make it possible to sit, listen and react to changes that occur to Path objects. First you get yourself a WatchService using the default FileSystem. WatchService watcher = FileSystems.getDefault().newWatchService(). The next step is to get the Path like before Paths.get("/foo/bar/old.log"). Then you register the Path with the WatchService to get a WatchKey: WatchKey key = path.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY). The last parameters in the register method are varargs. In the example you will be watching create, delete and modification events on the specified Path. Finally you need to create an invinite loop that is constantly polling the events out of the WatchKey. Your code can then react to these events.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;for (;;) {&lt;br /&gt;&lt;br /&gt;    //wait for key to be signaled&lt;br /&gt;    WatchKey key;&lt;br /&gt;    try {&lt;br /&gt; key = watcher.take();&lt;br /&gt;    } catch (InterruptedException x) {&lt;br /&gt; return;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    for (WatchEvent&lt;?&gt; event: key.pollEvents()) {&lt;br /&gt; WatchEvent.Kind&lt;?&gt; kind = event.kind();&lt;br /&gt;&lt;br /&gt;        //This key is registered only for ENTRY_CREATE events,&lt;br /&gt;        //but an OVERFLOW event can occur regardless if events are&lt;br /&gt;        //lost or discarded.&lt;br /&gt; if (kind == OVERFLOW) {&lt;br /&gt;     continue;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;        // do your stuff&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    boolean valid = key.reset();&lt;br /&gt;    if (!valid) {&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;One new feature that is particular interesting for our applications is the new DirectoryStream class. You use it to access the contents of a directory. Well you could do this before but DirectoryStream scales much better and uses less resources. This will not be an issue if you have a couple of hunded files in your directory but make a huge difference if there are hundreds of thousand files in the directory. Here is how to use DirectoryStream.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;Path dir = new File("/foo/bar").toPath(); // new method on File in JDK7&lt;br /&gt;DirectoryStream&lt;Path&gt; stream = null;&lt;br /&gt;try {&lt;br /&gt;    stream = dir.newDirectoryStream();&lt;br /&gt;    for (Path file: stream) {&lt;br /&gt;        System.out.println(file.getName());&lt;br /&gt;    }&lt;br /&gt;} catch (IOException x) {&lt;br /&gt;    ....&lt;br /&gt;} finally {&lt;br /&gt;    if (stream != null) stream.close();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Okay this post was maybe a bit too theoretical. You can check out what nio2 feels like with the &lt;a href="http://openjdk.java.net/projects/nio/"&gt;OpenJDK&lt;/a&gt; or this &lt;a href="http://java.sun.com/docs/books/tutorial/essential/io/fileio.html"&gt;great tutorial&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-5664037186977236585?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/5664037186977236585/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=5664037186977236585' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5664037186977236585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/5664037186977236585'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/06/session-of-day-java-nio2-in-jdk7.html' title='Session of the day: Java NIO2 in JDK7'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-3579315075120143108</id><published>2009-06-04T08:43:00.000-07:00</published><updated>2009-06-04T08:53:40.370-07:00</updated><title type='text'>Session of the day: JVM debugging</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_BYGcLbgH8o0/Sifs1TK2neI/AAAAAAAAAB4/dYENkYLQOUg/s1600-h/face_ken_sipe.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_BYGcLbgH8o0/Sifs1TK2neI/AAAAAAAAAB4/dYENkYLQOUg/s320/face_ken_sipe.jpg" alt="" id="BLOGGER_PHOTO_ID_5343499883321400802" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The second day at JavaOne was surprisingly just average. &lt;a href="http://weblogs.java.net/blog/kohsuke/"&gt;Kohsuke&lt;/a&gt; had a great talk about distributed Hudson builds and Hudson EC2 integration but the rest of the sessions was pretty normal. Then I am going into this session “Debugging your production JVM” from &lt;a href="http://kensipe.blogspot.com/"&gt;Ken Sipe&lt;/a&gt; and the guy blasts the roof off. He is showing all these nifty, cool tools that can help to get an insight what is going on in your JVM. Not just one tool but many. I am really having a hard time to write everything down. A lot of command-line tools that already come with Java like jstat, jps or jmap. They are ready to be used, you just need to know how to use them with the right parameters etc.&lt;br /&gt;&lt;br /&gt;Then Ken starts to talk about something really fancy - &lt;a href="https://btrace.dev.java.net/"&gt;BTrace&lt;/a&gt;. So how can BTrace help to debug your production VM. Essentially it is a little tool that you can use at runtime to at debugging “aspects” to your running Java bytecode. I use the word Aspect here because when I first saw it, BTrace felt quite similar to AspectJ. What BTrace does, it takes a little Script that your write in Java and dynamically injects it as tracing code into the running JVM.&lt;br /&gt;&lt;br /&gt;What I called Script here is pure Java code. What you write looks almost exactly like a plain Java Classes with a lot of Annotations. The Code you can write as BTrace Script is really limited however. Ken had a slide in the presentation about all the Java stuff that is not doable. I only remember that you could not use the new keyword to create new objects. Luckily I found the other restrictions on the BTrace website:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;can not create new&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not create new arrays.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not throw exceptions.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not catch exceptions.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not make arbitrary instance or static method calls - only the public static methods of com.sun.btrace.BTraceUtils class may be called from a BTrace program.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not assign to static or instance fields of target program's classes and objects. But, BTrace class can assign to it's own static fields ("trace state" can be mutated).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not have instance fields and methods. Only static public void returning methods are allowed for a BTrace class. And all fields have to be static.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not have outer, inner, nested or local classes.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not have synchronized blocks or synchronized methods.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not have loops (for, while, do..while)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not extend arbitrary class (super class has to be java.lang.Object)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not implement interfaces.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not contains assert statements.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;can not use class literals.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Your hands are tied. Well almost. So let's have a look at a sample from the BTrace website.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;import com.sun.btrace.annotations.*;&lt;br /&gt;import static com.sun.btrace.BTraceUtils.*;&lt;br /&gt;&lt;br /&gt;// @BTrace annotation tells that this is a BTrace program&lt;br /&gt;@BTrace&lt;br /&gt;public class HelloWorld {&lt;br /&gt;&lt;br /&gt;// @OnMethod annotation tells where to probe.&lt;br /&gt;// In this example, we are interested in entry&lt;br /&gt;// into the Thread.start() method.&lt;br /&gt;@OnMethod(&lt;br /&gt;    clazz="java.lang.Thread",&lt;br /&gt;    method="start"&lt;br /&gt;)&lt;br /&gt;public static void func() {&lt;br /&gt;    // println is defined in BTraceUtils&lt;br /&gt;    // you can only call the static methods of BTraceUtils&lt;br /&gt;    println("about to start a thread!");&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can see, it is a standard Java class annotated with @BTrace. Then it says @OnMethod with two parameters which translates to – every time the start method is invoked in java.lang.Thread ... What it will do in that case is invoke the static function it will find within the @BTrace annotated class. It has to be a static method. I forgot if it had to follow a naming convention too. So the static method will be invoked every time a Thread is started. In the sample, it will just print out something fixed on the console. You could also count the number of Threads or other things.&lt;br /&gt;&lt;br /&gt;Here is another example.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;@BTrace public class Memory {&lt;br /&gt;@OnTimer(4000)&lt;br /&gt;public static void printMem() {&lt;br /&gt;    println("Heap:");&lt;br /&gt;    println(heapUsage());&lt;br /&gt;    println("Non-Heap:");&lt;br /&gt;    println(nonHeapUsage());&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will print out memory usage every 4 seconds. Awesome. Now something really huge.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;@BTrace public class HistogramBean {&lt;br /&gt;// @Property exposes this field as MBean attribute&lt;br /&gt;@Property&lt;br /&gt;private static Map&lt;string, atomicinteger=""&gt; histo = newHashMap();&lt;br /&gt;&lt;br /&gt;@OnMethod(&lt;br /&gt;    clazz="javax.swing.JComponent",&lt;br /&gt;    method="&lt;init&gt;"&lt;br /&gt;)&lt;br /&gt;public static void onnewObject(@Self Object obj) {&lt;br /&gt;    ....&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@OnTimer(4000)&lt;br /&gt;public static void print() {&lt;br /&gt;    if (size(histo) != 0) {&lt;br /&gt;        printNumberMap("Component Histogram", histo);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/init&gt;&lt;/string,&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Don't worry about the details what it does right now. The important part is that you can annotate fields with @Property and have BTrace expose these fields as Mbean. All you need to do is inject the BTrace script a little bit different from the command line.&lt;br /&gt;&lt;br /&gt;Some words on the @OnMethod, @OnTimer stuff. These Annotations are called probe points and &lt;a href="https://btrace.dev.java.net/source/browse/btrace/docs/usersguide.html?rev=1.7"&gt;there are more&lt;/a&gt; like @OnMemoryLow, @OnExit, @OnError etc. Another example is to use BTrace to monitor entering and leaving of synchronization blocks.&lt;br /&gt;&lt;br /&gt;Unfortunately BTrace requires Java 6+, it will not work with 5. Now you have a good reason to step up your Java version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-3579315075120143108?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/3579315075120143108/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=3579315075120143108' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3579315075120143108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3579315075120143108'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/06/session-of-day-jvm-debugging.html' title='Session of the day: JVM debugging'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BYGcLbgH8o0/Sifs1TK2neI/AAAAAAAAAB4/dYENkYLQOUg/s72-c/face_ken_sipe.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-8195241705634007306</id><published>2009-06-03T08:14:00.000-07:00</published><updated>2009-06-03T08:36:35.161-07:00</updated><title type='text'>Session of the day: Servlet 3.0</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_BYGcLbgH8o0/SiaYIoKfuhI/AAAAAAAAABo/1V33TnE1UOw/s1600-h/servlet3.0.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_BYGcLbgH8o0/SiaYIoKfuhI/AAAAAAAAABo/1V33TnE1UOw/s320/servlet3.0.jpg" alt="" id="BLOGGER_PHOTO_ID_5343125281909488146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;SVG and Canvas is really cool stuff and “Cross Browser Vector Graphics with SVG and Canvas” came really close to be my session of the day here at JavaOne, but the Servlet 3.0 stuff topped it all. There are so many &lt;a href="http://weblogs.java.net/blog/mode/archive/2008/04/servlet_30_jsr_1.html"&gt;great features&lt;/a&gt; in JSR-315. The &lt;a href="http://blogs.webtide.com/gregw/entry/servlet_3_0_proposed_final"&gt;final draft is now out&lt;/a&gt; and the guys said it will go live with Java EE6.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;web.xml = history&lt;/span&gt;&lt;br /&gt;First of all, the biggest difference is that you do not need a web.xml anymore. Servlet 3.0 fully relies on Java Annotations. If you want to declare a Servlet use the @WebServlet Annotation on your Servlet class. The class still has to inherit from HttpServlet, this remains unchanged. That means it is not possible to use other methods instead of doPost, doGet etc. and annotate them to mark them as Request handler methods. This is something you can do in the Jersey library (JSR-311). In theory I guess it would have been possible to not inherit from HttpServlet but the create a rule that for every class annotated with @WebServlet you have to have methods annotated with @PostMethod or @GetMethod. I guess there are good reasons not to do so in &lt;a href="http://jars.de/java/jsr-315-servlets-30"&gt;Servlet 3.0&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;At the very minimum, you have to annotate specifying a URL under which to invoke your Servlet. If omitted, the full class name will be used as the Servlet name. Other parameters you can specify in the top-level @WebServlet Annotation are for instance if you want the Servlet to be usable in asynchronous requests. More on asynchronous requests later.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;@WebServlet(url = "/foo", asynchronous = true)&lt;br /&gt;public class SomeServlet extends HttpServlet {&lt;br /&gt; public void doGet(...) {&lt;br /&gt;     ....&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_BYGcLbgH8o0/SiaYQF8Y_5I/AAAAAAAAABw/L8RmUf3ZQ8I/s1600-h/talks_servlet.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_BYGcLbgH8o0/SiaYQF8Y_5I/AAAAAAAAABw/L8RmUf3ZQ8I/s320/talks_servlet.jpg" alt="" id="BLOGGER_PHOTO_ID_5343125410162474898" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;So the web.xml is gone. Filters are added to the ServletContext using @WebFilter Annotation, Listeners are added using @WebListener Annotation. The deployment descriptor File web.xml is still useful though. It can be used to overwrite whatever you have specified using Class Annotations. So if you create a web.xml file, whatever you have in there has the final word when the Container starts up the ServletContext.&lt;br /&gt;&lt;br /&gt;Servlets, Listeners and Filters can now also be added programatically. The ServletContext class has new methods like addServlet, addServletMapping, addFilter or addFilterMapping. On Container start up, you can hook in and add Servlets or whatever you want at Runtime.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Web Frameworks can plug in&lt;/span&gt;&lt;br /&gt;Something that I think is really cool, is the possibility for Web Frameworks like Apache Wicket, Tapestry or Spring MVC to plug-in into the ServletContext creation. Remember that in the past, whenever you learned about a new web framework, there was this one section in the documentation where you had to add some Servlet, some Filter or some Listener to the web.xml?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;web-app&amp;gt;&lt;br /&gt; &amp;lt;display-name&amp;gt;Wicket Examples&amp;lt;/display-name&amp;gt;&lt;br /&gt; &amp;lt;filter&amp;gt;&lt;br /&gt;     &amp;lt;filter-name&amp;gt;HelloWorldApplication&amp;lt;/filter-name&amp;gt;&lt;br /&gt;     &amp;lt;filter-class&amp;gt;org.apache.wicket.protocol.http.WicketFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;     &amp;lt;init-param&amp;gt;&lt;br /&gt;       &amp;lt;param-name&amp;gt;applicationClassName&amp;lt;/param-name&amp;gt;&lt;br /&gt;       &amp;lt;param-value&amp;gt;org.apache.wicket.examples.helloworld.HelloWorldApplication&amp;lt;/param-value&amp;gt;&lt;br /&gt;     &amp;lt;/init-param&amp;gt;&lt;br /&gt; &amp;lt;/filter&amp;gt;&lt;br /&gt; &amp;lt;filter-mapping&amp;gt;&lt;br /&gt;     &amp;lt;filter-name&amp;gt;HelloWorldApplication&amp;lt;/filter-name&amp;gt;&lt;br /&gt;     &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt; &amp;lt;/filter-mapping&amp;gt;&lt;br /&gt;&amp;lt;/web-app&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is now history in Servlet 3.0. Web Frameworks can supply something in their JAR-file deployables that is called web-fragment.xml. It is basically a light version of the web.xml and has almost the exact XML structure. What the Container does when it loads up, it will go into all the JAR files in WEB-INF/lib and scan for a web-fragment.xml File in the META-INF directory. If it finds one, the file will be used when creating the final ServletContext. Sometimes you want more control over how fragments are being pulled into the ServletContext creation. There are ways to control the ordering in which web-fragment.xml files are being put together. The library itself can specify a relative ordering in the web-fragment.xml file. For instance it can say, I am not interested in a particular order, load me last. It is also possible to define an absolute ordering in your own web.xml file which will have again the final word. One important thing of notice. Only the WEB-INF/lib directory will be used to scan for web fragments, not the classes directory.&lt;br /&gt;&lt;br /&gt;Third party libraries can also add resources on their own. Whatever the web framework has in META-INF/resources becomes available from the context in which the library is loaded. For instance if you have META-INF/resources/foo.jsp then the resource is available from http://localhost:8080/foo.jsp. Kind of useful too.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;New security, New Error Page&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Security constraints can now also be expressed using Annotations. I forgot the correct Annotation names, I think it was something like @DenyRoles or something that you could put on for instance doPost methods to secure them. I vaguely remember also, that the standard security mechanism to display a Web Form (Form Based Authentication) is removed. What you now do instead is to properly annotate a method which will authenticate the User for you. You are therefore basically free to choose however you want to authenticate your Users. Unfortunately this is a feature in the Servlet Specification that I have almost never used in the last 10 years, so I did not pay too much attention when they talked about this and the security part was also kept short in the session.&lt;br /&gt;&lt;br /&gt;Which brings me to the next improvement, default error pages. Remember back in the old Servlet 2.3+ days that you had to add a default error page for every error code? What a copy and paste mess. JSR-315 gives you the possibility to define default error pages. You can have for instance something like “show this page for all errors except 404”. Very handy.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;New methods in Response&lt;/span&gt;&lt;br /&gt;Remember that it was a pain in the ass to work with HttpResponse sometimes? It was not apparent in which phase the response was, what the status was. &lt;a href="http://today.java.net/pub/a/today/2008/10/14/introduction-to-servlet-3.html"&gt;Servlet 3.0&lt;/a&gt; will add new methods to HttpRepsonse that will make our lives easier. You can get Header name, Headers and the Response status now using API calls.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Asynchronous Requests&lt;/span&gt;&lt;br /&gt;Finally to the most impressive new feature - asynchronous requests. This is huge! Imagine that you have HTTP POST method in a Servlet and what it does is to call out to a WebService. While the Service is doing it's work, the HttpRequest is being held by the Servlet Container. Standard Stuff. This however becomes problematic if your thread pool limit is reached. So lets say you have defined that 50 Threads should be in the Pool. You receive 30 Requests per second. If the web service call takes 2 seconds, you have a problem because 60 Requests are coming in and only 50 Threads are in the pool.&lt;br /&gt;&lt;br /&gt;Here is what Servlet 3.0 does. Well, it is kind of hard to explain and I did not understand it fully. But here is what I think it does. You can specify on Servlet and Filters that they may be used for asynchronous requests. This is something you have to declare as an attribute of the @WebServlet or @WebFilter Annotation. The request comes in, it will look at the Filter chain and the Servlet. It will figure out if it can run asynchronously or not. The original request calls out and the Request is suspended, therefore freeing a Thread and returning it to the pool. A callback method is given along. The callback method is invoked when the external resource becomes available and the Container will use a new Thread to generate the Response. The Request therefore resumes it's work. New methods for resuming and suspending as well as querying the current status of the request have been added. There was also something called asynchronous Handle in the presentation slides but I forgot how it was used.&lt;br /&gt;&lt;br /&gt;Anyway &lt;a href="http://weblogs.java.net/blog/mode/archive/2009/04/servlet_30_pfd.html"&gt;the guy&lt;/a&gt; at JavaOne had an example ready where he had written a Servlet that queried the Ebay Rest Interface for 3 keywords. He then had written the same using asynchronous Requests from Servlet 3.0 and it was like 3 or 4 times faster. This is because not only are the Threads returned to the pool while they are doing nothing (Thread starvation) but also can multiple Requests be run in parallel. This is a major improvement I think. Our current web applications can be made faster just by using features of a new Servlet specification.&lt;br /&gt;&lt;br /&gt;I hope this was useful. I will experiment with Servlet 3.0 before the final release comes out. I think I might be able to do this today already using some experimental version of Jetty or Glassfish.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-8195241705634007306?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/8195241705634007306/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=8195241705634007306' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8195241705634007306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/8195241705634007306'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/06/session-of-day-servlet-30.html' title='Session of the day: Servlet 3.0'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_BYGcLbgH8o0/SiaYIoKfuhI/AAAAAAAAABo/1V33TnE1UOw/s72-c/servlet3.0.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-3622606099977165947</id><published>2009-06-01T23:31:00.000-07:00</published><updated>2009-06-01T23:36:28.948-07:00</updated><title type='text'>Welcome bag</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_BYGcLbgH8o0/SiTIOReIGTI/AAAAAAAAABY/m6GGG9XLbLU/s1600-h/blog_bag.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_BYGcLbgH8o0/SiTIOReIGTI/AAAAAAAAABY/m6GGG9XLbLU/s320/blog_bag.jpg" alt="" id="BLOGGER_PHOTO_ID_5342615205501737266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I made it through the first day of the CommunityOne West. Unfortunately my drive back from Fresno to California took longer than I thought. I was only be able to attend two conference sessions in the afternoon. The first session was about database architectures for web 2.0 applications. Personally I found the talk a bit superficial. Too much high level stuff. I wrote down a few buzzwords like &lt;a href="http://www.danga.com/memcached/"&gt;Memcache&lt;/a&gt;, Multi Statement Requests, Horizontal Partitioning and &lt;a href="https://www.hibernate.org/414.html"&gt;Hibernate Shards&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The second session was an introduction to Amazon EC2 and it was very interesting. F&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_BYGcLbgH8o0/SiTIVcUcAmI/AAAAAAAAABg/TF6DNolCNGk/s1600-h/blog_gel.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 240px; height: 320px;" src="http://4.bp.blogspot.com/_BYGcLbgH8o0/SiTIVcUcAmI/AAAAAAAAABg/TF6DNolCNGk/s320/blog_gel.jpg" alt="" id="BLOGGER_PHOTO_ID_5342615328672973410" border="0" /&gt;&lt;/a&gt;inally I know what Cloud Computing stands for and how it works. I realized, that I was programming in the cloud already, as I had used &lt;a href="http://javasplitter.blogspot.com/2009/05/how-to-google-app-enginefy-your.html"&gt;Google App Engine&lt;/a&gt;. &lt;a href="http://chris-richardson.blog-city.com/"&gt;Chris Richardson&lt;/a&gt;, who did the session, sounded a bit negative every time he mentioned Google App Engine. At least I got these vibes. He did not like that GAE was not fully 100% Java compliant and that database access was limited to Appengine's own datastore. Well, at least it is free I'd say.&lt;br /&gt;&lt;br /&gt;Before I went to the CommunityOne West, I checked in for tomorrows Java One and got my welcome bag. It contained a T-shirt, a jacket, some papers, an Open Solaris CD and something, you would have had a big question mark above your head for - antibacterial hand gel. Pig influenza is just around the corner.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-3622606099977165947?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/3622606099977165947/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=3622606099977165947' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3622606099977165947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/3622606099977165947'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/06/welcome-bag.html' title='Welcome bag'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_BYGcLbgH8o0/SiTIOReIGTI/AAAAAAAAABY/m6GGG9XLbLU/s72-c/blog_bag.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-4608084157648355876</id><published>2009-06-01T19:08:00.000-07:00</published><updated>2009-06-01T19:12:59.365-07:00</updated><title type='text'>Zeitgeist - what you can do as Java developer</title><content type='html'>Since &lt;a href="http://java.sun.com/javaone/"&gt;JavaOne&lt;/a&gt; is in San Francisco, I used the chance that I am in the Bay Area and visited a friend, that I had not seen a few years, in Fresno. We ended up hacking around and watching documentaries on DVD. One particular documentary that made quite an impression on me was Zeitgeist Addendum. You can watch it here on the blog but beware it has full-movie length.&lt;br /&gt;&lt;br /&gt;&lt;embed id="VideoPlayback" src="http://video.google.com/googleplayer.swf?docid=7065205277695921912&amp;hl=en&amp;fs=true" style="width:400px;height:326px" allowFullScreen="true" allowScriptAccess="always" type="application/x-shockwave-flash"&gt; &lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;In Zeitgeist Addendum the author evaluates how things tick today by looking at our system and the society. He starts by looking at the global financial system and how it is doomed to fail sooner or later. In the second part, someone talks about how small countries are controlled and corrupted by organizations in the worlds leading countries. It becomes apparent that this system will never change by itself. The last two parts, which I found most interesting, talk about alternatives to our current society structures. There is the Venus Project as a different society experiment. It is shown how different things are handled in the Venus Project than they are in our current society. &lt;br /&gt;&lt;br /&gt;One of the biggest problems today is that we live in a profit orientated society. You need money to survive. Companies need to make more money every year. A lot of bad things we see in our world today are directly connected to the profit orientated society. The destroying of our worlds environment.  The wars that countries fight against each other. In Zeitgeist Addendum it is proposed that the profit based system must be weakened for mankind to move on. Today, environmental friendly technology is held back or killed by competition just to make more profit. The solution to a lot of problems are not politicians but technology. How can I help?&lt;br /&gt;&lt;br /&gt;This is where I think even as a, maybe unimportant, Java developer you can help. Because this is what we create – technology. Start being a better developer. Educate yourself. Read a book at least once in three months. This will give you new ideas, this will motivate you, this will maybe help you to be more efficient, to create more in a shorter time. Help other developers around you. Do not think about why you should help or teach them. Do not be jealous to what they have and you don't. Do not be angry why they get away being inefficient every day. Give them something back instead, from what you have learned and therefore help others to become better and more efficient too.&lt;br /&gt;&lt;br /&gt;Automate things you are doing repeatedly and slow you down. If you spent 3 hours every week, looking at various log files, investigating why something did not work as expected - create something that will make it easier and more efficient for you. First of all, you will learn something while you do it. Secondly, if you only need 30 minutes instead of 3 hours, you have gained 2 ½ hours in which you can work on something more challenging - maybe the next &lt;a href="http://labs.google.com/papers/mapreduce.html"&gt;MapReduce algorithm&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Support the community. Participate in writing open source software. Give answers to other peoples questions. Write a blog. Publish the super-cool code snippet you have written, so that others save time. How can this help to weaken the profit based, monetary system? Well, maybe your answer to some question, your code, your open-source plugin will be used by someone else to create better technology. Technology that will makes it possible to travel faster using renewable energies, so that we don't need airplanes anymore. Or you indirectly help to create software that examines data intensive DNA patterns and cancer can be cured.&lt;br /&gt;&lt;br /&gt;Start using Linux. Almost everything that you do on a Windows powered machine, you can do using free software and Linux too. By using Linux and showing others (developers, family) how easy it is to use, or that it even exists, you help weakening the influence of Microsoft. I do not say Windows is bad, it is really great even. It just costs too much and Microsoft has for a long time leveraged the fact that there was no alternative. Unfortunatly an OS is something every computer needs. You cannot sell it for a couple of hunded bucks. Come on. Support the idea of free software. Imagine a world in which software is free and everyone has access to it. So many people that could help creating new, helpful technology.&lt;br /&gt;&lt;br /&gt;Support companies creating modern technology like Google. Even though Google is a profit orientated company, they have in the last years given so much great stuff out for free. Take Google App Engine. Isn't it great to have a place that does not cost you anything, where you can put your own Python slash Java applications and share it with others? Take the MapReduce paradigm I mentioned earlier. Google has shared it with others. It can now be leveraged by till example Health Researchers for data mining. There is a backside of the coin though. Google is dominating search. The world of search is paralyzed. People are searching for contents like they did in 1999. There cannot be new development in search if everyone uses Google. Think about alternatives, even though it hurts, I know :)&lt;br /&gt;&lt;br /&gt;You work in IT. You are making probably more money than the average salesman in your town. Think about switching to energy providers offering energy from renewable sources. This will likely costs more. It can even be that the energy is not from a renewable source at all (some people call that cheating by the way). But it will create awareness if people start paying extra for nice energy. As more and more people will hop on, companies will fully shift renewable energy. They will invest into renewable energy and it will become cheaper. Start to turn off computers when you are not using them. I had mine always running during the night. Probably because I was lazy to turn them off or I wanted to save time turning them on again next day. Save yourself some money and some non-renewable energy. &lt;br /&gt;&lt;br /&gt;Alright now it seems to be getting too far off. Just watch Zeitgeist Addendum and think about it. I am off for JavaOne now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-4608084157648355876?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/4608084157648355876/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=4608084157648355876' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4608084157648355876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/4608084157648355876'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/06/zeitgeist-what-you-can-do-as-java.html' title='Zeitgeist - what you can do as Java developer'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-2160832155655527337</id><published>2009-05-30T07:15:00.000-07:00</published><updated>2009-05-30T07:19:11.772-07:00</updated><title type='text'>Spending time before Java One in San Francisco</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_BYGcLbgH8o0/SiFAWRq5WZI/AAAAAAAAABQ/W33HtvR-FKg/s1600-h/java_one_aussicht_hotel.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 240px; height: 320px;" src="http://2.bp.blogspot.com/_BYGcLbgH8o0/SiFAWRq5WZI/AAAAAAAAABQ/W33HtvR-FKg/s320/java_one_aussicht_hotel.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5341621384482740626" /&gt;&lt;/a&gt;&lt;br /&gt;I finally made it to San Francisco. My company sent me and ten colleagues to the Java One conference this year. This is supposed to be the biggest Java related conference in the world. We will see about that. It starts next Tuesday. In the meantime, I have some extra days I can spent in San Francisco. The plan is to travel to Fresno today and meet a friend which I have not seen for a couple of years.&lt;br /&gt;&lt;br /&gt;Even before the Java One starts are there a lot of conferences about agile software development, Java based technologies or vendor specific stuff. Some of them are even for free. There is the CommunityOne West that starts next Monday. It is a side conference, also hosted by Sun. The Community One West goes from 1st to 3rd of June, also in Moscone Center. Since it is starting one day before the real JavaOne conference, it will be a great opportunity for me to get my head filled up with Java stuff even earlier. This is the &lt;a href="https://www28.cplan.com/cc239/sessions_catalog.jsp?ilc=230-1&amp;ilg=english&amp;isort=&amp;isort_type=&amp;is=yes&amp;icriteria1=+&amp;icriteria2=+&amp;icriteria4=+&amp;icriteria9=&amp;icriteria8=&amp;icriteria3=&amp;icriteria7=+"&gt;CommunityOne program&lt;/a&gt; for Monday. There are a lot of sessions about Open Solaris and Cloud Computing. Since I will unfortunately only be coming back from Fresno on Monday, I will miss the morning and lunch sessions of the Community One West. However, there are some “pearls” I found during the afternoon like “&lt;a href="https://www28.cplan.com/cc239/session_details.jsp?isid=307163&amp;ilocation_id=230-1&amp;ilanguage=english"&gt;Dynamic Data in a Web 2.0 World&lt;/a&gt;”, “&lt;a href="https://www28.cplan.com/cc239/session_details.jsp?isid=311624&amp;ilocation_id=230-1&amp;ilanguage=english"&gt;Three Techniques for Database Scalability with Hibernate&lt;/a&gt;” or “&lt;a href="https://www28.cplan.com/cc239/session_details.jsp?isid=307130&amp;ilocation_id=230-1&amp;ilanguage=english"&gt;What Do You Need to Know About Creating and Running a Scalable Web Site but Were Afraid to Ask?&lt;/a&gt;” Looking forward to go there.&lt;br /&gt;&lt;br /&gt;Anyway, I want to quit this post with some practical tips for you guys entering the US. One of my colleagues was really hit hard this time from the US border control. I am not sure that is the correct name but they are the guys who will check your filled in papers from the plane and ask all these questions. Obviously they had found something in his profile or he just looked similar to someone they were looking for. He was asked to not proceed to the Exit but to another office called “Secondary”. In there, they asked a lot of detailed questions and this time even with a quite obvious background. Something like “Do you have family or friends in Saudi Arabia, Iran or somewhere else in the middle east?” I guess he was tempted to answer that our former System Owner migrated from Iran to Sweden some 20 years ago :) &lt;br /&gt;&lt;br /&gt;Then the staff was really going into detail with questions about Java One, like what type of conference it is. How many years he had worked in our company. What his position is in the company. What exactly he was doing etc. Finally, he cleared secondary. Now everyone, even the Exit people, are in an area between the border security and the customs. This is where you pick up your luggage. I headed directly to the bathroom to get my hands washed. It is really smart, in times where US has the most Swine Influenza cases, to have everyone press their four finger and thumb of both hands on a fingerprint scanner! &lt;br /&gt;&lt;br /&gt;Waiting for the luggage, some guys with beagle dogs went around, checking bags. These dogs are really great. They found a lot of food in peoples bags. It was fun to watch - snap, dog caught ya. After a couple of minutes, we got the bags and moved out. Guess what, my colleague was picked on again and he had to go someplace else. They asked him, if he wanted to change something in his customs declaration paper. Obviously that was not the case and they started searching his belongings. Of course they did not find anything.&lt;br /&gt;&lt;br /&gt;Other stuff. Take it easy when leaving the plane. Border control usually starts off with only a few counters, so it looks like you have to wait forever. They will then open more and more counters. The passengers who were among the first, waited longest. It is better to come late I'd say. Make sure you have both sides on all forms filled in. Be prepared to answer detailed questions about the purpose of your trip and details about the place you are staying. Do not travel to the US if you do not speak English please. I had a Spanish lady in my queue, filling in a German &lt;a href="http://www.cbp.gov/xp/cgov/travel/id_visa/i-94_instructions/filling_out_i94.xml"&gt;I-94 form&lt;/a&gt;, who could not talk Any! English. It was a disaster. She did not even know what to fill in in which fields, not to talk about the questions they asked her. I know it is ignorant but thats the way it is, you have to be at least OK in English.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1493353025088627001-2160832155655527337?l=javasplitter.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javasplitter.blogspot.com/feeds/2160832155655527337/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1493353025088627001&amp;postID=2160832155655527337' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2160832155655527337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1493353025088627001/posts/default/2160832155655527337'/><link rel='alternate' type='text/html' href='http://javasplitter.blogspot.com/2009/05/spending-time-before-java-one-in-san.html' title='Spending time before Java One in San Francisco'/><author><name>Reikje</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_BYGcLbgH8o0/SiFAWRq5WZI/AAAAAAAAABQ/W33HtvR-FKg/s72-c/java_one_aussicht_hotel.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1493353025088627001.post-3770486665653124164</id><published>2009-05-25T04:06:00.000-07:00</published><updated>2009-05-25T04:53:18.816-07:00</updated><title type='text'>How to Google App Enginefy your existing Java application and fail</title><content type='html'>Last month Google added Java support to the &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt;. This means, that you can from now on host Java based applications on the Google infrastructure. Even better is the fact, that you can do it for free. Well, it is free for starters. There are quotas like 5 million page views per day, 6,5 hours CPU time per day, 1GB traffic per day etc.  For the everyday "lets-do-something in Java" app, this is more than enough, so I decided to run a simple &lt;a href="http://wicket.apache.org/"&gt;Wicket&lt;/a&gt; web-application on Googles appengine.&lt;br /&gt;&lt;br /&gt;I am still a part-time student at &lt;a href="http://www.fernuni-hagen.de/"&gt;Fernuni Hagen&lt;/a&gt; in Germany and in the current semester I am in a course called “&lt;a href="http://www.isdb.fernuni-hagen.de/index.php/de/lehre/lehrangebot/96-1905-computerunterstuetzes-beilaeufiges-lernen-ws-0809.html"&gt;Web 2.0 and social software&lt;/a&gt;”. The course is organized so that 3 students have to pick a topic from the web 2.0 bubble and prepare a presentation about it. &lt;a href="http://javasplitter.blogspot.com/2009/05/collective-intelligence-in-action.html"&gt;Recently&lt;/a&gt; I have read the book “Collective Intelligence in Action” so I thought I might as well talk about Tag, Tagging and TagClouds. It is always better to not just talk in your presentations but show some real action. Therefore I created a little web-application, based on Satnam Alag's domain model from the book and powered with Apache Wicket and Spring to be fully functional. &lt;br /&gt;&lt;br /&gt;The non Google App Enginefied version uses an in-memory HSQL database to persist Tags, Users and Items. This means, if you restart the application, everything will be gone. Everything is visualized using a TagCloud embedded in a Apache Wicket WebPage. The page will also contain entry forms to add new Users, Items and Tags. So here is the domain model which consists of five classes. The Entity class is an abstract base class for Item, Tag, TaggedItem and User.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;public abstract class Entity implements Serializable&lt;br /&gt;{&lt;br /&gt;    private static final long serialVersionUID = 1L;&lt;br /&gt;&lt;br /&gt;    public int id;&lt;br /&gt;&lt;br /&gt;    public String name;&lt;br /&gt;&lt;br /&gt;    public int getId()&lt;br /&gt;    {&lt;br /&gt;        return id;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setId(int id)&lt;br /&gt;    {&lt;br /&gt;        this.id = id;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getName()&lt;br /&gt;    {&lt;br /&gt;        return name;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setName(String name)&lt;br /&gt;    {&lt;br /&gt;        this.name = name;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public boolean equals(Object o)&lt;br /&gt;    {&lt;br /&gt;        if (this == o) return true;&lt;br /&gt;        if (o == null || getClass() != o.getClass()) return false;&lt;br /&gt;&lt;br /&gt;        Entity entity = (Entity) o;&lt;br /&gt;&lt;br /&gt;        if (id != entity.id) return false;&lt;br /&gt;&lt;br /&gt;        return true;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public int hashCode()&lt;br /&gt;    {&lt;br /&gt;        return new Integer(id).hashCode();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class User extends Entity&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Tag extends Entity&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Item extends Entity&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class TaggedItem extends Entity&lt;br /&gt;{&lt;br /&gt;    private int _userId;&lt;br /&gt;&lt;br /&gt;    private int _itemId;&lt;br /&gt;&lt;br /&gt;    private int _tagId;&lt;br /&gt;&lt;br /&gt;    private int _weight;&lt;br /&gt;&lt;br /&gt;    public int getUserId()&lt;br /&gt;    {&lt;br /&gt;        return _userId;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setUserId(final int userId)&lt;br /&gt;    {&lt;br /&gt;        _userId = userId;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getItemId()&lt;br /&gt;    {&lt;br /&gt;        return _itemId;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setItemId(final int itemId)&lt;br /&gt;    {&lt;br /&gt;        _itemId = itemId;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getTagId()&lt;br /&gt;    {&lt;br /&gt;        return _tagId;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setTagId(final int tagId)&lt;br /&gt;    {&lt;br /&gt;        _tagId = tagId;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getWeight()&lt;br /&gt;    {&lt;br /&gt;        return _weight;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setWeight(final int weight)&lt;br /&gt;    {&lt;br /&gt;        _weight = weight;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The CRUD operations for this domain model are implemented using the DAO pattern (surprise, surprise). On top of the hierarchy sits the GenericDao interface which contains methods for read, write, delete. Then I have created interfaces for each individual DAO class that is connected to one entity in the domain model, ie. UserDao or ItemDao. These individual DAO interfaces extend the GenericDao, specifying the Entity to persist and the primary key type. The concrete implementation is now done in classes like UserJdbcDao or ItemJdbcDao. These are implementing the appropriate interface and extend a helper class called AbstractJdbcDao, which contains a reference to the Spring SimpleJdbcTemplate. Here is an example of the class structure for the User class.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;public interface GenericDao&amp;lt;T, PK extends Serializable&amp;gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Persist the newInstance object into database&lt;br /&gt;     */&lt;br /&gt;    PK create(T newInstance);&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Retrieve an object that was previously persisted to the database using&lt;br /&gt;     * the indicated id as primary key&lt;br /&gt;     */&lt;br /&gt;    T read(PK id);&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Retrieves all objects that were previously persisted to the database.&lt;br /&gt;     */&lt;br /&gt;    List&amp;lt;T&amp;gt; readAll();&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Save changes made to a persistent object.&lt;br /&gt;     */&lt;br /&gt;    void update(T transientObject);&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Remove an object from persistent storage in the database&lt;br /&gt;     */&lt;br /&gt;    void delete(T persistentObject);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public interface UserDao extends GenericDao&amp;lt;User, Long&amp;gt;&lt;br /&gt;{&lt;br /&gt;    /**&lt;br /&gt;     * Returns the {@link User} whose name matches the given String.&lt;br /&gt;     * @param name a users name&lt;br /&gt;     * @return User or &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt;&lt;br /&gt;     */&lt;br /&gt;    User readByName(final String name);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public abstract class AbstractJdbcDao&amp;lt;T extends Entity&amp;gt;&lt;br /&gt;{&lt;br /&gt;    private SimpleJdbcTemplate m_simpleJdbcTemplate;&lt;br /&gt;    private String m_identityQuery;&lt;br /&gt;&lt;br /&gt;    protected SimpleJdbcTemplate getSimpleJdbcTemplate()&lt;br /&gt;    {&lt;br /&gt;        return m_simpleJdbcTemplate;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDataSource(DataSource dataSource)&lt;br /&gt;    {&lt;br /&gt;        m_simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getIdentityQuery()&lt;br /&gt;    {&lt;br /&gt;        return m_identityQuery;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setIdentityQuery(final String identityQuery)&lt;br /&gt;    {&lt;br /&gt;        m_identityQuery = identityQuery;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    abstract ParameterizedRowMapper&amp;lt;T&amp;gt; getMapper();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class UserJdbcDao extends AbstractJdbcDao&amp;lt;User&amp;gt; implements UserDao&lt;br /&gt;{&lt;br /&gt;    private static final ParameterizedRowMapper&amp;lt;User&amp;gt; MAPPER = new ParameterizedRowMapper&amp;lt;User&amp;gt;()&lt;br /&gt;    {&lt;br /&gt;        public User mapRow(ResultSet rs, int rowNum) throws SQLException&lt;br /&gt;        {&lt;br /&gt;            final User user = new User();&lt;br /&gt;            user.setId(rs.getLong("user_id"));&lt;br /&gt;            user.setName(rs.getString("user_name"));&lt;br /&gt;            return user;&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    public Long create(User newInstance)&lt;br /&gt;    {&lt;br /&gt;        final SimpleJdbcTemplate template = getSimpleJdbcTemplate();&lt;br /&gt;        template.update("INSERT INTO user(user_name) VALUES(?)", newInstance.getName());&lt;br /&gt;        return template.queryForLong(getIdentityQuery());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public User read(Long id)&lt;br /&gt;    {&lt;br /&gt;        final SimpleJdbcTemplate template = getSimpleJdbcTemplate();&lt;br /&gt;        final List&amp;lt;User&amp;gt; users = template.query("SELECT * FROM user WHERE user_id = ?", getMapper(), id);&lt;br /&gt;        return users.isEmpty() ? null : users.get(0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public User readByName(final String name)&lt;br /&gt;    {&lt;br /&gt;        final SimpleJdbcTemplate template = getSimpleJdbcTemplate();&lt;br /&gt;        final List&amp;lt;User&amp;gt; users = template.query("SELECT * FROM user WHERE user_name = ?", getMapper(), name);&lt;br /&gt;        return users.isEmpty() ? null : users.get(0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public List&amp;lt;User&amp;gt; readAll()&lt;br /&gt;    {&lt;br /&gt;        final SimpleJdbcTemplate template = getSimpleJdbcTemplate();&lt;br /&gt;        return template.query("SELECT * FROM user", getMapper());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void update(User transientObject)&lt;br /&gt;    {&lt;br /&gt;        throw new UnsupportedOperationException("Not implemented yet.");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void delete(User persistentObject)&lt;br /&gt;    {&lt;br /&gt;        final SimpleJdbcTemplate template = getSimpleJdbcTemplate();&lt;br /&gt;        template.update("DELETE FROM user WHERE user_id = ?", persistentObject.getId());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    ParameterizedRowMapper&amp;lt;User&amp;gt; getMapper()&lt;br /&gt;    {&lt;br /&gt;        return MAPPER;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Everything is wired together using Spring beans. This is where I define, that I want to use an in-memory database. All standard Spring stuff so far, no magic involved.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans&lt;br /&gt;        xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;        xmlns:aop="http://www.springframework.org/schema/aop"&lt;br /&gt;        xmlns:tx="http://www.springframework.org/schema/tx"&lt;br /&gt;        xsi:schemaLocation="&lt;br /&gt;   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&lt;br /&gt;   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd&lt;br /&gt;   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;!-- HSQL DS --&amp;gt;&lt;br /&gt;    &amp;lt;bean id="dataSource" class="org.springbyexample.jdbc.datasource.InitializingBasicDataSource" destroy-method="close"&amp;gt;&lt;br /&gt;        &amp;lt;property name="driverClassName" value="org.hsqldb.jdbcDriver"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="url" value="jdbc:hsqldb:mem:."/&amp;gt;&lt;br /&gt;        &amp;lt;property name="username" value="sa"/&amp;gt;&lt;br /&gt;        &amp;lt;property name="password" value=""/&amp;gt;&lt;br /&gt;        &amp;lt;property name="sqlScriptProcessor"&amp;gt;&lt;br /&gt;            &amp;lt;bean class="org.springbyexample.jdbc.core.SqlScriptProcessor"&amp;gt;&lt;br /&gt;                &amp;lt;property name="sqlScripts"&amp;gt;&lt;br /&gt;                    &amp;lt;list&amp;gt;&lt;br /&gt;                        &amp;lt;value&amp;gt;classpath:/db-create.sql&amp;lt;/value&amp;gt;&lt;br /&gt;                    &amp;lt;/list&amp;gt;&lt;br /&gt;                &amp;lt;/property&amp;gt;&lt;br /&gt;            &amp;lt;/bean&amp;gt;&lt;br /&gt;        &amp;lt;/property&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;!-- DAO base --&amp;gt;&lt;br /&gt;    &amp;lt;bean id="daoWithDataSource" abstract="true"&amp;gt;&lt;br /&gt;        &amp;lt;property name="dataSource" ref="dataSource" /&amp;gt;&lt;br /&gt;        &amp;lt;property name="identityQuery" value="CALL IDENTITY();" /&amp;gt; &amp;lt;!-- HSQL specific --&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;!-- JDBC DAO's --&amp;gt;&lt;br /&gt;    &amp;lt;bean id="userDao" class="com.fernuni.db.jdbc.UserJdbcDao" parent="daoWithDataSource" /&amp;gt;&lt;br /&gt;    &amp;lt;bean id="itemDao" class="com.fernuni.db.jdbc.ItemJdbcDao" parent="daoWithDataSource" /&amp;gt;&lt;br /&gt;    &amp;lt;bean id="tagDao" class="com.fernuni.db.jdbc.TagJdbcDao" parent="daoWithDataSource" /&amp;gt;&lt;br /&gt;    &amp;lt;bean id="taggedItemDao" class="com.fernuni.db.jdbc.TaggedItemJdbcDao" parent="daoWithDataSource" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Also note that I used some special DataSource which will always execute a database initializer script. To use this &lt;a href="http://www.springbyexample.org/maven/site/spring-by-example-jdbc/1.0.1/apidocs/org/springbyexample/jdbc/datasource/InitializingBasicDataSource.html"&gt;InitializingBasicDataSource&lt;/a&gt;, you have to reference the SpringByExample library. In Maven powered projects you would add this to your POM:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;repositories&amp;gt;&lt;br /&gt;        &amp;lt;repository&amp;gt;&lt;br /&gt;            &amp;lt;id&amp;gt;springbyexample.org&amp;lt;/id&amp;gt;&lt;br /&gt;            &amp;lt;name&amp;gt;Spring by Example&amp;lt;/name&amp;gt;&lt;br /&gt;            &amp;lt;url&amp;gt;http://www.springbyexample.org/maven/repo&amp;lt;/url&amp;gt;&lt;br /&gt;        &amp;lt;/repository&amp;gt;&lt;br /&gt;    &amp;lt;/repositories&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.springbyexample&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;spring-by-example-jdbc&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;1.0.3&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally I have created a single page using Apache Wicket which will visualize the TagCloud and also contain form fields to create and delete Users, Items and Tags. The page class is called HomePage and contains references to all DAO beans. Later on, it will replace the DAO beans with the ones I have to use in a Google App Engine environment. Here is my HomePage. I have removed a lot of code for better readability as the class is complex. Get the source code to have a look at the full implementation.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;public class HomePage extends WebPage&lt;br /&gt;{&lt;br /&gt;    private static final long serialVersionUID = 1L;&lt;br /&gt;&lt;br /&gt;    private String m_newUserName = "";&lt;br /&gt;    private String m_newItemName = "";&lt;br /&gt;&lt;br /&gt;    private String m_newTagName = "";&lt;br /&gt;    private User m_taggingUser = new User();&lt;br /&gt;    private Item m_taggedItem = new Item();&lt;br /&gt;&lt;br /&gt;    @SpringBean&lt;br /&gt;    private UserDao m_userDao;&lt;br /&gt;&lt;br /&gt;    @SpringBean&lt;br /&gt;    private ItemDao m_itemDao;&lt;br /&gt;&lt;br /&gt;    @SpringBean&lt;br /&gt;    private TagDao m_tagDao;&lt;br /&gt;&lt;br /&gt;    @SpringBean&lt;br /&gt;    private TaggedItemDao m_taggedItemDao;&lt;br /&gt;&lt;br /&gt;    public HomePage(final PageParameters parameters)&lt;br /&gt;    {&lt;br /&gt;        addUserFields();&lt;br /&gt;        addItemFields();&lt;br /&gt;        addTagFields();&lt;br /&gt;&lt;br /&gt;        displayTagCloud();&lt;br /&gt;&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void displayTagCloud()&lt;br /&gt;    {&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    private void addTagFields()&lt;br /&gt;    {&lt;br /&gt;        final Form tagForm = new Form("newTags");&lt;br /&gt;&lt;br /&gt;        final RequiredTextField newTagName = new RequiredTextField("newTagName", new PropertyModel(this, "newTagName"));&lt;br /&gt;        tagForm.add(newTagName);&lt;br /&gt;&lt;br /&gt;        final IModel userChoices = new LoadableDetachableModel()&lt;br /&gt;        {&lt;br /&gt;            protected Object load()&lt;br /&gt;            {&lt;br /&gt;                return m_userDao.readAll();&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        final IChoiceRenderer userChoiceRenderer = new IChoiceRenderer()&lt;br /&gt;        {&lt;br /&gt;            public Object getDisplayValue(Object object)&lt;br /&gt;            {&lt;br /&gt;                final User user = (User) object;&lt;br /&gt;                return user.getName();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public String getIdValue(Object object, int index)&lt;br /&gt;            {&lt;br /&gt;                final User user = (User) object;&lt;br /&gt;                return user.getId() + "";&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        final ListChoice userListChoices = new ListChoice("taggingUser", new PropertyModel(this, "taggingUser"), userChoices, userChoiceRenderer);&lt;br /&gt;        userListChoices.setRequired(true);&lt;br /&gt;        tagForm.add(userListChoices);&lt;br /&gt;&lt;br /&gt;        final IModel itemChoices = new LoadableDetachableModel()&lt;br /&gt;        {&lt;br /&gt;            protected Object load()&lt;br /&gt;            {&lt;br /&gt;                return m_itemDao.readAll();&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        final IChoiceRenderer itemChoiceRenderer = new IChoiceRenderer()&lt;br /&gt;        {&lt;br /&gt;            public Object getDisplayValue(Object object)&lt;br /&gt;            {&lt;br /&gt;                final Item item = (Item) object;&lt;br /&gt;                return item.getName();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public String getIdValue(Object object, int index)&lt;br /&gt;            {&lt;br /&gt;                final Item item = (Item) object;&lt;br /&gt;                return item.getId() + "";&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        final ListChoice itemListChoices = new ListChoice("taggedItem", new PropertyModel(this, "taggedItem"), itemChoices, itemChoiceRenderer);&lt;br /&gt;        itemListChoices.setRequired(true);&lt;br /&gt;        tagForm.add(itemListChoices);&lt;br /&gt;&lt;br /&gt;        final Button saveNewTagButton = new Button("saveNewTagButton")&lt;br /&gt;        {&lt;br /&gt;         @Override&lt;br /&gt;         public void onSubmit()&lt;br /&gt;         {&lt;br /&gt;                super.onSubmit();&lt;br /&gt;&lt;br /&gt;                Tag existingTag = m_tagDao.readByText(m_newTagName);&lt;br /&gt;                if (existingTag == null)&lt;br /&gt;                {&lt;br /&gt;                    final Tag newTag = new Tag();&lt;br /&gt;                    newTag.setName(m_newTagName);&lt;br /&gt;                    m_tagDao.create(newTag);&lt;br /&gt;&lt;br /&gt;                    existingTag = m_tagDao.readByText(m_newTagName);&lt;br /&gt;                    assert existingTag != null;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                final Long taggingUserId = m_taggingUser.getId();&lt;br /&gt;                final Long taggedItemId = m_taggedItem.getId();&lt;br /&gt;&lt;br /&gt;                final TaggedItem taggedItem = new TaggedItem();&lt;br /&gt;                taggedItem.setItemId(taggedItemId);&lt;br /&gt;                taggedItem.setUserId(taggingUserId);&lt;br /&gt;                taggedItem.setTagId(existingTag.getId());&lt;br /&gt;&lt;br /&gt;                m_taggedItemDao.create(taggedItem);&lt;br /&gt;         }&lt;br /&gt;        };&lt;br /&gt;        tagForm.add(saveNewTagButton);&lt;br /&gt;&lt;br /&gt;        add(tagForm);&lt;br /&gt;&lt;br /&gt;        // Existing Tags&lt;br /&gt;        final Form existingTagsForm = new Form("existingTagsForm");&lt;br /&gt;&lt;br /&gt;        final IModel taggedItemsModel = new LoadableDetachableModel()&lt;br /&gt;        {&lt;br /&gt;            protected Object load()&lt;br /&gt;            {&lt;br /&gt;                return m_taggedItemDao.readAll();&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        final ListView existingTaggedItems = new ListView("existingTaggedItems", taggedItemsModel)&lt;br /&gt;        {&lt;br /&gt;            protected void populateItem(ListItem item)&lt;br /&gt;            {&lt;br /&gt;                final TaggedItem taggedItem = (TaggedItem) item.getModelObject();&lt;br /&gt;&lt;br /&gt;                final User taggingUser = m_userDao.read(taggedItem.getUserId());&lt;br /&gt;                final Item itemContainingTag = m_itemDao.read(taggedItem.getItemId());&lt;br /&gt;                final Tag tag = m_tagDao.read(taggedItem.getTagId());&lt;br /&gt;&lt;br /&gt;                final Label taggedText = new Label("taggedText", new PropertyModel(tag, "name"));&lt;br /&gt;                item.add(taggedText);&lt;br /&gt;                final Label taggedBy = new Label("taggedBy", new PropertyModel(taggingUser, "name"));&lt;br /&gt;                item.add(taggedBy);&lt;br /&gt;                final Label taggedAt = new Label("taggedAt", new PropertyModel(itemContainingTag, "name"));&lt;br /&gt;                item.add(taggedAt);&lt;br /&gt;&lt;br /&gt;                final Button deleteTaggedItem = new Button("deleteTaggedItem")&lt;br /&gt;                {&lt;br /&gt;                    @Override&lt;br /&gt;                    public void onSubmit()&lt;br /&gt;                    {&lt;br /&gt;                        super.onSubmit();&lt;br /&gt;&lt;br /&gt;                        m_taggedItemDao.delete(taggedItem);&lt;br /&gt;                    }&lt;br /&gt;                };&lt;br /&gt;                item.add(deleteTaggedItem);&lt;br /&gt;&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;        existingTagsForm.add(existingTaggedItems);&lt;br /&gt;&lt;br /&gt;        add(existingTagsForm);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So far so good. Lets now Google App Enginefy this application. First of all, since this application uses Apache Wicket, you have to change some settings regarding Threads. Google Appengine does not support Threads today. Step 1: run the Wicket application in &lt;a href="http://cwiki.apache.org/WICKET/faqs.html#FAQs-Myapplicationsays%22DEVELOPMENTMODE%22%2ChowdoIswitchtoproduction%3F"&gt;deployment mode&lt;/a&gt; to disable a thread checking for modifications in the background. Step 2:  override the method newSessionStore() in your WebApplication class like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    protected ISessionStore newSessionStore()&lt;br /&gt;    {&lt;br /&gt;        return new HttpSessionStore(this);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will eliminate another thread that is used by the default DiskPageStore class. Step 3: &lt;a href="http://code.google.com/appengine/docs/java/config/appconfig.html#Enabling_Sessions"&gt;enable sessions in Google App Engine&lt;/a&gt; as they are turned off by default. Wicket uses Http Session heavily. I got all this from &lt;a href="http://herebebeasties.com/2009-04-10/wicket-on-googles-app-engine/"&gt;Alastair Maw’s blog&lt;/a&gt;, thanks a lot!&lt;br /&gt;&lt;br /&gt;Now you have to add all the libraries that come with the Google App Engine SDK to your project. In my case the project is based on Maven, so I added the following to my pom.xml.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;repositories&amp;gt;&lt;br /&gt;        &amp;lt;repository&amp;gt;&lt;br /&gt;            &amp;lt;id&amp;gt;appengine&amp;lt;/id&amp;gt;&lt;br /&gt;            &amp;lt;name&amp;gt;Google App Engine Libraries&amp;lt;/name&amp;gt;&lt;br /&gt;            &amp;lt;url&amp;gt;http://www.mvnsearch.org/maven2&amp;lt;/url&amp;gt;&lt;br /&gt;        &amp;lt;/repository&amp;gt;&lt;br /&gt;        &amp;lt;repository&amp;gt;&lt;br /&gt;            &amp;lt;id&amp;gt;datanucleus&amp;lt;/id&amp;gt;&lt;br /&gt;            &amp;lt;name&amp;gt;Datanucleus Libraries&amp;lt;/name&amp;gt;&lt;br /&gt;            &amp;lt;url&amp;gt;http://www.datanucleus.org/downloads/maven2&amp;lt;/url&amp;gt;&lt;br /&gt;        &amp;lt;/repository&amp;gt;&lt;br /&gt;    &amp;lt;/repositories&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;dependencies&amp;gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.google.appengine&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;jdo2-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;2.3-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.google.appengine&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;datanucleus-appengine&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;1.0.1.final&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;org.datanucleus&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;datanucleus-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${datanucleus.version}&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;org.datanucleus&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;datanucleus-jpa&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${datanucleus.version}&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.google.appengine&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;appengine-api-1.0-sdk&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;1.2.1&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;     &amp;lt;/dependencies&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;datanucleus.version&amp;gt;1.1.0&amp;lt;/datanucleus.version&amp;gt;&lt;br /&gt;     &amp;lt;/properties&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately some dependencies cannot be resolved, even with the extra repositories I added manually. You have to add these jar file manually to your local Maven repository. I will not write about it here but check &lt;a href="http://www.danwalmsley.com/2009/04/07/building-google-app-engine-java-projects-with-maven2/"&gt;Dan Walmsleys Blog&lt;/a&gt; or &lt;a href="http://shalinsays.blogspot.com/2009/04/google-app-engine-and-maven.html"&gt;Shalins Blog&lt;/a&gt;, they explain what you need to do.&lt;br /&gt;&lt;br /&gt;Alright, now that we have all set up to Google App Enginefly our Java application - let's start. The App Engine SDK ships with a Servlet Container which you can start and test your application in an App Engine like environment. &lt;a href="http://code.google.com/appengine/downloads.html"&gt;Download&lt;/a&gt; and unzip the SDK, then go into the bin folder. To enable remote debugging in the appengine environment, open the startup script (dev_appserver.sh in Linux) and make it look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;# Launches the development AppServer&lt;br /&gt;&lt;br /&gt;[ -z "${DEBUG}" ] || set -x  # trace if $DEBUG env. var. is non-zero&lt;br /&gt;&lt;br /&gt;SDK_BIN=`dirname $0 | sed -e "s#^\\([^/]\\)#${PWD}/\\1#"` # sed makes absolute&lt;br /&gt;&lt;br /&gt;SDK_LIB=$SDK_BIN/../lib&lt;br /&gt;&lt;br /&gt;SDK_CONFIG=$SDK_BIN/../config/sdk&lt;br /&gt;&lt;br /&gt;java -ea -cp "$SDK_LIB/appengine-tools-api.jar" \&lt;br /&gt;&lt;br /&gt;  com.google.appengine.tools.KickStart \&lt;br /&gt;&lt;br /&gt;  --jvm_flag=-Xdebug \&lt;br /&gt;&lt;br /&gt;  --jvm_flag=-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n \&lt;br /&gt;&lt;br /&gt;  com.google.appengine.tools.development.DevAppServerMain $*&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next time you start your local appengine, you will be able to start a remote debugger on port 8000. Nice!&lt;br /&gt;&lt;br /&gt;So at this point, the application would run on Google App Engine without problems. However, the data is not persistent and will be gone every time you restart. So let's use a real database. Each App Enginefied application can access something what Google calls a datastore. The datastore may be accessed using either JDO or JPA. Neither plain JDBC nor O/R mappers like Hibernate or Toplink will work at this stage. Appengine uses something called &lt;a href="http://www.datanucleus.org/"&gt;datanucleus&lt;/a&gt; for datastore access, which I think is another abstraction for different ways of persistence. So datanucleus will process JDO or JPA instrumented classes and do some persistence magic.&lt;br /&gt;&lt;br /&gt;I decided to use JDO to access the appengine datastore from my application. In the first step let's add a PersistenceManagerFactory and some new DAO beans to the current Spring configuration.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;bean id="persistenceManagerFactory" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean"&amp;gt;&lt;br /&gt;        &amp;lt;property name="jdoProperties"&amp;gt;&lt;br /&gt;            &amp;lt;props&amp;gt;&lt;br /&gt;                &amp;lt;prop key="javax.jdo.PersistenceManagerFactoryClass"&amp;gt;&lt;br /&gt;                    org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory&lt;br /&gt;                &amp;lt;/prop&amp;gt;&lt;br /&gt;                &amp;lt;prop key="javax.jdo.option.ConnectionURL"&amp;gt;appengine&amp;lt;/prop&amp;gt;&lt;br /&gt;                &amp;lt;prop key="javax.jdo.option.NontransactionalRead"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br /&gt;                &amp;lt;prop key="javax.jdo.option.NontransactionalWrite"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br /&gt;                &amp;lt;prop key="javax.jdo.option.RetainValues"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br /&gt;                &amp;lt;prop key="datanucleus.appengine.autoCreateDatastoreTxns"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br /&gt;                &amp;lt;prop key="datanucleus.DetachOnClose"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br /&gt;            &amp;lt;/props&amp;gt;&lt;br /&gt;        &amp;lt;/property&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;bean id="daoWithPersistenceManagerFactory" abstract="true"&amp;gt;&lt;br /&gt;        &amp;lt;property name="persistenceManagerFactory" ref="persistenceManagerFactory" /&amp;gt;&lt;br /&gt;    &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;bean id="userDao" class="com.fernuni.db.jdo.UserJdoDao" parent="daoWithPersistenceManagerFactory" /&amp;gt;&lt;br /&gt;    &amp;lt;bean id="itemDao" class="com.fernuni.db.jdo.ItemJdoDao" parent="daoWithPersistenceManagerFactory" /&amp;gt;&lt;br /&gt;    &amp;lt;bean id="tagDao" class="com.fernuni.db.jdo.TagJdoDao" parent="daoWithPersistenceManagerFactory" /&amp;gt;&lt;br /&gt;    &amp;lt;bean id="taggedItemDao" class="com.fernuni.db.jdo.TaggedItemJdoDao" parent="daoWithPersistenceManagerFactory" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next I wrote a set of new DAO classes based on the JdoTemplate from Spring. When compared to JDBC, it is the AbstractJdoDao this time, which contains most code. The concreted DAO classes like UserJdoDao are rather small and reuse almost everything in the  AbstractJdoDao.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;public abstract class AbstractJdoDao&amp;lt;T extends Entity&amp;gt;&lt;br /&gt;{&lt;br /&gt;    private JdoTemplate m_jdoTemplate;&lt;br /&gt;&lt;br /&gt;    public JdoTemplate getJdoTemplate()&lt;br /&gt;    {&lt;br /&gt;        return m_jdoTemplate;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setPersistenceManagerFactory(final PersistenceManagerFactory persistenceManagerFactory)&lt;br /&gt;    {&lt;br /&gt;        m_jdoTemplate = new JdoTemplate(persistenceManagerFactory);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public T readEntityByName(final String name, final Class&amp;lt;T&amp;gt; clazz)&lt;br /&gt;    {&lt;br /&gt;        final JdoTemplate jdoTemplate = getJdoTemplate();&lt;br /&gt;        final Collection found = jdoTemplate.find(&lt;br /&gt;            clazz, "m_name == value", "String value", new Object[] {name}&lt;br /&gt;        );&lt;br /&gt;        return (found != null &amp;&amp; !found.isEmpty()) ? (T) found.toArray()[0] : null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Long createEntity(final T item)&lt;br /&gt;    {&lt;br /&gt;        final JdoTemplate jdoTemplate = getJdoTemplate();&lt;br /&gt;        final T persistentItem = (T) jdoTemplate.makePersistent(item);&lt;br /&gt;        return persistentItem.getId();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public T readEntity(final Long id, final Class&amp;lt;T&amp;gt; clazz)&lt;br /&gt;    {&lt;br /&gt;        final JdoTemplate jdoTemplate = getJdoTemplate();&lt;br /&gt;        return (T) jdoTemplate.getObjectById(clazz, id);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public List&amp;lt;T&amp;gt; readAllEntities(final Class&amp;lt;T&amp;gt; clazz)&lt;br /&gt;    {&lt;br /&gt;        final JdoTemplate jdoTemplate = getJdoTemplate();&lt;br /&gt;        return new ArrayList&amp;lt;T&amp;gt;(jdoTemplate.find(clazz));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void updateEntity(final T transientObject)&lt;br /&gt;    {&lt;br /&gt;        final JdoTemplate jdoTemplate = getJdoTemplate();&lt;br /&gt;        jdoTemplate.refresh(transientObject);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void deleteEntity(final T persistentObject)&lt;br /&gt;    {&lt;br /&gt;        final JdoTemplate jdoTemplate = getJdoTemplate();&lt;br /&gt;        jdoTemplate.deletePersistent(persistentObject);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class UserJdoDao extends AbstractJdoDao&amp;lt;User&amp;gt; implements UserDao&lt;br /&gt;{&lt;br /&gt;    public User readByName(final String name)&lt;br /&gt;    {&lt;br /&gt;        return readEntityByName(name, User.class);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Long create(final User user)&lt;br /&gt;    {&lt;br /&gt;        return createEntity(user);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public User read(final Long id)&lt;br /&gt;    {&lt;br /&gt;        return readEntity(id, User.class);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public List&amp;lt;User&amp;gt; readAll()&lt;br /&gt;    {&lt;br /&gt;        return readAllEntities(User.class);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void update(final User transientObject)&lt;br /&gt;    {&lt;br /&gt;        updateEntity(transientObject);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void delete(final User persistentObject)&lt;br /&gt;    {&lt;br /&gt;        deleteEntity(persistentObject);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Using JDO requires that the bytecode in your domain model classes is instrumented with the persistence information. So first of all, lets put down this information. To be least intrusive, I decided to provide separate .jdo files instead of using annotations. Here is the package.jdo file which I put in the package along with my domain model classes.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE jdo PUBLIC&lt;br /&gt;    "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 2.0//EN"&lt;br /&gt;    "http://java.sun.com/dtd/jdo_2_0.dtd"&amp;gt;&lt;br /&gt;&amp;lt;jdo&amp;gt;&lt;br /&gt;    &amp;lt;package name="com.fernuni.domain"&amp;gt;&lt;br /&gt;        &amp;lt;class name="Entity" detachable="true" identity-type="application"&amp;gt;&lt;br /&gt;            &amp;lt;inheritance strategy="complete-table"/&amp;gt;&lt;br /&gt;            &amp;lt;field name="id" primary-key="true" value-strategy="identity"&amp;gt;&lt;br /&gt;                &amp;lt;column name="ENTITY_ID"/&amp;gt;&lt;br /&gt;            &amp;lt;/field&amp;gt;&lt;br /&gt;            &amp;lt;field name="name"&amp;gt;&lt;br /&gt;                &amp;lt;column name="ENTITY_NAME"/&amp;gt;&lt;br /&gt;            &amp;lt;/field&amp;gt;&lt;br /&gt;        &amp;lt;/class&amp;gt;&lt;br /&gt;        &amp;lt;class name="User" detachable="true" identity-type="application"&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;/class&amp;gt;&lt;br /&gt;        &amp;lt;class name="Item" detachable="true" identity-type="application"&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;/class&amp;gt;&lt;br /&gt;        &amp;lt;class name="Tag" detachable="true" identity-type="application"&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;/class&amp;gt;&lt;br /&gt;        &amp;lt;class name="TaggedItem" detachable="true" identity-type="application"&amp;gt;&lt;br /&gt;            &amp;lt;field name="m_userId"&amp;gt;&lt;br /&gt;                &amp;lt;column name="TAGGED_USER_ID"/&amp;gt;&lt;br /&gt;            &amp;lt;/field&amp;gt;&lt;br /&gt;            &amp;lt;field name="m_itemId"&amp;gt;&lt;br /&gt;                &amp;lt;column name="TAGGED_ITEM_ID"/&amp;gt;&lt;br /&gt;            &amp;lt;/field&amp;gt;&lt;br /&gt;            &amp;lt;field name="m_tagId"&amp;gt;&lt;br /&gt;                &amp;lt;column name="TAGGED_TAG_ID"/&amp;gt;&lt;br /&gt;            &amp;lt;/field&amp;gt;&lt;br /&gt;        &amp;lt;/class&amp;gt;&lt;br /&gt;    &amp;lt;/package&amp;gt;&lt;br /&gt;&amp;lt;/jdo&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately datanucleus does not support primary keys of type Integer and all Id's in my JDBC based applications were Integers. So I had to change from Integer to Long to get it working. Quite intrusive but something I can live with. As a last step, Maven needs to instrument the domain classes using the JDO instructions from my package.jdo file. I added the maven-datanucleus-plugin in my Maven build process.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 9px; line-height: 9px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;build&amp;gt;      &lt;br /&gt;        &amp;lt;plugins&amp;gt;&lt;br /&gt;            &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;groupId&amp;gt;org.datanucleus&amp;lt;/groupId&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;maven-datanucleus-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                &amp;lt;version&amp;gt;${datanucleus.version}&amp;lt;/version&amp;gt;&lt;br /&gt;                &amp;lt;configuration&amp;gt;&lt;br /&gt;                    &amp;lt;mappingIncludes&amp;gt;**/*.class&amp;lt;/mappingIncludes&amp;gt;&lt;br /&gt;                    &amp;lt;verbose&amp;gt;true&amp;lt;/verbose&amp;gt;&lt;br /&gt;                    &amp;lt;enhancerName&amp;gt;ASM&amp;lt;/enhancerName&amp;gt;&lt;br /&gt;                    &amp;lt;api&amp;gt;JDO&amp;lt;/api&amp;gt;&lt;br /&gt;                &amp;lt;/configuration&amp;gt;&lt;br /&gt;                &amp;l
