<?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-7524162926732063545</id><updated>2011-10-04T23:58:17.834+02:00</updated><category term='java7'/><category term='scripting'/><category term='firefox'/><category term='hibernate'/><category term='scala'/><category term='ant'/><category term='css'/><category term='java'/><category term='wicket'/><category term='groovy'/><category term='spring'/><category term='java performance'/><category term='html'/><category term='aop'/><category term='weblogic'/><category term='maven'/><category term='eclipse'/><category term='concurrency'/><category term='guava'/><category term='web design'/><category term='project coin'/><category term='java generics'/><title type='text'>out.println</title><subtitle type='html'>Standard output of work-related thoughts.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>26</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7524162926732063545.post-7982956514641157204</id><published>2011-01-04T21:34:00.015+01:00</published><updated>2011-04-21T22:31:46.110+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='project coin'/><category scheme='http://www.blogger.com/atom/ns#' term='java7'/><title type='text'>Simplified varargs for dummies</title><content type='html'>I've migrated this post to &lt;a href="http://out-println.appspot.com/posts/simplified_varargs_101"&gt;my new blog&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-7982956514641157204?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/7982956514641157204/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=7982956514641157204' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/7982956514641157204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/7982956514641157204'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2011/01/simplified-varargs-for-dummies.html' title='Simplified varargs for dummies'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-6995810996821458665</id><published>2010-12-16T19:33:00.015+01:00</published><updated>2010-12-19T15:06:31.667+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><title type='text'>Breakpoint dependencies in Eclipse</title><content type='html'>This post describes a hack to achieve the following behavior in the Eclipse debugger: &lt;b&gt;stop at a given breakpoint only if another breakpoint has been reached before&lt;/b&gt;. &lt;br /&gt;I'm not aware of an existing solution to do that (although IDEA &lt;a href="http://stackoverflow.com/questions/2674582"&gt;seems to have&lt;/a&gt; that functionality) &amp;mdash; and if I'm wrong, I've just lost a couple of hours of my life :-)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The problem&lt;/h3&gt;&lt;br /&gt;Suppose I'm debugging a unit test that runs the same assertion over and over with different parameters (I know unit tests should have few assertions, but sometimes this pattern is just more practical):&lt;pre&gt;&amp;nbsp;&amp;nbsp;assertEquals(43, SomeClass.someMethod(1));&lt;br /&gt;&amp;nbsp;&amp;nbsp;assertEquals(44, SomeClass.someMethod(2));&lt;br /&gt;&amp;nbsp;&amp;nbsp;assertEquals(45, SomeClass.someMethod(3));&lt;br /&gt;&amp;nbsp;&amp;nbsp;assertEquals(50, SomeClass.someMethod(4));&lt;/pre&gt;Suppose the last assertion is failing. I want to debug it, and I'm particularly interested in an internal method called indirectly by &lt;tt&gt;someMethod&lt;/tt&gt;, deep down the call stack:&lt;pre&gt;private static int internalMethod(int p) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;return p + 42;&lt;br /&gt;}&lt;/pre&gt;Basically, I have three options:&lt;ul&gt;&lt;li&gt;set a breakpoint on &lt;tt&gt;internalMethod&lt;/tt&gt;. But the debugger will suspend every time the method is reached, including in the first N-1 calls to &lt;tt&gt;someMethod&lt;/tt&gt; that I'm not interested in. That sucks.&lt;/li&gt;&lt;li&gt;set the breakpoint on the assertion that fails. But when the debugger suspends, I still have to go down the call stack to reach &lt;tt&gt;internalMethod&lt;/tt&gt;. This involves using &lt;i&gt;Go into&lt;/i&gt; repeatedly, which may go into a lot of auxiliary code I'm not interested in (any method invoked to build parameters, class loads, etc.). That also sucks.&lt;/li&gt;&lt;li&gt;set the breakpoint on the outer method, and when it suspends, set the breakpoint on the inner method manually, and hit &lt;i&gt;Continue&lt;/i&gt; to reach it directly. That sucks less, but still involves manual work (to be undone and redone everytime I rerun the test).&lt;/li&gt;&lt;/ul&gt;Wouldn't it be nice to set both breakpoints, and configure the second one to "activate" only after the first one has been reached? Well that's possible: breakpoints can be conditioned by Java code, and that code can have side effects.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The solution&lt;/h3&gt;&lt;br /&gt;I drop a class named &lt;tt&gt;Breaks&lt;/tt&gt; in my test folder (the source code of the class is available &lt;a href="https://gist.github.com/743887"&gt;here&lt;/a&gt;). On the outer breakpoint, I add the following condition:&lt;br /&gt;&lt;br /&gt;&lt;img src="https://8392209901035651731-a-1802744773732722657-s-sites.googlegroups.com/site/outprinltn/breakpoint_props1.png"/&gt;&lt;br /&gt;&lt;br /&gt;This sets a "marker" that is accessible from other breakpoints. The &lt;tt&gt;set&lt;/tt&gt; method returns &lt;tt&gt;false&lt;/tt&gt;, so the debugger will never suspend on that breakpoint (if I want it to, there is an equivalent &lt;tt&gt;setAndBreak&lt;/tt&gt; method).&lt;br /&gt;&lt;br /&gt;On the second breakpoint, the condition invokes a method that returns &lt;tt&gt;true&lt;/tt&gt; only if the marker is set (alternatively, &lt;tt&gt;testAndClear&lt;/tt&gt; also deletes the marker):&lt;br /&gt;&lt;br /&gt;&lt;img src="https://8392209901035651731-a-1802744773732722657-s-sites.googlegroups.com/site/outprinltn/breakpoint_props2.png"/&gt;&lt;br /&gt;&lt;br /&gt;Voilà! As long as the outer breakpoint hasn't been reached, the inner breakpoint will not suspend.&lt;br /&gt;&lt;br /&gt;This is portable to any debugger that supports conditions, and more elaborate strategies are possible (for instance, associating counters to the markers, instead of simple on / off state).&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Update 2010/12/18:&lt;/i&gt; you will run into compile errors if &lt;tt&gt;Breaks&lt;/tt&gt; and the debugged classes reside in different packages. To avoid this, put &lt;tt&gt;Breaks&lt;/tt&gt; in a package with a short name, and use the fully qualified name in the breakpoint conditions (putting it in the default package doesn't seem to work, and import statements are not allowed in breakpoint conditions).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-6995810996821458665?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/6995810996821458665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=6995810996821458665' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/6995810996821458665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/6995810996821458665'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2010/12/breakpoint-dependencies-in-eclipse.html' title='Breakpoint dependencies in Eclipse'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-5464358082642904627</id><published>2010-06-20T17:32:00.008+02:00</published><updated>2010-06-21T14:54:16.219+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='guava'/><title type='text'>Remove boilerplate with Guava</title><content type='html'>&lt;a href="http://code.google.com/p/guava-libraries/"&gt;Guava&lt;/a&gt; describes itself as "Google's core Libraries for Java 1.5+". It is a superset of the Google Collections framework, along with other utilities, released as an open-source project under the Apache 2.0 license.&lt;br /&gt;&lt;br /&gt;What I want to cover in this post are not Guava's major features, but rather some simple "shortcut" methods (each factoring a common Java idiom) that can make a developer's life easier.&lt;br /&gt;&lt;br /&gt;To illustrate this, let's consider this simple method:&lt;pre&gt;public void save(final String info, final File file) throws IOException {&lt;br /&gt;&amp;nbsp;&amp;nbsp;if (file == null) throw new NullPointerException("file should not be null");&lt;br /&gt;&amp;nbsp;&amp;nbsp;Writer writer = null;&lt;br /&gt;&amp;nbsp;&amp;nbsp;boolean threw = true;&lt;br /&gt;&amp;nbsp;&amp;nbsp;try {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writer = new BufferedWriter(new OutputStreamWriter(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new FileOutputStream(file), Charset.forName("UTF-8")));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String data = info == null ? "Nothing" : info;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writer.write(data);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;threw = false;&lt;br /&gt;&amp;nbsp;&amp;nbsp;} finally {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (writer != null)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writer.close();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} catch (IOException e) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Do not swallow original exception&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (!threw) throw e;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/pre&gt;Here is a version with the corresponding Guava methods:&lt;pre&gt;public void save(final String info, final File file) throws IOException {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Preconditions.html#checkNotNull(T,%20java.lang.Object)"&gt;Preconditions.checkNotNull&lt;/a&gt;(file, "file should not be null");&lt;br /&gt;&amp;nbsp;&amp;nbsp;Writer writer = null;&lt;br /&gt;&amp;nbsp;&amp;nbsp;boolean threw = true;&lt;br /&gt;&amp;nbsp;&amp;nbsp;try {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writer = &lt;a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/io/Files.html#newWriter(java.io.File,%20java.nio.charset.Charset)"&gt;Files.newWriter&lt;/a&gt;(file, &lt;a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Charsets.html#UTF_8"&gt;Charsets.UTF_8&lt;/a&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writer.write(&lt;a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Objects.html#firstNonNull(T,%20T)"&gt;Objects.firstNonNull&lt;/a&gt;(info, "Nothing"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;threw = false;&lt;br /&gt;&amp;nbsp;&amp;nbsp;} finally {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/io/Closeables.html#close(java.io.Closeable,%20boolean)"&gt;Closeables.close&lt;/a&gt;(writer, threw);&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/pre&gt;Actually, there is even simpler, since we are only writing one string to the file:&lt;pre&gt;public void save(final String info, final File file) throws IOException {&lt;br /&gt;&amp;nbsp;&amp;nbsp;Preconditions.checkNotNull(file, "file should not be null");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/io/Files.html#write(java.lang.CharSequence,%20java.io.File,%20java.nio.charset.Charset)"&gt;Files.write&lt;/a&gt;(Objects.firstNonNull(info, "Nothing"), file, Charsets.UTF_8);&lt;br /&gt;}&lt;/pre&gt;Optionally, you can also static import everything (which increases readability but makes the origin of the methods less obvious &amp;mdash; the choice is a matter of personal taste):&lt;pre&gt;public void save(final String info, final File file) throws IOException {&lt;br /&gt;&amp;nbsp;&amp;nbsp;checkNotNull(file, "file should not be null");&lt;br /&gt;&amp;nbsp;&amp;nbsp;write(firstNonNull(info, "Nothing"), file, UTF_8);&lt;br /&gt;}&lt;/pre&gt;That's it. Nothing groundbreaking really, but I like how this makes the code more expressive, focusing on what you do rather than how you do it. Guava has a myriad of these utilities (look for static methods in the classes that have a plural name: &lt;a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Lists.html"&gt;Lists&lt;/a&gt;, &lt;a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Strings.html"&gt;Strings&lt;/a&gt;, &lt;a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/io/Resources.html"&gt;Resources&lt;/a&gt;...).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-5464358082642904627?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/5464358082642904627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=5464358082642904627' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/5464358082642904627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/5464358082642904627'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2010/06/remove-boilerplate-with-guava.html' title='Remove boilerplate with Guava'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-7238064951153705550</id><published>2010-06-13T19:42:00.007+02:00</published><updated>2010-06-15T10:18:20.562+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Effectively immutable</title><content type='html'>Following on my previous post, another situation where shared state can be accessed without synchronization is when dealing with effectively immutable objects.&lt;br /&gt;&lt;br /&gt;Here is a class to gather simple statistics during a multi-threaded batch process:&lt;pre&gt;public final class Stats {&lt;br /&gt;&amp;nbsp;&amp;nbsp;public enum Counter { INPUTS, PARSE_ERRORS, PROCESSING_ERRORS, SUCCESSES, };&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;private final EnumMap&amp;lt;Counter, AtomicInteger&amp;gt; values;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;public Stats() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;values = new EnumMap&amp;lt;Counter, AtomicInteger&amp;gt;(Counter.class);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Pre-fill the map:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (Counter counter: Counter.values())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;values.put(counter, new AtomicInteger());&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;public void increment(Counter counter) { values.get(counter).incrementAndGet(); }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;@Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;public String toString() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringBuilder sb = new StringBuilder();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (Entry&amp;lt;Counter, AtomicInteger&amp;gt; entry: values.entrySet())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sb.append(entry.getKey() + " = " + entry.getValue() + "\n");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return sb.toString();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/pre&gt;A single instance is shared among all worker threads. Each worker increments the appropriate counters as it progresses:&lt;pre&gt;stats.increment(Stats.Counter.INPUTS);&lt;/pre&gt;The statistics are output when all work is done:&lt;pre&gt;System.out.println(stats);&lt;/pre&gt;&lt;br /&gt;The important point here is that access to the &lt;tt&gt;values&lt;/tt&gt; field is not synchronized, yet &lt;tt&gt;Stats&lt;/tt&gt; is still thread-safe. This is because &lt;tt&gt;values&lt;/tt&gt; is effectively immutable: after it has been pre-filled in the constructor and safely published through a final field, it is never structurally modified. Therefore it is safe to assume that all invocations of &lt;tt&gt;increment&lt;/tt&gt; will see it in a consistent state.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;On the other hand, here is an example where the modification of an &lt;tt&gt;EnumMap&lt;/tt&gt; is not safely published:&lt;pre&gt;public class UnsafeEnumMapMutation { // DOESN'T WORK&lt;br /&gt;&amp;nbsp;&amp;nbsp;static enum Command { STOP }&lt;br /&gt;&amp;nbsp;&amp;nbsp;private static final EnumMap&amp;lt;Command, Integer&amp;gt; MAP =&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new EnumMap&amp;lt;Command, Integer&amp;gt;(Command.class);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;public static void main(final String[] args) throws InterruptedException {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;final ExecutorService executor = Executors.newFixedThreadPool(2);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;final Runnable looping = new Runnable() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int i = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (!MAP.containsKey(Command.STOP)) i++;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.submit(looping);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;final Runnable stopper = new Runnable() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void run() { MAP.put(Command.STOP, 1); }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.submit(stopper);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.shutdown();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/pre&gt;As in my previous post, task &lt;tt&gt;stopper&lt;/tt&gt; is trying to tell task &lt;tt&gt;looping&lt;/tt&gt; to terminate. This time, the signal is the presence of a given key the map. However, this change is not protected by synchronization, and the map is not effectively immutable, since it is mutated &lt;i&gt;after&lt;/i&gt; its initial publication as a final field. And again, this example loops when I run it with the &lt;tt&gt;-server&lt;/tt&gt; option.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-7238064951153705550?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/7238064951153705550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=7238064951153705550' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/7238064951153705550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/7238064951153705550'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2010/06/effectively-immutable.html' title='Effectively immutable'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-8891656581994128794</id><published>2010-06-09T14:02:00.006+02:00</published><updated>2010-06-13T21:15:17.184+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Piggybacking on synchronization</title><content type='html'>Sometimes you can take advantage of an existing synchronization to guarantee the visibility of some changes. In &lt;a href="http://jcip.net/"&gt;Java Concurrency In Practice&lt;/a&gt;, Brian Goetz calls this "piggybacking on synchronization".&lt;br /&gt;&lt;br /&gt;A typical example is the publication of read-only resources that will be shared by all tasks in a thread pool: one of my projects at work parses and processes a few thousands XML files in parallel. I use &lt;a href="http://xstream.codehaus.org/"&gt;XStream&lt;/a&gt; for the parsing. The javadoc of &lt;a href="http://xstream.codehaus.org/javadoc/com/thoughtworks/xstream/XStream.html"&gt;&lt;tt&gt;XStream&lt;/tt&gt;&lt;/a&gt; &amp;mdash; the base class that lets you configure the framework and [de]serialize objects &amp;mdash; states that it is safe to use by multiple threads once it has been configured. So it makes sense to use a single instance all along:&lt;pre&gt;public class GoodPiggy {&lt;br /&gt;&amp;nbsp;&amp;nbsp;private ExecutorService executor;&lt;br /&gt;&amp;nbsp;&amp;nbsp;private XStream xstream;&lt;br /&gt;  &lt;br /&gt;&amp;nbsp;&amp;nbsp;public void init() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor = Executors.newFixedThreadPool(someSize);    &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;final XStream xstream = new XStream();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// configure xstream...&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;private class Task implements Runnable {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// do something with xstream... (threadsafe)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;public void submit() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.submit(new Task());&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/pre&gt;The important question here is: are the changes to &lt;tt&gt;xstream&lt;/tt&gt; safely published, i.e. do the worker threads running the tasks "see" the configuration performed in &lt;tt&gt;init()&lt;/tt&gt;? This is where piggybacking comes into play: submitting a task to an executor &lt;a href="http://en.wikipedia.org/wiki/Happened-before"&gt;&lt;i&gt;happens-before&lt;/i&gt;&lt;/a&gt; the task begins execution, so the code using &lt;tt&gt;xstream&lt;/tt&gt; in &lt;tt&gt;run()&lt;/tt&gt; is guaranteed to see it in a consistent state (assuming of course that &lt;tt&gt;init()&lt;/tt&gt; and &lt;tt&gt;submit()&lt;/tt&gt; are run by the same thread).&lt;br /&gt;JCIP warns that piggybacking on synchronization is a fragile construct, but I think this case is a reasonable use.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Note: &lt;strike&gt;an even better solution is to make &lt;tt&gt;xstream&lt;/tt&gt; a final field initialized in the class's constructor&lt;/strike&gt;. EDIT 2010/06/13 &amp;mdash; that was actually wrong: a final field would only guarantee the safe publication of the &lt;/i&gt;reference&lt;i&gt;, but not of the changes performed afterwards on the (mutable) object designated by that reference. Piggybacking would come into play even with a final field.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Of course, things don't work so well if the tasks need to modify the shared state. Here is a counter-example (adapted from item 66 of &lt;a href="http://java.sun.com/docs/books/effective/"&gt;Effective Java, 2nd edition&lt;/a&gt;):&lt;pre&gt;public class BadPiggy { // DOESN'T WORK&lt;br /&gt;&amp;nbsp;&amp;nbsp;private static boolean stop;&lt;br /&gt;  &lt;br /&gt;&amp;nbsp;&amp;nbsp;public static void main(final String[] args) throws InterruptedException {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;final ExecutorService executor = Executors.newFixedThreadPool(2);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Runnable looping = new Runnable() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int i = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (!stop) i++;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.submit(looping);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Runnable stopper = new Runnable() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void run() { stop = true; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.submit(stopper);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.shutdown();&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/pre&gt;Here the modification of &lt;tt&gt;stop&lt;/tt&gt; is not safely published, because there is no happens-before relationship between the moment &lt;tt&gt;stopper&lt;/tt&gt; sets it, and the moment &lt;tt&gt;looping&lt;/tt&gt; is expected to see the change. I can get this example to loop forever on my machine (windows, Java 6u16 VM with &lt;tt&gt;-server&lt;/tt&gt; option).&lt;br /&gt;&lt;br /&gt;The solution here is to make the field &lt;tt&gt;volatile&lt;/tt&gt;, which guarantees visibility of the changes. If we needed mutual exclusion as well (for instance, if the shared state was an incrementing counter), we would need synchronization, either explicitly, or through a higher-level construct (like an &lt;tt&gt;AtomicInteger&lt;/tt&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-8891656581994128794?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/8891656581994128794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=8891656581994128794' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/8891656581994128794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/8891656581994128794'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2010/06/piggybacking-on-synchronization.html' title='Piggybacking on synchronization'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-3545930625374406522</id><published>2010-05-26T09:33:00.012+02:00</published><updated>2010-05-26T21:00:13.363+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Using Scala implicit conversions for backward compatibility</title><content type='html'>This post explains how to use implicit conversions to work around API incompatibilities between Scala 2.7 and 2.8.&lt;br /&gt;I learnt about this technique from reading the source code of &lt;a href="http://github.com/harrah/browse"&gt;SXR&lt;/a&gt;. What follows is a step-by-step explanation.&lt;h4&gt;Implicit conversion basics&lt;/h4&gt;Implicit conversions can make an object behave like it has another type. In particular, it can be used to add new methods to existing types. When a method is invoked on an object and no match is found, Scala will try to apply any implicit conversion currently in scope. Try typing this in the Scala REPL:&lt;pre&gt;implicit def intToHello(i: Int) = {&lt;br /&gt;&amp;nbsp;&amp;nbsp;println("intToHello was applied")&lt;br /&gt;&amp;nbsp;&amp;nbsp;new { def message = "hello from " + i }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;In this contrived example, we define an implicit conversion to add a &lt;tt&gt;message&lt;/tt&gt; method to integers. The conversion returns an anonymous instance that provides the method. I've added a print statement for illustrative purposes. We can now invoke &lt;tt&gt;message&lt;/tt&gt; on any integer:&lt;pre&gt;scala&gt; println(42.message)&lt;br /&gt;intToHello was applied&lt;br /&gt;hello from 42&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;A case of API incompatibility: &lt;tt&gt;Symbol.fullNameString&lt;/tt&gt;&lt;/h4&gt;SXR is a Scala compiler plugin that generates an HTML cross-reference of the sources of a Scala project. In order to support partial recompilation and cross-project links, it needs to generate "stable" IDs for public compiler symbols; in particular, these IDs contain the full name of the symbol, which, in Scala 2.7.7, is retrieved with the method &lt;a href="https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_7_final/src/compiler/scala/tools/nsc/symtab/Symbols.scala#L1234"&gt;Symbol.fullNameString&lt;/a&gt; :&lt;pre&gt;def nameString(s: Symbol) = s.fullNameString&lt;br /&gt;&lt;/pre&gt;(&lt;a href="http://sites.google.com/site/outprinltn/Implicits1.scala"&gt;full source&lt;/a&gt;)&lt;br/&gt;&lt;br /&gt;Unfortunately (for this particular situation!), symbols have been refactored in Scala 2.8. Class &lt;tt&gt;Symbol&lt;/tt&gt; now extends &lt;tt&gt;scala.reflect.generic.Symbols.AbsSymbol&lt;/tt&gt;, and the method we need is now called &lt;a href="https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_8_0_RC2/src/library/scala/reflect/generic/Symbols.scala#L47"&gt;fullName&lt;/a&gt;. The code above no longer compiles:&lt;pre&gt;&amp;lt;console&amp;gt;:12: error: value fullNameString is not a member of Demo.this.global.Symbol&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;def nameString(s: Symbol) = s.fullNameString&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;Implicits to the rescue&lt;/h4&gt;To compile the code with Scala 2.8, &lt;tt&gt;Symbol&lt;/tt&gt; must behave like it has a &lt;tt&gt;fullNameString&lt;/tt&gt; method. This is done exactly as in our first &lt;tt&gt;intToHello&lt;/tt&gt; example: &lt;pre&gt;def nameString(s: Symbol) = s.fullNameString&lt;br /&gt;&lt;b&gt;private implicit def symCompat(sym: Symbol): SymCompat = new SymCompat(sym)&lt;br /&gt;private final class SymCompat(s: Symbol) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def fullNameString = s.fullName;&lt;br /&gt;}&lt;/b&gt;&lt;br /&gt;&lt;/pre&gt;(&lt;a href="http://sites.google.com/site/outprinltn/Implicits2.scala"&gt;full source&lt;/a&gt;)&lt;br/&gt;&lt;br /&gt;An implicit is used to add the missing &lt;tt&gt;fullNameString&lt;/tt&gt; method, which delegates to the original &lt;tt&gt;fullName&lt;/tt&gt;. The code now compiles with Scala 2.8. However, it no longer compiles with 2.7:&lt;pre&gt;&amp;lt;console&amp;gt;:12: error: value fullName is not a member of Demo.this.global.Symbol&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;def fullNameString = s.fullName;&lt;br /&gt;&lt;/pre&gt;The 2.7 version of &lt;tt&gt;Symbol&lt;/tt&gt; has no &lt;tt&gt;fullName&lt;/tt&gt; method. Although the &lt;tt&gt;symCompat&lt;/tt&gt; implicit will never be invoked at runtime in Scala 2.7 (since &lt;tt&gt;Symbol&lt;/tt&gt; does defines &lt;tt&gt;fullNameString&lt;/tt&gt;), this is still a compile error. To solve this, the missing method is added to the same implicit conversion:&lt;br /&gt;&lt;pre&gt;def nameString(s: Symbol) = s.fullNameString&lt;br /&gt;private implicit def symCompat(sym: Symbol): SymCompat = new SymCompat(sym)&lt;br /&gt;private final class SymCompat(s: Symbol) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def fullNameString = s.fullName; &lt;b&gt;def fullName = sourceCompatibilityOnly&lt;/b&gt;&lt;br /&gt;}&lt;br /&gt;&lt;b&gt;private def sourceCompatibilityOnly = assert(false, "should not get here")&lt;/b&gt;&lt;br /&gt;&lt;/pre&gt;(&lt;a href="http://sites.google.com/site/outprinltn/Implicits3.scala"&gt;full source&lt;/a&gt;)&lt;br/&gt;&lt;br /&gt;To stress the fact that the method will never actually be invoked at runtime, it delegates to a method that throws an assertion error.&lt;h4&gt;Conclusion&lt;/h4&gt;The final version of the code compiles with both versions of Scala. The implicit conversion and its supporting type provide runtime compatibility for Scala 2.8, and compile-time compatibility for Scala 2.7. Note that this can also be done &lt;a href="http://sites.google.com/site/outprinltn/Implicits4.scala"&gt;the other way around&lt;/a&gt;; if the code is intended primarily for one version, it is probably a good idea to have the implicit applied on the other one. Finally, this technique should be properly encapsulated, to avoid leaking the implicits to the rest of your code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-3545930625374406522?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/3545930625374406522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=3545930625374406522' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/3545930625374406522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/3545930625374406522'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2010/05/using-scala-implicit-conversions-for.html' title='Using Scala implicit conversions for backward compatibility'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-7056810234691998856</id><published>2010-01-16T09:53:00.004+01:00</published><updated>2010-01-16T16:15:46.421+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java performance'/><title type='text'>How NOT to microbenchmark</title><content type='html'>A terrible article on developer.com spawned a number of reactions in various forums: &lt;a href="http://www.developer.com/java/article.php/3856906/Java-vs-C-The-Performance-Showdown.htm"&gt;Java vs. C++: The Performance Showdown&lt;/a&gt;. I won't go over the flaws in the author's testing "procedure", since this is already done in the article's comments (in particular &lt;a href="http://www.developer.com/java/article.php/3856906/Java-vs-C-The-Performance-Showdown.htm#comment25086-0"&gt;this one&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;But even bad articles can have positive effects: following some of the links in the comments, I eventually came across &lt;a href="http://www-128.ibm.com/developerworks/java/library/j-jtp02225.html"&gt;this excellent article&lt;/a&gt; by Brian Goetz. Here is his advice on micro-benchmarking:&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;So, how do you write a perfect microbenchmark? First, write a good optimizing JIT. Meet the people who have written other good, optimizing JITs (they're easy to find, because not too many good, optimizing JITs exist!). Have them over to dinner, and swap stories of performance tricks on how to run Java bytecode as fast as possible. Read the hundreds of papers on optimizing the execution of Java code, and write a few. You will then have the skills you need to write a good microbenchmark for something like the cost of synchronization, object pooling, or virtual method invocation.&lt;/i&gt;&lt;/blockquote&gt;Wow! It seems Mr Goetz is telling us we should not try to write microbenchmarks. So what should we do instead? Go read the article!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-7056810234691998856?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/7056810234691998856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=7056810234691998856' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/7056810234691998856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/7056810234691998856'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2010/01/how-not-to-microbenchmark.html' title='How NOT to microbenchmark'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-314916607847688368</id><published>2010-01-07T13:50:00.004+01:00</published><updated>2010-01-07T14:08:55.164+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><title type='text'>Hibernate: disabling all lazy associations programmatically</title><content type='html'>In an ideal world, you would define a global fetch plan for your application, carefully weighing the pros and cons of making each association lazy.&lt;br /&gt;&lt;br /&gt;In real life, you might find yourself forced to reuse existing mappings that use (and abuse of) lazy associations. This is annoying in a performance-critical use case, since you probably don't want 10 requests to go to the database for each loaded entity.&lt;br /&gt;&lt;br /&gt;I found &lt;a href="https://forum.hibernate.org/viewtopic.php?f=1&amp;t=932237&amp;start=0"&gt;an old post about this issue&lt;/a&gt; on the Hibernate forums. "christian" of the Hibernate team (whom I assume is Christian Bauer) had this suggestion:&lt;blockquote&gt;&lt;i&gt;&lt;br /&gt;Usually, you override fetching strategies with HQL and Criteria queries. If you like to disable/enable some setting globally, you might rebuild the SessionFactory after modifying the metadata from the Configuration programatically. This is easier than it sounds, get all PersistentClass objects from Configuration (the API), loop over all collections and setLazy(true). Then, build a new SessionFactory from this Configuration.&lt;br /&gt;&lt;br /&gt;This is acceptable for once-a-day batch operations, I think.&lt;/i&gt;&lt;/blockquote&gt;This is exactly what I needed. Here is an implementation:&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;public static Configuration setAllToLazy(final Configuration cfg) {&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; Iterator&amp;lt;PersistentClass&amp;gt; classes = cfg.getClassMappings();&lt;br /&gt; while (classes.hasNext()) {&lt;br /&gt;  PersistentClass clazz = classes.next();&lt;br /&gt;  setPropertiesToLazy(clazz.getPropertyIterator());&lt;br /&gt;&lt;br /&gt;  Property key = clazz.getIdentifierProperty();&lt;br /&gt;  // Don't forget composite keys, which can contain associations&lt;br /&gt;  if (key.isComposite()) {&lt;br /&gt;   Component c = (Component) key.getValue();&lt;br /&gt;   setPropertiesToLazy(c.getPropertyIterator());&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; Iterator&amp;lt;Collection&amp;gt; collections = cfg.getCollectionMappings();&lt;br /&gt; while (collections.hasNext()) {&lt;br /&gt;  Collection collection = collections.next();&lt;br /&gt;  collection.setLazy(true);&lt;br /&gt; }&lt;br /&gt; return cfg;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Handle "simple" (*-to-one) properties&lt;br /&gt;@SuppressWarnings("unchecked")&lt;br /&gt;private static void setPropertiesToLazy(final Iterator iterator) {&lt;br /&gt; Iterator&amp;lt;Property&amp;gt; properties = iterator;&lt;br /&gt; while (properties.hasNext()) {&lt;br /&gt;  Value value = properties.next().getValue();&lt;br /&gt;  if (value instanceof ToOne) {&lt;br /&gt;   ((ToOne) value).setLazy(true);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-314916607847688368?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/314916607847688368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=314916607847688368' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/314916607847688368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/314916607847688368'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2010/01/hibernate-disabling-all-lazy.html' title='Hibernate: disabling all lazy associations programmatically'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-1301793841901432156</id><published>2009-03-17T00:05:00.004+01:00</published><updated>2009-03-17T21:26:53.590+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Follow-up on "Maven modules with independent versions"</title><content type='html'>Frank provided insightful feedback on my previous post &lt;a href="http://out-println.blogspot.com/2008/10/maven-modules-with-independent-versions.html"&gt;Maven modules with independent versions&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;First of all, he ran into the same issues as me, which proves that my post was not completely pointless :-)&lt;br /&gt;&lt;br /&gt;More importantly, he found a weakness in my solution: some repository managers (such as &lt;a href="http://nexus.sonatype.org/about/faq.html#QHowdoIdisableartifactredeployment"&gt;Nexus&lt;/a&gt;) can be configured to prevent redeploys of release versions -- which, on a sidenote, is probably a good idea.&lt;br /&gt;However, in my example from the previous post, this prevents global deployments to be run from the root directory, since some of the modules are still in a previous version that is already in the repository.&lt;ul&gt;&lt;li&gt;for release deployments, this is not really a problem: my solution assumed individual module releases anyway, and the release plugin takes care of deploying.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;for snapshot deployments, this is more annoying: they are typically performed nightly by the continuous integration system. But the modules that are not impacted by the current development iteration have not been incremented to a snapshot version, therefore they break the nightly deploy. And you know how grumpy our developers get when they don't have their fresh snapshots in the morning.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;To address these issues, I've added two system properties that will condition the deployment of each module:&lt;ul&gt;&lt;li&gt;&lt;tt&gt;maven.delivery.version&lt;/tt&gt;: if set, only the modules with this version will be deployed. This takes care of release deployments. For instance, in the case where &lt;tt&gt;webapp&lt;/tt&gt; is in version 1.0.1 and the business modules are still in 1.0.0, you run this command from the global POM to ensure 1.0.0 artifacts are not redeployed:&lt;pre&gt;mvn deploy -Dmaven.delivery.version=1.0.1&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;maven.delivery.deploySnapshotsOnly&lt;/tt&gt;: if set to &lt;tt&gt;true&lt;/tt&gt;, only snapshot modules are deployed. For instance, during the 1.0.1 iteration, &lt;tt&gt;webapp&lt;/tt&gt; is in version 1.0.1-SNAPSHOT, and the business modules are still in 1.0.0. You configure this command in your CI system:&lt;pre&gt;mvn deploy -Dmaven.delivery.deploySnapshotsOnly=true&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;These properties are handled by a new mojo in our custom plugin. When it decides that a module must not be redeployed, it simply sets &lt;tt&gt;maven.deploy.skip&lt;/tt&gt; (a built-in property of the deploy plugin) to &lt;tt&gt;true&lt;/tt&gt; on the project.&lt;br /&gt;This mojo must be executed before the &lt;tt&gt;deploy&lt;/tt&gt; phase, so we bind its execution to the &lt;tt&gt;install&lt;/tt&gt; phase of &lt;tt&gt;parent&lt;/tt&gt;:&lt;pre&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;com.acme&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;delivery-maven-plugin&amp;lt;/artifactId&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;check-deploy-needed&amp;lt;/id&amp;gt;&lt;br /&gt;      &amp;lt;phase&amp;gt;install&amp;lt;/phase&amp;gt;&lt;br /&gt;      &amp;lt;goals&amp;gt;&amp;lt;goal&amp;gt;check-deploy-needed&amp;lt;/goal&amp;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;/pre&gt;I also added the execution on the &lt;tt&gt;delivery&lt;/tt&gt; module, although in practice it's not essential: if you deploy any module, you necessarily need to deploy &lt;tt&gt;delivery&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Here are the &lt;a href="http://outprinltn.googlepages.com/maven-modules-example2.zip"&gt;sources of the example&lt;/a&gt; (ZIP, 16.9Kb).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-1301793841901432156?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/1301793841901432156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=1301793841901432156' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/1301793841901432156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/1301793841901432156'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2009/03/follow-up-on-maven-modules-with.html' title='Follow-up on &quot;Maven modules with independent versions&quot;'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7524162926732063545.post-866179135113284905</id><published>2009-03-07T13:37:00.002+01:00</published><updated>2009-03-07T14:40:05.108+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web design'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>HTML forms the way God intented</title><content type='html'>I've been busy with a small web application prototype for the last few days. In my opinion, user interface is very important, even in the early stages of development. After all, users care about what they see, not about the soundness of the internal architecture (although I do). So I tried to make my prototype look very much like the final application, which has, among other things, multiple-column HTML forms.&lt;br /&gt;&lt;br /&gt;As we all know, &lt;a href="http://www.hotdesign.com/seybold"&gt;using tables for layout is stupid&lt;/a&gt;, so my tabular forms would clearly require some CSS trickery.&lt;br /&gt;&lt;br /&gt;I had heard about the &lt;a href="http://960.gs"&gt;960 grid system&lt;/a&gt; a while ago, and decided to give it a try. But I quickly realized that it was not the right tool for the job: 960gs was designed to handle the global layout of the page (header, menu, main body, etc.), not the low-level details of the page's content. (Note that it is not a criticism of 960gs, &lt;i&gt;I&lt;/i&gt; was the one who misused it).&lt;br /&gt;&lt;br /&gt;After some more research, I came across this excellent online tutorial: &lt;a href="http://www.sitepoint.com/article/fancy-form-design-css"&gt;Fancy Form Design Using CSS&lt;/a&gt;. It is a step-by-step explanation of how to properly design table-free, accessible forms. The key points are: use &lt;tt&gt;&amp;lt;fieldset&amp;gt;&lt;/tt&gt; and &lt;tt&gt;&amp;lt;label&amp;gt;&lt;/tt&gt; tags, and put your fields in an ordered list formatted with CSS styles.&lt;br /&gt;&lt;br /&gt;My multiple-column forms build on this solution, separating the &lt;tt&gt;clear:left;&lt;/tt&gt; property in a specific class, that I use to mark only the first field of each line.&lt;br /&gt;&lt;br /&gt;This tutorial is also part of a book called &amp;quot;The Art and Science of CSS&amp;quot;. However, according to &lt;a href="http://www.amazon.com/Art-Science-CSS-Jonathan-Snook/product-reviews/0975841971/ref=cm_cr_dp_hist_3?ie=UTF8&amp;showViewpoints=0&amp;filterBy=addThreeStar"&gt;this amazon.com review&lt;/a&gt;, a lot its information was already covered in other books.&lt;br /&gt;&lt;br /&gt;See for yourself. As for me, the online tutorial was an interesting find.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-866179135113284905?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/866179135113284905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=866179135113284905' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/866179135113284905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/866179135113284905'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2009/03/html-forms-way-god-intented.html' title='HTML forms the way God intented'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-282945887966553071</id><published>2009-02-27T23:09:00.006+01:00</published><updated>2010-01-16T10:55:35.760+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java generics'/><title type='text'>An application of typesafe heterogeneous containers</title><content type='html'>One of our customers is a bit reluctant to use open source frameworks. This means we often find ourselves reinventing the wheel (making sure it's not of the square variety).&lt;br /&gt;&lt;br /&gt;Today I was back to implementing an abstract factory to provide DAOs. This was a nice opportunity to put into practice the &lt;i&gt;typesafe heterogeneous container&lt;/i&gt; pattern described in item 29 of &lt;a href="http://www.amazon.com/gp/product/0321356683?ie=UTF8&amp;tag=outprintln-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0321356683"&gt;Effective Java (2nd Edition)&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=outprintln-20&amp;l=as2&amp;o=1&amp;a=0321356683" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;.&lt;br /&gt;&lt;br /&gt;Here is the signature of the factory method (where &lt;tt&gt;Dao&lt;/tt&gt; is a base interface implemented by all DAOs):&lt;pre&gt;public &amp;lt;T extends Dao&amp;gt; T getDao(Class&amp;lt;T&amp;gt; daoInterface);&lt;/pre&gt;To request a DAO implementation, the client code passes the interface it must implement. Assuming &lt;tt&gt;UserDao&lt;/tt&gt; defines the contract for user-related data access:&lt;pre&gt;UserDao dao = factory.getDao(UserDao.class);&lt;/pre&gt;The beauty of this pattern lies in the type safety provided by the generic type system: if the DAO is stored under the key &lt;tt&gt;UserDao.class&lt;/tt&gt;, the returned type &lt;i&gt;has&lt;/i&gt; to be an instance of this type. On the contrary, the program will fail at compile time.&lt;br /&gt;&lt;br /&gt;Here is how you would back the factory with a map:&lt;pre&gt;private final Map&amp;lt;Class&amp;lt;? extends Dao&amp;gt;, Dao&amp;gt; daos =&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new HashMap&amp;lt;Class&amp;lt;? extends Dao&amp;gt;, Dao&amp;gt;();&lt;br /&gt;&lt;br /&gt;@Override&lt;br /&gt;public &amp;lt;T extends Dao&amp;gt; T getDao(Class&amp;lt;T&amp;gt; daoInterface) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return daoInterface.cast(daos.get(daoInterface));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private &amp;lt;T extends Dao&amp;gt; void addDao(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Class&amp;lt;T&amp;gt; daoInterface,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;T implementation)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.daos.put(daoInterface, implementation);&lt;br /&gt;}&lt;/pre&gt;In this case, I don't need to use a thread-safe &lt;tt&gt;Map&lt;/tt&gt; implementation, because the factory is effectively immutable: the map is filled at instantiation time in the constructor, and can never be modified after that (note that &lt;tt&gt;addDao&lt;/tt&gt; is private).&lt;br /&gt;&lt;br /&gt;For more details about how the above implementation works and ensures type safety, refer to the book (I'm not going to plagiarize the whole item after all).&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;Update 16/01/2010&lt;/i&gt;&lt;/b&gt;: this eventually turned into a more general factory &amp;mdash;not just for DAOs&amp;mdash;, very similar to Google Guice (I would have used Guice if not for my customer's restrictions).&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://www.assoc-amazon.com/s/link-enhancer?tag=outprintln-20&amp;o=1"&gt;&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;noscript&gt;&lt;br /&gt;    &lt;img src="http://www.assoc-amazon.com/s/noscript?tag=outprintln-20" alt="" /&gt;&lt;br /&gt;&lt;/noscript&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-282945887966553071?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/282945887966553071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=282945887966553071' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/282945887966553071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/282945887966553071'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2009/02/application-of-typesafe-heterogeneous.html' title='An application of typesafe heterogeneous containers'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-1477970368261802157</id><published>2009-02-26T22:22:00.024+01:00</published><updated>2009-03-12T13:14:25.987+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='wicket'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Wicket / Swarm / Spring Security How-to</title><content type='html'>This post explains how to integrate Wicket and Spring Security. It is based on &lt;a href="http://wicketstuff.org/confluence/display/STUFFWIKI/Swarm+and+Acegi+HowTo"&gt;an older article&lt;/a&gt; in the Wicket Stuff wiki (not written by me), which covered the now deprecated Acegi. I've rewritten my own prototype, using recent versions of the frameworks. The complete source is available &lt;a href="http://outprinltn.googlepages.com/wicket-springsec.zip"&gt;here&lt;/a&gt;.&lt;br/&gt;&lt;br /&gt;&lt;h3&gt;About the frameworks&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://wicket.apache.org/"&gt;Apache Wicket&lt;/a&gt; is an open-source web application framework for the Java platform. This example uses version &lt;b&gt;1.4-rc2&lt;/b&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://wicketstuff.org/confluence/display/STUFFWIKI/Wicket-Security"&gt;Wicket-Security&lt;/a&gt; is an extension of Wicket. It consists in:&lt;b&gt; WASP&lt;/b&gt; (Wicket Abstract Security Platform), an API that allows individual Wicket components (pages, links, form widgets, etc.) to do their own authentication and/or authorization checks; and &lt;b&gt;SWARM&lt;/b&gt;, the default implementation of WASP. This example uses version &lt;b&gt;1.4-SNAPSHOT&lt;/b&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://static.springframework.org/spring-security/site/"&gt;Spring Security&lt;/a&gt; (formerly Acegi) is a framework to secure enterprise applications developed using the Spring framework. This example uses version &lt;b&gt;2.0.4&lt;/b&gt;, which depends on Spring &lt;b&gt;2.0.8&lt;/b&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Why use Spring Security &lt;u&gt;AND&lt;/u&gt; Swarm?&lt;/h3&gt;&lt;br /&gt;Assuming your web application uses both Wicket and Spring, their respective security frameworks complement each other nicely: &lt;ul&gt;&lt;li&gt;Swarm provides fine-grained authorizations for your Wicket pages and components; for example, if you want a link to be active only when the user has certain privileges. But if you need to secure non-Wicket web resources (for instance, web services), you can use Spring Security's URL-based filtering.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Swarm has an API to perform authentication, but does not provide authentication modules out of the box. On the other hand, Spring Security has a number of &lt;i&gt;Authentication Providers&lt;/i&gt; for common authentication sources: DAO-based, LDAP directory, OpenId... (see chapter III of the &lt;a href="http://static.springframework.org/spring-security/site/reference/html/springsecurity.html"&gt;online manual&lt;/a&gt;).&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Spring Security has powerful mechanisms to secure the business side: annotation-based method autorizations and domain object security.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;About the example&lt;/h3&gt;&lt;br /&gt;The example application aims at illustrating various aspects of security, while staying as simple as possible:&lt;ul&gt;&lt;li&gt;it defines two roles (&lt;tt&gt;ROLE_ADMIN&lt;/tt&gt; and &lt;tt&gt;ROLE_USER&lt;/tt&gt;), and two users (&lt;tt&gt;admin&lt;/tt&gt;, who has both roles, and &lt;tt&gt;user&lt;/tt&gt;, who only has &lt;tt&gt;ROLE_USER&lt;/tt&gt;).&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;authentication is performed by a Spring Security Authentication Provider.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;a successful login redirects to a page displaying the user's name and roles. This page also has an administration panel only displayed for, er... administrators.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;finally, we use a business service. As it returns a very strategical piece of information, its use is reserved to administrators. The administration panel displays the result of a call to the service.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Getting started: configuring Spring Security&lt;/h3&gt;&lt;br /&gt;We bootstrap the Wicket application with the standard Maven 2 Archetype, as described in &lt;a href="http://wicket.apache.org/quickstart.html"&gt;QuickStart&lt;/a&gt;.&lt;br&gt;&lt;br /&gt;Our Spring Security configuration is directly inspired by the framework's tutorial sample. Apart from declaring the dependencies in the POM, we add a few elements to &lt;b&gt;&lt;tt&gt;WEB-INF/web.xml&lt;/tt&gt;&lt;/b&gt;:&lt;ul&gt;&lt;li&gt;the listener to load the Spring Security context:&lt;pre&gt;&amp;lt;context-param&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;param-value&amp;gt;/WEB-INF/applicationContext-security.xml&amp;lt;/param-value&amp;gt;&lt;br&gt;&amp;lt;/context-param&amp;gt;&lt;br&gt;...&lt;br&gt;&amp;lt;listener&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;listener-class&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;org.springframework.web.context.ContextLoaderListener&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/listener-class&amp;gt;&lt;br&gt;&amp;lt;/listener&amp;gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;and the Spring security filter (the mapping must appear &lt;i&gt;before&lt;/i&gt; the Wicket filter's):&lt;pre&gt;&amp;lt;filter&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;filter-name&amp;gt;springSecurityFilterChain&amp;lt;/filter-name&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;filter-class&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;org.springframework.web.filter.DelegatingFilterProxy&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/filter-class&amp;gt;&lt;br&gt;&amp;lt;/filter&amp;gt;&lt;br&gt;...&lt;br&gt;&amp;lt;filter-mapping&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;filter-name&amp;gt;springSecurityFilterChain&amp;lt;/filter-name&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;br&gt;&amp;lt;/filter-mapping&amp;gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In &lt;b&gt;&lt;tt&gt;WEB-INF/applicationContext-security.xml&lt;/tt&gt;&lt;/b&gt;, we configure the Spring context used for security. This is done in a very concise and expressive manner thanks to Spring's &lt;i&gt;namespace configuration&lt;/i&gt; feature:&lt;ul&gt;&lt;li&gt;the snippet below will create the beans necessary for the security filter. Note that we tell Spring Security not to secure any URL, since this will be taken care of by Swarm. Of course, if we had to protect web resources other than those served by Wicket, we would need a way to distinguish those URLs (different prefix / extension...) and a finer-grained configuration here.&lt;pre&gt;&amp;lt;http auto-config="true"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;intercept-url pattern="/**"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;access="IS_AUTHENTICATED_ANONYMOUSLY" /&amp;gt;&lt;br&gt;&amp;lt;/http&amp;gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;for simplicity's sake, we use the in-memory authentication provider, which lets us define users and roles directly in the configuration:&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;lt;authentication-provider&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;user-service&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;user name="admin" password="admin"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;authorities="ROLE_ADMIN, ROLE_USER" /&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;user name="user" password="user" authorities="ROLE_USER" /&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/user-service&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/authentication-provider&amp;gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;finally, the following line enables &lt;tt&gt;@Secured&lt;/tt&gt; annotation support:&lt;pre&gt;&amp;lt;global-method-security secured-annotations="enabled" /&amp;gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;We can immediately take advantage of that last point in our business service (which, by the way, is a dummy implementation):&lt;br /&gt;&lt;pre&gt;public class AdminService {&lt;br&gt;&amp;nbsp;&lt;b&gt;@Secured("ROLE_ADMIN")&lt;/b&gt;&lt;br&gt;&amp;nbsp;public int getResult() {&lt;br&gt;&amp;nbsp;&amp;nbsp;return 42;&lt;br&gt;&amp;nbsp;}&lt;br&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Making our Wicket Application a Swarm application&lt;/h3&gt;&lt;br /&gt;As explained in &lt;a href="http://wicketstuff.org/confluence/display/STUFFWIKI/Getting+started+with+Swarm"&gt;Getting started with Swarm&lt;/a&gt;, the easiest way to do this is by extending &lt;tt&gt;SwarmWebApplication&lt;/tt&gt;:&lt;pre&gt;public class WicketSpringSecApplication extends SwarmWebApplication&lt;/pre&gt;This requires implementing three new methods. &lt;tt&gt;getHiveKey()&lt;/tt&gt;and &lt;tt&gt;setupHive()&lt;/tt&gt; are detailed in the page linked above, so I'll let you refer to it. The third one simply specifies our login page:&lt;br /&gt;&lt;pre&gt;public Class&amp;lt;LoginPage&amp;gt; getLoginPage() {&lt;br&gt;&amp;nbsp;&amp;nbsp;return LoginPage.class;&lt;br&gt;}&lt;/pre&gt;The login page contains a form, which &lt;tt&gt;onSubmit()&lt;/tt&gt; method will call the Wasp API for authentication (more on this later), and redirect to the home page if it is successful.&lt;br/&gt;&lt;br /&gt;&lt;h3&gt;Connecting Swarm authentication to the Spring Security provider&lt;/h3&gt;&lt;br /&gt;Time to bridge the gap between the two security frameworks. First of all, a bit of terminology:&lt;ul&gt;&lt;li&gt;with Swarm, you pass a throw-away instance of a subclass of&lt;tt&gt;&lt;b&gt;LoginContext&lt;/b&gt;&lt;/tt&gt; to &lt;b&gt;&lt;tt&gt;WaspSession.login()&lt;/tt&gt;&lt;/b&gt;, and get a &lt;b&gt;&lt;tt&gt;Subject&lt;/tt&gt;&lt;/b&gt; in return.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;with Spring Security, you pass an &lt;tt&gt;&lt;b&gt;AbstractAuthenticationToken&lt;/b&gt;&lt;/tt&gt; to an &lt;b&gt;&lt;tt&gt;AuthenticationManager&lt;/tt&gt;&lt;/b&gt;, and get an &lt;tt&gt;&lt;b&gt;Authentication&lt;/b&gt;&lt;/tt&gt; object in return.&lt;/li&gt;&lt;/ul&gt;We need a couple of adapter classes to make all this work together. They can be found in the package &lt;tt&gt;com.example.wicketspringsec.security.spring&lt;/tt&gt;:&lt;ul&gt;&lt;li&gt;&lt;b&gt;&lt;tt&gt;SpringSecuritySubject&lt;/tt&gt;&lt;/b&gt; is a &lt;tt&gt;Subject&lt;/tt&gt; implementation that can be constructed from an &lt;tt&gt;Authentication&lt;/tt&gt;. In other words, it translates Spring Security's response to something Wasp understands. I won't detail the code here, it's just a matter of converting the list of roles (&lt;tt&gt;GrantedAuthority&lt;/tt&gt;s to &lt;tt&gt;Subject&lt;/tt&gt;s). If you look at the source right now, you'll see that I introduced a custom &lt;tt&gt;NamedSubject&lt;/tt&gt; interface; that's just an implementation detail, to which I'll come back later.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&lt;b&gt;&lt;tt&gt;SpringSecurityLoginContext&lt;/tt&gt;&lt;/b&gt; is a Swarm &lt;tt&gt;LoginContext&lt;/tt&gt; that delegates authentication to Spring Security. The core logic is resumed in these 3 lines of the &lt;tt&gt;login()&lt;/tt&gt; method (I'll explain how we get the &lt;tt&gt;authenticationManager&lt;/tt&gt; instance in just a minute):&lt;pre&gt;Authentication authResult = authenticationManager.authenticate(token);&lt;br&gt;[...]&lt;br&gt;NamedSubject wicketSubject = new SpringSecuritySubject(authResult);&lt;br&gt;[...]&lt;br&gt;return wicketSubject;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;to be completely generic, we designed &lt;tt&gt;SpringSecurityLoginContext&lt;/tt&gt; to be constructed from an &lt;tt&gt;AbstractAuthenticationToken&lt;/tt&gt;. As our sample application uses form authentication, we define a simple subclass that takes just a login and a password: &lt;b&gt;&lt;tt&gt;SpringSecurityUsernamePasswordLoginContext&lt;/tt&gt;&lt;/b&gt;.&lt;/li&gt;&lt;/ul&gt;So how do we get hold of the &lt;tt&gt;AuthenticationManager&lt;/tt&gt; reference needed to perform authentication? Since we used namespace configuration in &lt;tt&gt;WEB-INF/applicationContext-security.xml&lt;/tt&gt;, the Spring bean's ID not directly visible. Fortunately, the namespace provides us an element to create an alias to the bean:&lt;br /&gt;&lt;pre&gt;&amp;lt;authentication-manager alias="authenticationManager" /&amp;gt;&lt;/pre&gt;To make this bean easily accessible from our custom security classes, we're going to inject it in the Wicket &lt;tt&gt;Application&lt;/tt&gt; object. We start by making this object a Spring bean. To keep this separate from the security configuration, we do this in a new file &lt;b&gt;&lt;tt&gt;WEB-INF/applicationContext.xml&lt;/tt&gt;&lt;/b&gt; (which needs to be added to the &lt;tt&gt;contextConfigLocation&lt;/tt&gt; parameter in &lt;tt&gt;WEB-INF/web.xml&lt;/tt&gt;):&lt;pre&gt;&amp;lt;bean id="wicketApplication"&lt;br/&gt;&amp;nbsp;&amp;nbsp; class="com.example.wicketspringsec.ui.WicketSpringSecApplication"/&amp;gt;&lt;/pre&gt; For Wicket to find this bean, we need to go once again to &lt;tt&gt;WEB-INF/web.xml&lt;/tt&gt;&lt;br /&gt;and change the declaration of the Wicket filter to use &lt;b&gt;&lt;tt&gt;SpringWebApplicationFactory&lt;/tt&gt;&lt;/b&gt;:&lt;pre&gt;&amp;lt;filter&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;filter-name&amp;gt;wicket-springsec&amp;lt;/filter-name&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;filter-class&amp;gt;org.apache.wicket.protocol.http.WicketFilter&amp;lt;/filter-class&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;init-param&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;param-name&amp;gt;applicationFactoryClassName&amp;lt;/param-name&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;param-value&amp;gt;org.apache.wicket.spring.SpringWebApplicationFactory&amp;lt;/param-value&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/init-param&amp;gt;&lt;br&gt;&amp;lt;/filter&amp;gt;&lt;/pre&gt;&lt;br /&gt;Finally, we inject &lt;tt&gt;authenticationManager&lt;/tt&gt; in &lt;tt&gt;wicketApplication&lt;/tt&gt;(after defining the appropriate getter and setter in the Java class):&lt;br /&gt;&lt;pre&gt;&amp;lt;bean id="wicketApplication"&lt;br&gt;&amp;nbsp;&amp;nbsp;class="com.example.wicketspringsec.ui.WicketSpringSecApplication"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;lt;property name="authenticationManager" ref="authenticationManager" /&amp;gt;&lt;br&gt;&amp;lt;/bean&amp;gt;&lt;/pre&gt;Back to our custom &lt;tt&gt;SpringSecurityLoginContext&lt;/tt&gt;; we can now get the reference of the authentication manager through the application:&lt;br /&gt;&lt;pre&gt;AuthenticationManager authenticationManager = WicketSpringSecApplication&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.get().getAuthenticationManager();&lt;/pre&gt; One last detail: since we will also use Spring Security for certain authorizations, it must be notified of user login and logoff. We do this in the method &lt;tt&gt;SpringSecurityLoginContext.setAuthentication(Authentication)&lt;/tt&gt;.&lt;br&gt;&lt;br /&gt;That's it! There were a lot of details to handle, but our custom Swarm login context is finally ready. It is invoked from the login page (in &lt;tt&gt;LoginPage.LoginForm.onSubmit()&lt;/tt&gt;):&lt;pre&gt;LoginContext context = new SpringSecurityUsernamePasswordLoginContext(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;username.getModelObject(), password.getModelObject());&lt;br&gt;try {&lt;br&gt;&amp;nbsp;&amp;nbsp;((WaspSession) getSession()).login(context);&lt;br&gt;&amp;nbsp;&amp;nbsp;...&lt;/pre&gt;&lt;h3&gt;The user interface&lt;/h3&gt;&lt;br /&gt;As I said earlier, the main page displays information about the user's name and roles. This information is stored in the typical Wicket way: as a property in a custom &lt;tt&gt;WebSession&lt;/tt&gt; implementation. We call this class &lt;b&gt;&lt;tt&gt;WicketSpringSecSession&lt;/tt&gt;&lt;/b&gt;, and in our case it must extend &lt;tt&gt;WaspSession&lt;/tt&gt; (don't forget this, or security won't work anymore). In &lt;tt&gt;WicketSpringSecApplication&lt;/tt&gt;, we override &lt;tt&gt;newSession&lt;/tt&gt; to return the new implementation. In &lt;tt&gt;SpringSecurityLoginContext&lt;/tt&gt;, we update this information after a successful login.&lt;br&gt;&lt;br /&gt;Instead of creating a new object to hold the information, I chose to reuse the &lt;tt&gt;Subject&lt;/tt&gt;, adding username support to it (hence the &lt;tt&gt;NamedSubject&lt;/tt&gt; interface). This is probably a bad practice, as it gives programmatic access to the user's roles from the webapp components. A convenient shortcut in the context of this prototype, but a real application would probably need to do better.&lt;br&gt;&lt;br /&gt;The last part to implement is the administration panel, aptly named &lt;b&gt;&lt;tt&gt;AdminPanel&lt;/tt&gt;&lt;/b&gt;. The Java class extends &lt;tt&gt;SecurePanel&lt;/tt&gt;, an authorization-aware version of &lt;tt&gt;Panel&lt;/tt&gt;. It just contains a &lt;tt&gt;Label&lt;/tt&gt; that displays the admin service's result (we inject the service in the Wicket application object like we did for &lt;tt&gt;authenticationManager&lt;/tt&gt;). You may be tempted to call the service directly from the label's constructor:&lt;pre&gt;this.add(new Label("adminServiceResult", String.valueOf(WicketSpringSecApplication.get()&lt;br&gt;    .getAdminService().getResult()));&lt;/pre&gt;But that wouldn't work: every time the page is constructed, the panel is also constructed, even if it is not actually rendered. That would mean calling the admin service when a normal users accesses the page, which will throw an exception since the service is secured on the business side. The workaround is to build the label with a separate &lt;tt&gt;Model&lt;/tt&gt; instance, which calls the service in its &lt;tt&gt;getObject()&lt;/tt&gt; method. This method will not be invoked unless the label is actually rendered.&lt;br/&gt;&lt;br /&gt;&lt;h3&gt;The hive configuration file&lt;/h3&gt;&lt;br /&gt;The Swarm authorizations are defined in the file &lt;b&gt;&lt;tt&gt;WEB-INF/wicket-springsec.hive&lt;/tt&gt;&lt;/b&gt;. We give access to the home page to all users, but filter the administration panel (&lt;i&gt;I had to add line breaks for blogger to display this correctly, refer to the source for the exact syntax&lt;/i&gt;):&lt;pre&gt;grant principal org.apache.wicket.security.hive.authorization.SimplePrincipal&lt;br/&gt;"ROLE_USER"&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;permission ${ComponentPermission} "com.example.wicketspringsec.ui.HomePage", "render";&lt;br&gt;&amp;nbsp;&amp;nbsp;permission ${ComponentPermission} "com.example.wicketspringsec.ui.HomePage", "enable";&lt;br&gt;};&lt;br&gt;&lt;br&gt;grant principal org.apache.wicket.security.hive.authorization.SimplePrincipal&lt;br/&gt;"ROLE_ADMIN"&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;permission ${ComponentPermission}&lt;br/&gt; "com.example.wicketspringsec.ui.HomePage:adminPanel","render";&lt;br&gt;};&lt;/pre&gt;On a sidenote, I used the &lt;tt&gt;${ComponentPermission}&lt;/tt&gt; alias in the example for conciseness, but it doesn't work for me :-( I have to use the full name &lt;tt&gt;org.apache.wicket.security.hive.authorization.permissions.ComponentPermission&lt;/tt&gt;.&lt;br /&gt;&lt;hr/&gt;&lt;b&gt;&lt;i&gt;Update 2009/03/12: &lt;/i&gt;&lt;/b&gt;those interested in securing Wicket applications should also be aware that there is an alternative to Wicket-Security, called wicket-auth-roles. &lt;a href="http://osdir.com/ml/users-wicket.apache.org/2009-02/msg01110.html"&gt;This thread&lt;/a&gt; will give you a good overview of the status of the two frameworks. Integrating wicket-auth-roles with Spring Security is covered &lt;a href="http://cwiki.apache.org/WICKET/spring-security-and-wicket-auth-roles.html"&gt;here&lt;/a&gt;.&lt;br /&gt;One compelling feature of wicket-auth-roles is the ability to configure authorizations with Java annotations. I find it somehow more elegant than a centralized configuration file. There is an example &lt;a href="http://wicketstuff.org/wicket13/authorization/"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-1477970368261802157?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/1477970368261802157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=1477970368261802157' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/1477970368261802157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/1477970368261802157'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2009/02/wicket-swarm-spring-security-how-to.html' title='Wicket / Swarm / Spring Security How-to'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7524162926732063545.post-580941771356027844</id><published>2008-10-21T14:14:00.008+02:00</published><updated>2009-03-17T21:31:41.800+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven modules with independent versions</title><content type='html'>&lt;a href="http://www.sonatype.com/book/reference/multimodule.html"&gt;Examples of Maven multi-module projects&lt;/a&gt; generally assume that all modules share the same version. However, there are scenarios where a set of modules are too independent to have a common version, yet not independent enough to be completely separate projects. This post presents such a scenario, and proposes a mechanism to handle it.&lt;br /&gt;&lt;br /&gt;Let's consider an application with a basic structure: a webapp module and a business service module. However, &lt;b&gt;these two modules are not packaged together: the webapp module will be deployed on machine A, and the service module on machine B&lt;/b&gt; (the webapp will access the services remotely).&lt;br /&gt;&lt;br /&gt;The Maven projects are structured like this (red arrows denote a "depends-on" relationship):&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_acCbCYrl2jE/SP3ILWpFVGI/AAAAAAAAAGM/dwFQ9noYscA/s1600-h/projects.jpg"&gt;&lt;img src="http://2.bp.blogspot.com/_acCbCYrl2jE/SP3ILWpFVGI/AAAAAAAAAGM/dwFQ9noYscA/s320/projects.jpg" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_acCbCYrl2jE/SP3ILWpFVGI/AAAAAAAAAGM/dwFQ9noYscA/s320/projects.jpg" alt="" id="BLOGGER_PHOTO_ID_5259580037220619362" border="0" /&gt;&lt;/a&gt;We followed the best practice of decoupling the service API (interfaces, value objects...) from its implementation. We also created a parent POM to hold common information, for instance a &lt;tt&gt;dependencyManagement&lt;/tt&gt; section defining the versions of external dependencies.&lt;br /&gt;&lt;br /&gt;In a classical multi-module structure, &lt;tt&gt;webapp&lt;/tt&gt;, &lt;tt&gt;service-api&lt;/tt&gt; and &lt;tt&gt;service-impl&lt;/tt&gt; are modules of &lt;tt&gt;parent&lt;/tt&gt;. A common version is defined in &lt;tt&gt;parent&lt;/tt&gt;'s POM and inherited downwards. Internal dependencies are typically expressed with &lt;tt&gt;${project.version}&lt;/tt&gt;. Everytime we need a new version, the &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/"&gt;release plugin&lt;/a&gt; lets us update all the modules simultaneously.&lt;br /&gt;The problem is that our modules can evolve independently: suppose our next version only consists in graphical changes. &lt;tt&gt;webapp&lt;/tt&gt; is the only impacted module, but we have to perform a global release to version 1.0.1. We deliver our 1.0.1 artifacts to the production guys, but they don't agree: if the business module wasn't impacted, why go through the costly process of a full redeploy? So we decide to only redeploy &lt;tt&gt;webapp:1.0.1&lt;/tt&gt; in production, and leave &lt;tt&gt;service-impl:1.0.0&lt;/tt&gt; in place.&lt;br /&gt;But something doesn't feel right: &lt;tt&gt;webapp:1.0.1&lt;/tt&gt; depends on version 1.0.1 of &lt;tt&gt;service-api&lt;/tt&gt;, while  the  version &lt;tt&gt;service-impl:1.0.0&lt;/tt&gt; really implements is 1.0.0. Of course, we know that the API hasn't changed between the two versions, but this is purely based on our functional knowledge of the project. Multiply this by many versions and many modules, and tracking what must be redeployed and what can stay in a previous version becomes complex. A mistake can result in marshalling errors at runtime (hopefully detected during testing).&lt;br /&gt;&lt;br /&gt;The next logical solution is to manage each module as an independent project with its own version. Now &lt;tt&gt;webapp:1.0.1&lt;/tt&gt; can be released independently, but that doesn't solve all of our issues: we still have to make sure it depends on the right version of &lt;tt&gt;service-api&lt;/tt&gt; (the one the service in production will implement). We can track these target versions ourselves, but once again this is a manual process. Nothing in the build safeguards us from accidentally releasing &lt;tt&gt;webapp:1.0.1&lt;/tt&gt; with a wrong version of &lt;tt&gt;service-api&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;What we need is a way to express the cohesive set of versions our system will be composed of, and enforce these versions in all internal dependencies; a way to say: "the system currently consists in &lt;tt&gt;webapp:1.0.1&lt;/tt&gt;, &lt;tt&gt;service-api:1.0.0&lt;/tt&gt; and &lt;tt&gt;service-impl:1.0.0&lt;/tt&gt;. Therefore &lt;tt&gt;webapp:1.0.1&lt;/tt&gt; must depend on &lt;tt&gt;service-api:1.0.0&lt;/tt&gt;".&lt;br /&gt;&lt;br /&gt;A first idea is to declare all the module versions as properties in the parent POM, and use these properties throughout the project. But that doesn't work either: everytime we change one of these properties, we would need to release a new version of the parent POM; to take this new version into account, we'd have to change all the modules. Therefore they wouldn't be independent.&lt;br /&gt;&lt;br /&gt;The trick is to let the modules define their versions freely, but to add a new module to check consistency. We make a few structural changes to our multi-module project (blue arrows denote "has-module" relationships):&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_acCbCYrl2jE/SP3IjxZMSZI/AAAAAAAAAGU/IeegX1zt9Rk/s1600-h/solution.jpg"&gt;&lt;img src="http://3.bp.blogspot.com/_acCbCYrl2jE/SP3IjxZMSZI/AAAAAAAAAGU/IeegX1zt9Rk/s320/solution.jpg" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_acCbCYrl2jE/SP3IjxZMSZI/AAAAAAAAAGU/IeegX1zt9Rk/s320/solution.jpg" alt="" id="BLOGGER_PHOTO_ID_5259580456718584210" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Don't panic :-) We only added two POMs:&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;global&lt;/tt&gt; is just a convenience to make building the whole project easier. It is an aggregate POM that declares all the other projects as modules, but they don't inherit from it. Therefore, it doesn't impose any version or dependency to itself (in fact, the modules don't know anything about &lt;tt&gt;global&lt;/tt&gt;). On the filesystem, we put &lt;tt&gt;global&lt;/tt&gt;'s POM in the root directory and use a flat structure for the other modules:&lt;br /&gt;&lt;pre&gt;pom.xml (global)&lt;br /&gt;[-] delivery&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\- pom.xml&lt;br /&gt;[-] parent&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\- pom.xml&lt;br /&gt;[+] service-api&lt;br /&gt;[+] service-impl&lt;br /&gt;[+] webapp&lt;/pre&gt;&lt;tt&gt;delivery&lt;/tt&gt; is our way of describing the system as a whole. In this POM, we add a dependency to every other module, in the version this module is expected to have in the target environment. To check the consistency of the system, we use a custom mojo, binded to the &lt;tt&gt;initialize&lt;/tt&gt; phase. This mojo analyzes the dependencies between the modules, and checks that they conform to the base versions defined in &lt;tt&gt;delivery&lt;/tt&gt;'s POM.&lt;br /&gt;For instance, to describe the previous example, we put the following dependencies in &lt;tt&gt;delivery&lt;/tt&gt;'s POM: &lt;tt&gt;webapp:1.0.1&lt;/tt&gt;, &lt;tt&gt;service-api:1.0.0&lt;/tt&gt;, &lt;tt&gt;service-impl:1.0.0&lt;/tt&gt;, and &lt;tt&gt;parent:1.0.0&lt;/tt&gt;. The mojo checks the declared dependencies of &lt;tt&gt;webapp:1.0.1&lt;/tt&gt; and finds a dependency to &lt;tt&gt;service-api&lt;/tt&gt;; if the version of this dependency is not 1.0.0, the build fails, because our webapp depends on the wrong implementation of the service.&lt;br /&gt;&lt;br /&gt;Additionally, we can use the following convention: since &lt;tt&gt;delivery&lt;/tt&gt;'s version will evolve for each release, we consider this version to be the "global" version of the system. When any other module is impacted, it will "jump" to the global version, whatever its previous version was. This simplifies identifying the contents of a partial delivery.&lt;br /&gt;&lt;br /&gt;Here is an illustrative scenario:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;in the first version, all the projects have version 1.0.0. Everything is delivered.&lt;/li&gt;   &lt;li&gt;the next version (&lt;tt&gt;delivery:1.0.1&lt;/tt&gt;) consists in graphical changes. &lt;tt&gt;webapp&lt;/tt&gt; needs to be modified, so it is raised to 1.0.1 (we also update the corresponding dependency in &lt;tt&gt;delivery&lt;/tt&gt;'s POM). We run the global build and don't get any errors. We do a partial redeploy of all deliverables in version 1.0.1, in that case only &lt;tt&gt;webapp&lt;/tt&gt;.&lt;/li&gt;   &lt;li&gt;the next version (&lt;tt&gt;delivery:1.0.2&lt;/tt&gt;) is a bugfix in the service implementation, without any impact to the API. &lt;tt&gt;service-impl&lt;/tt&gt; needs to be modified, so it "jumps" from 1.0.0 to 1.0.2. The global build is successful, therefore we do a partial redeploy of &lt;tt&gt;service-impl:1.0.2&lt;/tt&gt;.&lt;/li&gt;   &lt;li&gt;the next version (&lt;tt&gt;delivery:1.0.3&lt;/tt&gt;) is a change to the service, which, this time, impacts the API. The business modules are impacted: &lt;tt&gt;service-impl&lt;/tt&gt; is raised to 1.0.3, and &lt;tt&gt;service-api&lt;/tt&gt; jumps from 1.0.0 to 1.0.3. But we forgot to reflect that change in the webapp. When we run the global build, the mojo fails:&lt;/li&gt; &lt;/ul&gt; &lt;tt&gt;[INFO] [delivery:check-version-consistency {execution: check-version-consistency&lt;br /&gt;}]&lt;br /&gt;[ERROR] Inconsistency in versions: com.acme:webapp:jar uses com.acme:service-api&lt;br /&gt;:jar in version 1.0.0, but in delivery the reference version is defined as 1.0.3&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;We realize that &lt;tt&gt;webapp&lt;/tt&gt; is also impacted, and therefore must be raised to 1.0.3. This time we'll need a full redeploy of both the business and the presentation modules.&lt;br /&gt;&lt;br /&gt;This project structure fulfills our requirements:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;modules can be released independently. A module that hasn't been impacted can stay as-is in production.&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;we have a way to describe our system as a cohesive set of modules in definite versions. A look at &lt;tt&gt;delivery&lt;/tt&gt;'s dependencies gives us a clear view of the current situation.&lt;/li&gt;   &lt;li&gt;we have a way to enforce these versions throughout the project. The mojo will detect dependencies that don't honor this global contract. This also serves as a dependency analysis to detect the impacts of a change to a module.&lt;/li&gt; &lt;/ul&gt; Here is a &lt;a href="http://outprinltn.googlepages.com/maven-modules-example.zip"&gt;ZIP archive&lt;/a&gt; containing the mojo and the example.&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;&lt;b&gt;&lt;i&gt;Update 2009/03/17:&lt;/i&gt;&lt;/b&gt;  my discussion with Frank gave rise to a &lt;a href="http://out-println.blogspot.com/2009/03/follow-up-on-maven-modules-with.html"&gt;new blog post&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-580941771356027844?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/580941771356027844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=580941771356027844' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/580941771356027844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/580941771356027844'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2008/10/maven-modules-with-independent-versions.html' title='Maven modules with independent versions'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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/_acCbCYrl2jE/SP3ILWpFVGI/AAAAAAAAAGM/dwFQ9noYscA/s72-c/projects.jpg' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7524162926732063545.post-88685391085703425</id><published>2008-10-07T17:17:00.004+02:00</published><updated>2008-10-07T19:23:04.997+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='weblogic'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='scripting'/><title type='text'>Scripting Ant tasks with BSF</title><content type='html'>Today I wrote a couple of custom Ant tasks in Groovy, using the &lt;a href="http://ant.apache.org/manual/index.html"&gt;Scriptdef&lt;/a&gt; optional task. I had never used scripting languages within Ant (nor was I familiar with task development for that matter), but it proved to be really quick and straightforward.&lt;br /&gt;&lt;br /&gt;Here is a very simple example: I wanted to configure the &lt;a href="http://edocs.bea.com/wls/docs81/ConsoleHelp/deployment.html#1104924"&gt;load order&lt;/a&gt; for a Weblogic deployment, but it is not feasible with BEA's &lt;a href="http://edocs.beasys.com/wls/docs81/deployment/tools.html#1000477"&gt;wldeploy &lt;/a&gt;task. The workaround is to do it programmatically through the JMX API:&lt;br /&gt;&lt;pre&gt;&amp;lt;!-- Sets the load order on a Weblogic deployment --&amp;gt;&lt;br /&gt;&amp;lt;scriptdef name="wlSetLoadOrder" language="groovy" classpath="${weblogic.home}/server/lib/weblogic.jar"&amp;gt;&lt;br /&gt;  &amp;lt;!-- The name of the deployment --&amp;gt;&lt;br /&gt;  &amp;lt;attribute name="name" /&amp;gt;&lt;br /&gt;  &amp;lt;!-- The load order --&amp;gt;&lt;br /&gt;  &amp;lt;attribute name="loadOrder" /&amp;gt;&lt;br /&gt;  &amp;lt;!-- The admin URL of the domain --&amp;gt;&lt;br /&gt;  &amp;lt;attribute name="adminUrl" /&amp;gt;&lt;br /&gt;  &amp;lt;!-- A weblogic user with administration rights --&amp;gt;&lt;br /&gt;  &amp;lt;attribute name="user" /&amp;gt;&lt;br /&gt;  &amp;lt;!-- The user's password --&amp;gt;&lt;br /&gt;  &amp;lt;attribute name="password" /&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;    import java.util.Hashtable&lt;br /&gt;    import javax.naming.Context&lt;br /&gt;    import javax.naming.InitialContext&lt;br /&gt;    import weblogic.management.MBeanHome&lt;br /&gt;    import weblogic.management.deploy.DeployerRuntime&lt;br /&gt;    import weblogic.management.deploy.DeploymentData&lt;br /&gt;    import org.apache.tools.ant.BuildException&lt;br /&gt;&lt;br /&gt;    try {&lt;br /&gt;      int loadOrder = Integer.parseInt(attributes["loadorder"])&lt;br /&gt;      self.log("Configuring load order " + loadOrder + " for " + attributes["name"])&lt;br /&gt;&lt;br /&gt;      // Connect to the MBean server&lt;br /&gt;      def ctx = new InitialContext(new Hashtable(&lt;br /&gt;        (Context.PROVIDER_URL) : attributes["adminurl"],&lt;br /&gt;        (Context.INITIAL_CONTEXT_FACTORY) : "weblogic.jndi.WLInitialContextFactory",&lt;br /&gt;        (Context.SECURITY_PRINCIPAL) : attributes["user"],&lt;br /&gt;        (Context.SECURITY_CREDENTIALS) : attributes["password"]))&lt;br /&gt;      def adminHome = ctx.lookup(MBeanHome.ADMIN_JNDI_NAME)&lt;br /&gt;&lt;br /&gt;      // Lookup the deployment's ApplicationMBean&lt;br /&gt;      def appMBean = adminHome.getMBean(attributes["name"], "Application")&lt;br /&gt;&lt;br /&gt;      // Set the JMX attribute&lt;br /&gt;      appMBean.setLoadOrder(loadOrder)&lt;br /&gt;    } catch (NumberFormatException e) {&lt;br /&gt;      throw new BuildException("Invalid value for loadOrder: " + attributes["loadorder"])&lt;br /&gt;    }&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt;&amp;lt;/scriptdef&amp;gt;&lt;br /&gt;&lt;/pre&gt;This new task is unsurprisingly invoked like any regular Ant task:&lt;br /&gt;&lt;pre&gt;&amp;lt;wlSetLoadOrder name="myKillerApp" loadorder="200"&lt;br /&gt;  adminurl="t3://localhost:7001" user="admin" password="weblogic"&lt;br /&gt;/&amp;gt;&lt;/pre&gt;Notes:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;this works for Weblogic 8.1. I have not tried with later versions, but it can probably be easily adapted.&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;you will need to put the appropriate dependencies in Ant's classpath, namely: Groovy, Commons Logging and BSH. See &lt;a href="http://ant.apache.org/manual/install.html#librarydependencies"&gt;this page&lt;/a&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/7524162926732063545-88685391085703425?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/88685391085703425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=88685391085703425' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/88685391085703425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/88685391085703425'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2008/10/scripting-ant-tasks-with-bsf.html' title='Scripting Ant tasks with BSF'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-3274611247310746634</id><published>2008-08-06T17:19:00.002+02:00</published><updated>2008-08-06T17:21:39.573+02:00</updated><title type='text'>ZIP gotcha: you could be a few milliseconds from build failure</title><content type='html'>In Apache Ant's documentation, you will find the following notice in the &lt;a href="http://ant.apache.org/manual/CoreTasks/zip.html"&gt;description of the Zip task&lt;/a&gt;: &lt;i&gt;Please note that ZIP files store file modification times with a granularity of two seconds. If a file is less than two seconds newer than the entry in the archive, Ant will not consider it newer&lt;/i&gt;.&lt;br&gt; &lt;br&gt; I had never really paid attention to this, until I actually ran into a situation where it creates a problem: in a build script, I need to extract a deployment descriptor from a generated EAR, modify it, and rezip it in the EAR (ugly, but I really don't have any control over the generation of the EAR).&lt;br&gt; &lt;br&gt; So what had to happen happened: the interval between the generation of the EAR and the time I make my modification is less than two seconds. But, in the true spirit of Murphy's law, it is not &lt;i&gt;always&lt;/i&gt; less: on my machine and during the nightly build, it takes &lt;i&gt;slighty longer&lt;/i&gt;, which explains why I hadn't seen the problem in the first place. But when the build is run manually on the integration server, the interval suddendly becomes &lt;i&gt;slightly shorter&lt;/i&gt; than two seconds (probably due to a higher process priority), and the descriptor is not updated.&lt;br&gt; &lt;br&gt; I added an artificial two-second pause to make sure that the modified file will always be "newer enough".&lt;br&gt; &lt;br&gt; By the way, this is not specific to Ant. From &lt;a  href="http://en.wikipedia.org/wiki/ZIP_%28file_format%29#Technical_information"&gt;Wikipedia&lt;/a&gt;: &lt;i&gt;The FAT filesystem of DOS only has a timestamp resolution of two seconds; ZIP file records mimic this. As a result, the built-in timestamp resolution of files in a ZIP archive is only two seconds, though extra fields can be used to store more accurate timestamps.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-3274611247310746634?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/3274611247310746634/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=3274611247310746634' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/3274611247310746634'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/3274611247310746634'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2008/08/zip-gotcha-you-could-be-few.html' title='ZIP gotcha: you could be a few milliseconds from build failure'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-7049709344490303500</id><published>2008-03-07T18:43:00.006+01:00</published><updated>2008-03-30T15:43:55.737+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven 2, Xalan, and the evil 2.2D11 / 2.4.1 version</title><content type='html'>A few days ago, I ran into one of those frustrating situations with Maven 2: a multi-module build where each sub-project builds perfectly individually, but building from the top-level POM fails.&lt;br /&gt;&lt;br /&gt;In that particular case, Maven was trying to download the Spring JARs in a mysterious "2.2D11" version, which was not at all the one declared in my POM:&lt;br /&gt;&lt;pre&gt;Missing: ---------- 1) org.springframework:spring-beans:jar:2.2.D11&lt;br /&gt;Try downloading the file manually from the project website.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Fortunately, this was not the first time I ran into phantom dependency versions: there used to be a similar bug with the &lt;a href="http://m2eclipse.codehaus.org/"&gt;m2eclipse&lt;/a&gt; plugin, where "2.4.1" versions would sometimes inexplicably pop up in Eclipse. But, what is even more fortunate, someone &lt;a href="http://www.mail-archive.com/user@m2eclipse.codehaus.org/msg00119.html"&gt;pintpointed the problem&lt;/a&gt;:&lt;br&gt;&lt;br /&gt;&lt;i&gt;- if Java 1.4.2 is the first entry in the %PATH% on the machine, this java version will be used to run eclipse - Java 1.4.2 contains some Apache XML parser that defines, among others, a silly environment variable "version" with value "2.4.1" - m2plugin tells Maven (if I understand correctly) via Maven Embedder to evaluate dependencies - Maven Embedder has a bug (or "feature") by which variables like {project.version} are overridden by corresponding system variables (i.e. "version"). - as a result, Maven is looking for version "2.4.1" of such dependencies instead of the desired value of {project.version}, and fails to build&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;"Some Apache XML parser" is actually &lt;a  href="http://xml.apache.org/xalan-j/"&gt;Xalan-J&lt;/a&gt;. And it turns out that my project uses a custom &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-plugins.html"&gt;mojo&lt;/a&gt; that outputs an XML file using the &lt;tt&gt;javax.xml.transform.Transformer&lt;/tt&gt; interface, which is precisely what Xalan implements:&lt;br /&gt;&lt;pre&gt;   TransformerFactory transformerFactory = TransformerFactory.newInstance();&lt;br /&gt;   Transformer transformer = transformerFactory.newTransformer();&lt;br /&gt;   DOMSource source = new DOMSource(document);&lt;br /&gt;&lt;br /&gt;   StreamResult result = new StreamResult(dest);&lt;br /&gt;   transformer.transform(source, result);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I figured that if a system property called &lt;tt&gt;version&lt;/tt&gt; created the problem, removing it could be the solution. Therefore, I added the following line just after the preceding code:&lt;br /&gt;&lt;pre&gt;   System.getProperties().remove("version");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And that did the trick :-)&lt;br /&gt;&lt;br /&gt;So the bottom line is: Maven + Xalan = beware of the evil &lt;tt&gt;version&lt;/tt&gt; property...&lt;br /&gt;&lt;br /&gt;Environment:&lt;br&gt; &lt;ul&gt;   &lt;li&gt;Apache Maven 2.0.8&lt;/li&gt;   &lt;li&gt;JDK 1.4.1_05 from BEA Weblogic 8.1 SP2 (I guess that explains the different Xalan version)&lt;/li&gt;   &lt;li&gt;Windows XP&lt;br&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/7524162926732063545-7049709344490303500?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/7049709344490303500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=7049709344490303500' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/7049709344490303500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/7049709344490303500'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2008/03/maven-2-xalan-and-evil-22d11-241.html' title='Maven 2, Xalan, and the evil 2.2D11 / 2.4.1 version'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-5424316048381381834</id><published>2008-02-24T18:11:00.010+01:00</published><updated>2010-06-04T23:28:03.223+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Writing Maven POMs in Groovy</title><content type='html'>&lt;i&gt;2010/06/04 &amp;mdash; a word of caution as I see people are still finding this old post: this is an experiment I did two years ago, it has nothing to do with the new 'polyglot' features of Maven 3.&lt;/i&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;I recently came across Brett Porter's post about &lt;a href="http://blogs.exist.com/bporter/2008/02/11/maven-now-supports-condensed-poms-using-attributes/"&gt;condensing Maven's POMs using XML attributes&lt;/a&gt;. Simplifying Maven's syntax sounds like a great idea, since like a lot of people I'm a bit tired of typing all those XML tags ;-)&lt;br /&gt;&lt;br /&gt;It also turns out that I want to learn &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; better these days, so I keep a Groovy console open on my computer for my little experiments.&lt;br /&gt;&lt;br /&gt;Although unrelated, these two thoughts somehow collided in my brain, resulting in the idea of writing Maven POMs using Groovy rather than XML. I started by putting the &lt;tt&gt;maven-model&lt;/tt&gt; JAR in the Groovy console's classpath and fiddling with its classes. I quickly realized that I liked this syntax:&lt;br /&gt;&lt;pre&gt;project.dependencies =&lt;br /&gt;   [ new Dependency(groupId: 'junit', artifactId: 'junit',&lt;br /&gt;                    version: '3.8.1', scope: 'test') ]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;A lot more than this one:&lt;br /&gt;&lt;pre&gt;  &amp;lt;dependencies&amp;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;3.8.1&amp;lt;/version&amp;gt;&lt;br /&gt;     &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;&lt;br /&gt;   &amp;lt;/dependency&amp;gt;&lt;br /&gt; &amp;lt;/dependencies&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Therefore, I decided to go a bit further and integrate this to the Maven runtime. My goal was to be able to run commands like &lt;tt&gt;mvn package&lt;/tt&gt; with a &lt;tt&gt;pom.groovy&lt;/tt&gt; file instead of a &lt;tt&gt;pom.xml&lt;/tt&gt; at the root of my project. I dived into the Maven sources and came up with the following changes (NB: the links below are to the original source files in Subversion, for the modified files see the bottom of this post):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;in &lt;a href="https://svn.apache.org/repos/asf/maven/components/tags/maven-2.0.8/maven-core/src/main/java/org/apache/maven/DefaultMaven.java"&gt;DefaultMaven.java&lt;/a&gt;, I modified the methods that collect the &lt;tt&gt;pom.xml&lt;/tt&gt; and &lt;tt&gt;release-pom.xml&lt;/tt&gt; files, to support the new &lt;tt&gt;pom.groovy&lt;/tt&gt; file (which name I also declared as a constant in the interface &lt;a href="https://svn.apache.org/repos/asf/maven/components/tags/maven-2.0.8/maven-core/src/main/java/org/apache/maven/Maven.java"&gt;Maven.java&lt;/a&gt;). This new file has the least priority: if any of the XML POMs exist in the same directory, it takes precedence over the Groovy POM.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;in &lt;a href="https://svn.apache.org/repos/asf/maven/components/tags/maven-2.0.8/maven-project/src/main/java/org/apache/maven/project/DefaultMavenProjectBuilder.java"&gt;DefaultMavenProjectBuilder.java&lt;/a&gt;, I added the evaluation of the POM with a &lt;a href="http://groovy.codehaus.org/api/groovy/lang/GroovyShell.html"&gt;GroovyShell&lt;/a&gt; if the file name ends with &lt;tt&gt;.groovy&lt;/tt&gt;. This also required adding a dependency to Groovy in &lt;tt&gt;maven-project&lt;/tt&gt;'s &lt;a href="https://svn.apache.org/repos/asf/maven/components/tags/maven-2.0.8/maven-project/pom.xml"&gt;pom.xml&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;then I needed to reflect these changes to my local Maven installation. Here I must confess that I lamely ran &lt;tt&gt;mvn assembly:assembly -DdescriptorId=jar-with-dependencies&lt;/tt&gt; in the two projects I had modified, and manually merged the resulting JARs with &lt;tt&gt;maven-2.0.8-uber.jar&lt;/tt&gt;. This results in a 5 Mb &lt;tt&gt;maven-2.0.8-uber.jar&lt;/tt&gt; containing Groovy and its transitive dependencies. Probably not The Right Way&lt;span style="font-size:-1;"&gt;&lt;sup&gt;TM&lt;/sup&gt;&lt;/span&gt; to do this, but sufficient for a first test.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Speaking of testing, I started with a very simple POM generated from the standard project archetype:&lt;br /&gt;&lt;pre&gt;&amp;lt;project&amp;gt;&lt;br /&gt; &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt; &amp;lt;groupId&amp;gt;test&amp;lt;/groupId&amp;gt;&lt;br /&gt; &amp;lt;artifactId&amp;gt;test&amp;lt;/artifactId&amp;gt;&lt;br /&gt; &amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;&lt;br /&gt; &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt; &amp;lt;name&amp;gt;test&amp;lt;/name&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;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;3.8.1&amp;lt;/version&amp;gt;&lt;br /&gt;     &amp;lt;scope&amp;gt;test&amp;lt;/scope&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;And here is the Groovy equivalent in &lt;tt&gt;pom.groovy&lt;/tt&gt; (I decided that the contract for the Groovy script was to expose a variable named &lt;tt&gt;project&lt;/tt&gt;):&lt;br /&gt;&lt;pre&gt;import org.apache.maven.model.*&lt;br /&gt;&lt;br /&gt;project = new Model(&lt;br /&gt; groupId: 'test',&lt;br /&gt; artifactId: 'test',&lt;br /&gt; packaging: 'jar',&lt;br /&gt; version: '1.0-SNAPSHOT',&lt;br /&gt; name: 'test',&lt;br /&gt; modelVersion: '4.0.0')&lt;br /&gt;&lt;br /&gt;project.dependencies =&lt;br /&gt;   [ new Dependency(groupId: 'junit', artifactId: 'junit',&lt;br /&gt;                    version: '3.8.1', scope: 'test') ]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The moment of truth had arrived... I ran &lt;tt&gt;mvn clean package&lt;/tt&gt; from the command line, held my breath and then shouted "Tadaa!!" as the build executed and the &lt;tt&gt;BUILD SUCCESSFUL&lt;/tt&gt; message appeared.&lt;br /&gt;&lt;br /&gt;I plan more tests to see how this adapts to more complex POMs. Note that while I chose Groovy, you could as well try this at home with your favorite overhyped, buzzword-compliant dynamic language ;-)&lt;br /&gt;&lt;br /&gt;Here are links to Subversion diffs of the two modified projects: &lt;a href="http://outprinltn.googlepages.com/maven-core-2.0.8.diff"&gt;maven-core-2.0.8.diff&lt;/a&gt;, &lt;a href="http://outprinltn.googlepages.com/maven-project-2.0.8.diff"&gt;maven-project-2.0.8.diff&lt;/a&gt;. Or if you prefer, here is a &lt;a href="http://outprinltn.googlepages.com/maven-groovy.zip"&gt;ZIP&lt;/a&gt; containing all the modified files.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Note: I later found out that Sam Pullara had already had a &lt;a href="http://www.javarants.com/2007/12/21/using-groovy-to-make-maven2-more-modular-and-readable/"&gt;similar idea&lt;/a&gt; about 2 months ago. However, my approach being slightly different (he has a Groovy script generate the &lt;tt&gt;pom.xml&lt;/tt&gt; and invoke Maven, while I have the Maven core execute the script), I've decided to keep this posted anyway.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-5424316048381381834?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/5424316048381381834/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=5424316048381381834' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/5424316048381381834'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/5424316048381381834'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2008/02/i-recently-came-across-brett-porters.html' title='Writing Maven POMs in Groovy'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-3485340344836317669</id><published>2007-09-18T21:22:00.001+02:00</published><updated>2007-09-18T21:29:58.203+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>What protected really means</title><content type='html'>Section 3.5 of &lt;a  href="http://www.sun.com/books/catalog/gosling_JPL4.xml"&gt;The Java&amp;#8482; Programming Language, 4th Edition&lt;/a&gt; defines &lt;tt&gt;protected&lt;/tt&gt; as:&lt;br&gt; "&lt;i&gt;beyond being accessible within the class itself and to code within the same package [...], a protected member can also be accessed from a class through object references that are of at least the same type as the class.&lt;/i&gt;"&lt;br&gt; &lt;br&gt; The rationale is given a bit further:&lt;br&gt; "&lt;i&gt;Suppose that one subclass, as part of its expanded contract, places constraints on the values of protected members of the superclass. If a different subclass could access the protected members of objects of the first subclass then it could manipulate them in a way that would break the first subclass's contract - and this should not be permissible.&lt;/i&gt;"&lt;br&gt; &lt;br&gt; The text gives examples, but does not explain precisely how a subclass could try to break the contract of another. Here is a very simple example I put together to understand this.&lt;br&gt; &lt;br&gt; But first, let's remember that in Java, visibility is per-class, not per-object. For example, an object can access the private members of other instances of the same class. In other words, the following code compiles and works perfectly:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class TestPrivate {&lt;br /&gt;  &lt;br /&gt;  static class MyInt {&lt;br /&gt;    private int value;&lt;br /&gt;&lt;br /&gt;    public MyInt(int value) {this.value = value;}&lt;br /&gt;    &lt;br /&gt;    public int getValue() {return value;}&lt;br /&gt;    &lt;br /&gt;    public void resetValue(MyInt other) {other.value = 0;}&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    MyInt resetter = new MyInt(0);&lt;br /&gt;    MyInt other = new MyInt(42);&lt;br /&gt;&lt;br /&gt;    resetter.resetValue(other);&lt;br /&gt;    System.out.println(other.getValue());&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It may be obvious for you, but I've found that a number of people will tell you intuitively that the code doesn't compile (and, to be honest, I'm not sure of the answer I would have given a few weeks ago). Try to run a survey among your fellow programmers, I'd be interested to hear about the results.&lt;br&gt; &lt;br&gt; Going back to the protected example, here is the parent class, which encapsulates an &lt;tt&gt;int&lt;/tt&gt; (I told you it would be a &lt;i&gt;very&lt;/i&gt; simple example):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package test.protected1;&lt;br /&gt;&lt;br /&gt;public class MyInt {&lt;br /&gt;  protected int value;&lt;br /&gt;  &lt;br /&gt;  public MyInt(int value) {&lt;br /&gt;    this.value = value;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public String toString() {&lt;br /&gt;    return String.valueOf(value);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And here is the first subclass, which expands the contract by enforcing positivity:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package test.protected1;&lt;br /&gt;&lt;br /&gt;public final class MyPositiveInt extends MyInt {&lt;br /&gt;  public MyPositiveInt(int value) {&lt;br /&gt;    super(value);&lt;br /&gt;    if (value &lt; 0) {&lt;br /&gt;      throw new IllegalArgumentException("value must be positive");&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;tt&gt;MyPositiveInt&lt;/tt&gt; enforces its contract strictly: there is no way to modify the &lt;tt&gt;int&lt;/tt&gt; once the instance has been constructed, and furthermore the class is &lt;tt&gt;final&lt;/tt&gt;, preventing attacks by subclasses.&lt;br&gt; &lt;br&gt; And now here is the would-be attacker subclass. Note that it is defined in a separate package (see below):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package test.protected2;&lt;br /&gt;&lt;br /&gt;import test.protected1.MyInt;&lt;br /&gt;import test.protected1.MyPositiveInt;&lt;br /&gt;&lt;br /&gt;public class MyPositiveIntBreaker extends MyInt {&lt;br /&gt;&lt;br /&gt;  public MyPositiveIntBreaker(int value) {&lt;br /&gt;    super(value);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static void breakPositiveInt(MyPositiveInt toBreak) {&lt;br /&gt;    MyInt broken = (MyInt) toBreak;&lt;br /&gt;    broken.value = -1;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The idea is: 1) casting the &lt;tt&gt;MyPositiveInt&lt;/tt&gt; to a &lt;tt&gt;MyInt&lt;/tt&gt; is perfectly valid; 2) &lt;tt&gt;MyPositiveBreaker&lt;/tt&gt; extends &lt;tt&gt;MyInt&lt;/tt&gt;, so the protected field &lt;tt&gt;value&lt;/tt&gt; is accessible; 3) visibility is per-class, to there should be no problem accessing &lt;tt&gt;value&lt;/tt&gt; of another &lt;tt&gt;MyInt&lt;/tt&gt; instance.&lt;br&gt; &lt;br&gt; If this worked, we would be able to construct a &lt;tt&gt;MyPositiveInt&lt;/tt&gt; that breaks its contract, without the original class being able to do anything about it. That's where the rule cited above comes into play: the third affirmation is actually false, and accessing &lt;tt&gt;broken.value&lt;/tt&gt; gives a compile-time error. This is because we access the protected field from class &lt;tt&gt;MyPositiveIntBreaker&lt;/tt&gt; through a reference of type &lt;tt&gt;MyInt&lt;/tt&gt;, and &lt;tt&gt;MyInt&lt;/tt&gt; is not "&lt;i&gt;of at least the same type as&lt;/i&gt;" &lt;tt&gt;MyPositiveIntBreaker&lt;/tt&gt;, it's the other way around.&lt;br&gt; &lt;br&gt; Finally, protected also means package-private, so if you moved &lt;tt&gt;MyPositiveIntBreaker&lt;/tt&gt; into package &lt;tt&gt;test.protected1&lt;/tt&gt; the "attack" would work. However, it is generally considered that classes in the same package are trustworthy; if you don't fully control the class path, you can use &lt;a href="http://java.sun.com/developer/JDCTechTips/2001/tt0130.html"&gt;security permissions&lt;/a&gt; (old link but still seems valid) to prevent new classes from being added to your package.&lt;br&gt; &lt;br&gt; As a conclusion, this example is of course very simplistic. For instance, testing &lt;tt&gt;value&lt;/tt&gt; after calling &lt;tt&gt;super(value)&lt;/tt&gt; in &lt;tt&gt;MyPositiveInt(int)&lt;/tt&gt; feels awkward: in real life it would probably be better to make the variable private and define protected accessors. But the objective was to illustrate the reasons that motivate the "real" meaning of &lt;tt&gt;protected&lt;/tt&gt;; a real-life example would probably be a bit more complex.&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-3485340344836317669?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/3485340344836317669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=3485340344836317669' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/3485340344836317669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/3485340344836317669'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2007/09/what-protected-really-means.html' title='What protected really means'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-835672965606289462</id><published>2007-09-10T20:11:00.001+02:00</published><updated>2007-09-11T09:28:38.095+02:00</updated><title type='text'>A development environment installation tool?</title><content type='html'>It had always struck me that &lt;a  href="http://tomcat.apache.org/tomcat-6.0-doc/index.html"&gt;the Tomcat documentation&lt;/a&gt; didn't explain how to use &lt;tt&gt;CATALINA_BASE&lt;/tt&gt; to run multiple instances from a single installation. I recently realized that this is detailed in the &lt;a  href="http://tomcat.apache.org/tomcat-6.0-doc/RUNNING.txt"&gt;&lt;tt&gt;RUNNING.txt&lt;/tt&gt;&lt;/a&gt; file that comes in the base directory of the distribution :-o&lt;br&gt; &lt;br&gt; I like to keep a clean installation of a product and have separate directories for each project that uses it. I'd like to generalize this idea to create a development environment installation tool: installing everything from scratch is always time-consuming for new developers; what we did for some projects at my company was to create a giant archive containing everything you need to build and run a specific project (JDK, application server, build tool, IDE, workspace, etc.). All the developer has to do is get the archive, unzip it, and adapt the configuration. With a few assumptions (for instance, a standardized installation path), you can keep the personalization phase to the strict minimum (changing the SCM user and updating the sources to the current version).&lt;br&gt; &lt;br&gt; The downside to this approach is that each project brings its own installation of potentially similar products. In the end, you would end up with 4 installations of JDK version X or Eclipse version Y on your hard drive. That's where I see a parallel with Maven's dependency mechanism - instead of handling your third-party JARs yourself, you declare them, and Maven handles all the necessary downloading and copying.&lt;br&gt; &lt;br&gt; I believe a similar repository mechanism could be used for development tools:&lt;br&gt; &lt;ul&gt;   &lt;li&gt;The central repository would be on a server somewhere in your company and host zipped product installations.&lt;/li&gt;   &lt;li&gt;The local repository on your machine would contain a clean unzipped version of the products. No project would be allowed to modify these files.&lt;br&gt;   &lt;/li&gt;   &lt;li&gt;Each project would independently provide (for example from an SCM repository):&lt;/li&gt;   &lt;ul&gt;     &lt;li&gt;an "environment descriptor" listing dependencies to the required products.&lt;/li&gt;     &lt;li&gt;project-specific product configuration, for instance a Tomcat base, a Weblogic domain, an Eclipse workspace...&lt;br&gt;     &lt;/li&gt;     &lt;li&gt;launch scripts (which would rely on a standardized product root and project directory).&lt;/li&gt;     &lt;li&gt;and the project sources of course.&lt;br&gt;     &lt;/li&gt;   &lt;/ul&gt;   &lt;li&gt;The environment installation process would read the descriptor and update the local repository, by unzipping the products that are not already installed.&lt;/li&gt; &lt;/ul&gt; I think I already know how to handle a couple of tools could in this way: the Java SDK, Maven, ANT, Tomcat, Weblogic...&lt;br&gt; &lt;br&gt; Eclipse is a bit trickier though, because of the plugins: different projects may need the same version of the IDE, but with different and potentially conflicting plugins. It would be nice to say "I need Eclipse version x, and plugin A, and plugin B", but to keep everything in separate directories. I think this is feasible as well: thanks to the &lt;a  href="http://help.eclipse.org/help32/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/misc/multi_user_installs.html"&gt;Eclipse manual&lt;/a&gt; and &lt;a  href="http://blog.exis.com/colin/archives/2004/12/23/managing-plugins-in-eclipse/"&gt;a post&lt;/a&gt; from Colin Sampaleanu's blog, I've set up an example with an Eclipse 3.2 installation in a directory, the &lt;a  href="http://subclipse.tigris.org/"&gt;Subclipse plugin&lt;/a&gt; in another, and a third directory that stores external configuration and workspace locations. I can launch a workbench with Subclipse installed, without affecting the first two directories.&lt;br&gt; &lt;br&gt; So how about a development environment installation tool? Some may argue that an IDE should already provide everything, but I think that in practice you often need a few additional tools on the side. I'm not aware of any tool providing the features I described, but I might as well be &lt;a  href="http://en.wikipedia.org/wiki/Reinventing_the_wheel"&gt;reinventing the wheel&lt;/a&gt; (or worse, the &lt;a  href="http://en.wikipedia.org/wiki/Reinventing_the_square_wheel"&gt;square wheel&lt;/a&gt;)... comments are welcome.&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-835672965606289462?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/835672965606289462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=835672965606289462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/835672965606289462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/835672965606289462'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2007/09/development-environment-installation.html' title='A development environment installation tool?'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-1629117795685872227</id><published>2007-09-03T17:31:00.001+02:00</published><updated>2007-09-03T17:37:15.047+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>SLF4J and Logback</title><content type='html'>&lt;a href="http://www.slf4j.org"&gt;SLF4J&lt;/a&gt; and &lt;a  href="http://logback.qos.ch"&gt;Logback&lt;/a&gt; are alternatives to the popular &lt;a href="http://commons.apache.org/logging"&gt;Jakarta Commons-Logging&lt;/a&gt; (JCL) and &lt;a href="http://logging.apache.org/log4j"&gt;Log4J&lt;/a&gt; logging frameworks. Both projects are led by Log4J founder Ceki G&amp;uuml;lc&amp;uuml;.&lt;br&gt; &lt;br&gt; &lt;br&gt; SLF4J's main goal is to avoid the &lt;a  href="http://www.qos.ch/logging/classloader.jsp"&gt;class loader problems&lt;/a&gt; JCL suffered from.While JCL uses a dynamic mechanism to discover which logging frameworks are available at runtime, SLF4J is bound to its underlying implementation statically, at compile-time. To achieve this, you place two JARs in the classpath: the SLF4J API itself, and one "binding" JAR corresponding to the chosen implementation.&lt;br&gt; &lt;br&gt; SLF4J is being adopted by a growing number of open-source projects (see a non-exhaustive list on the project's main page). For situations where it has to coexist with JCL, &lt;a  href="http://www.slf4j.org/manual.html#gradual"&gt;migration solutions&lt;/a&gt; are available. If you use Maven, you may also have problems with dependencies that drag along JCL transitively ; to solve this, see &lt;a  href="http://day-to-day-stuff.blogspot.com/2007/07/no-more-commons-logging.html"&gt;this hack&lt;/a&gt;.&lt;br&gt; &lt;br&gt; &lt;br&gt; Logback is the official successor to Log4J (Log4J currently has 3 branches : 1.2 - stable with limited evolution, 1.3 - discontinued, and 2.0 - experimental). Here is a list of evolutions and enhancements I noted while reading the &lt;a  href="http://logback.qos.ch/manual/index.html"&gt;Logback manual&lt;/a&gt;:&lt;br&gt; &lt;ul&gt;   &lt;li&gt;the &lt;b&gt;basic syntax&lt;/b&gt;, as illustrated in the &lt;a  href="http://logback.qos.ch/xref/chapter1/HelloWorld1.html"&gt;Hello World&lt;/a&gt; example, should look quite familiar to JCL users. Note that this example actually uses SLF4J classes - the Logback manual promotes using SLF4J from the start.&lt;/li&gt;   &lt;li&gt;&lt;b&gt;&lt;a  href="http://logback.qos.ch/manual/architecture.html#ParametrizedLogging"&gt;parameterized logging&lt;/a&gt;:&lt;/b&gt; logging messages now accept parameters. For instance, we can use &lt;tt&gt;logger.debug("The entry is {}", entry)&lt;/tt&gt; instead of &lt;tt&gt;logger.debug("The entry is " + entry)&lt;/tt&gt;. The advantage is that the first version will not try to convert&lt;tt&gt; entry &lt;/tt&gt;to a&lt;tt&gt; String &lt;/tt&gt;if logging is disabled (this is equivalent to using the &lt;tt&gt;isDebugEnabled&lt;/tt&gt; method with Log4J), thus improving performance (by a factor of at least 30 according to the manual). The framework provides similar methods for two and a variable number of parameters (the latter using&lt;tt&gt; Object[]&lt;/tt&gt;, probably to preserve 1.4 compatibility).&lt;/li&gt;   &lt;li&gt;&lt;a  href="http://logback.qos.ch/manual/architecture.html#Performance"&gt;&lt;b&gt;performance&lt;/b&gt;&lt;/a&gt; has apparently been a strong focus. Apart from the preceding item, the manual also mentions improvements in the way the framework determines whether to log or not (Log4J walks the logger hierarchy - see the&lt;tt&gt; getEffectiveLevel &lt;/tt&gt;method in the &lt;tt&gt;Category     &lt;/tt&gt;class - while Logback propagates the level to child loggers if it changes), and in formatting and writing the messages.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://logback.qos.ch/manual/joran.html"&gt;&lt;b&gt;configuration&lt;/b&gt;&lt;/a&gt; is now performed with an integrated framework called Joran. On a basic user level, this doesn't change much, except that configuration is now stored in an XML file, which supports substitution properties and file inclusion. Joran can also be &lt;a  href="http://logback.qos.ch/manual/joran.html#Joran"&gt;used independently&lt;/a&gt;.&lt;br&gt;   &lt;/li&gt;   &lt;li&gt;&lt;a href="http://logback.qos.ch/manual/filters.html"&gt;&lt;b&gt;filters&lt;/b&gt;&lt;/a&gt; provide a way to, well, filter logging messages. They can be used to refine log selection at the appender level, or to control logging event creation at the more general context level (via "&lt;a  href="http://logback.qos.ch/manual/filters.html#TurboFilter"&gt;TurboFilters&lt;/a&gt;"). The manual provides the following examples:&lt;/li&gt;   &lt;ul&gt;     &lt;li&gt;refining an appender for a specific message level (&lt;tt&gt;LevelFilter&lt;/tt&gt;) or a level threshold (&lt;tt&gt;ThresholdFilter&lt;/tt&gt;).&lt;/li&gt;     &lt;li&gt;refining an appender by checking messages against java expressions specified in the configuration file (these are compiled on-the-fly with &lt;a href="http://www.janino.net"&gt;Janino&lt;/a&gt;, an optional dependency).&lt;/li&gt;     &lt;li&gt;defining a TurboFilter to refine logging events for a specific &lt;a  href="http://www.slf4j.org/api/index.html"&gt;Marker&lt;/a&gt;. Markers are objects used to enrich log statements. All the logging methods (&lt;tt&gt;logger.debug&lt;/tt&gt;,       &lt;tt&gt;logger.info&lt;/tt&gt;, etc.) have a version taking a &lt;tt&gt;Marker&lt;/tt&gt; as a first argument.&lt;/li&gt;   &lt;/ul&gt;   &lt;li&gt;the &lt;b&gt;&lt;a href="http://logback.qos.ch/manual/mdc.html"&gt;MDC&lt;/a&gt;&lt;/b&gt; (short for &lt;i&gt;Mapped Diagnostic Context&lt;/i&gt;) is a mechanism to deal with multi-threaded applications. It is basically a ThreadLocal map-like object, where each thread can put specific key-value pairs. These properties can then be referenced in the layout pattern with the &lt;tt&gt;%X{...}&lt;/tt&gt; notation, or used by a filter.&lt;/li&gt;   &lt;li&gt;the &lt;b&gt;&lt;a  href="http://logback.qos.ch/manual/contextSelector.html"&gt;Context Selector&lt;/a&gt;&lt;/b&gt; is a JNDI-based mechanism to allow several web applications all running on the same server to each have their own configuration file.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://logback.qos.ch/access.html"&gt;&lt;b&gt;logback-access&lt;/b&gt;&lt;/a&gt; is a specialized module that provides HTTP-access log functionality with Tomcat and Jetty.&lt;br&gt;   &lt;/li&gt; &lt;/ul&gt; &lt;br&gt; SLF4J &lt;a href="http://www.slf4j.org/faq.html#requirements"&gt;requires&lt;/a&gt; JDK 1.3 or above.&lt;br&gt; Logback requires JDK 5.0. The Maven POM is configured to generate &lt;a  href="http://retrotranslator.sourceforge.net/"&gt;retrotranslated&lt;/a&gt; JARs for JDK 1.4, however I haven't found them in the central repository.&lt;br&gt; &lt;br&gt; &lt;br&gt; Whether or not to switch to Logback and/or SLF4J is a personal choice. However, Logback seems to be the designated successor to Log4J, which apparently won't evolve a lot from now on. There is also a lot of &lt;a  href="http://www.theserverside.com/news/thread.tss?thread_id=46698"&gt;debate&lt;/a&gt; about whether to use yet another abstraction layer like SLF4J or JCL (why not stick to plain 1.4 logging after all?). If you are developing a library, it is probably a good idea not to lock your clients into a specific implementation. For an application, it boils down to the question: do I want to keep the possibility of changing my logging implementation?&lt;br&gt; &lt;br&gt; Remember the following migration options:&lt;br&gt; &lt;ul&gt;   &lt;li&gt;if you are using SLF4J but depend on libraries that use JCL: &lt;tt&gt;jcl104-over-slf4j.jar&lt;/tt&gt; (drop-in replacement of JCL, redirects JCL calls to SLF4J), and &lt;a  href="http://day-to-day-stuff.blogspot.com/2007/07/no-more-commons-logging.html"&gt;commons-logging version 99-0-does-not-exist&lt;/a&gt; to avoid dragging the transitive Maven dependencies.&lt;br&gt;   &lt;/li&gt;   &lt;li&gt;if you are using SLF4J but depend on libraries that use Log4J directly:&lt;a href="http://www.slf4j.org/log4j-over-slf4j.html"&gt;&lt;tt&gt; log4j-over-slf4j.jar &lt;/tt&gt;&lt;/a&gt;(drop-in replacement of Log4J, redirects Log4J calls to SLF4J).&lt;br&gt;   &lt;/li&gt;   &lt;li&gt;if you are using SLF4J but realize your environment mandates JCL:&lt;tt&gt; slf4j-jcl.jar &lt;/tt&gt;(JCL binding for SLF4J, redirects SLF4J calls to JCL).&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/7524162926732063545-1629117795685872227?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/1629117795685872227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=1629117795685872227' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/1629117795685872227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/1629117795685872227'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2007/09/slf4j-and-logback.html' title='SLF4J and Logback'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-1747017784039468576</id><published>2007-08-30T12:17:00.001+02:00</published><updated>2007-08-30T12:19:15.531+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven repository browsing</title><content type='html'>&lt;a href="http://www.mvnrepository.com"&gt;mvnrepository.com&lt;/a&gt; is a web interface to Maven 2's central repository.&lt;br&gt; &lt;br&gt; It will allow you to quickly find the ultimate version of an artifact and view interesting details (dependencies, JAR / POM download, copy/paste ready declaration, etc.). There is also an &lt;a  href="http://www.mvnrepository.com/feeds/rss2.0.xml"&gt;RSS feed&lt;/a&gt; of all newly deployed artifacts, which number of posts seems to average a reasonable 20 per day.&lt;br&gt; &lt;br&gt; I think I had seen similar sites in the past but never settled for one (instead using &lt;a href="http://m2eclipse.codehaus.org"&gt;m2eclipse&lt;/a&gt; or worse, browsing ibiblio.org directly!). This one seems simple and straightforward enough.&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-1747017784039468576?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/1747017784039468576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=1747017784039468576' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/1747017784039468576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/1747017784039468576'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2007/08/maven-repository-browsing.html' title='Maven repository browsing'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-6911870933973630508</id><published>2007-08-24T18:28:00.001+02:00</published><updated>2007-08-24T18:38:11.149+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='aop'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Compile-time checks with AspectJ - part 2</title><content type='html'>As announced in my &lt;a  href="http://out-println.blogspot.com/2007/08/compile-time-checks-with-aspectj.html"&gt;previous post&lt;/a&gt;, here is the configuration to integrate AspectJ compile-time checks to a Maven build. It is really straightforward, thanks to the &lt;a  href="http://mojo.codehaus.org/aspectj-maven-plugin/"&gt;AspectJ Maven plugin&lt;/a&gt;. The following code is added in the &lt;tt&gt;pom.xml&lt;/tt&gt; file of the &lt;tt&gt;aop-test&lt;/tt&gt; project:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;project xmlns=[...]&amp;gt;&lt;br&gt; &amp;nbsp; [...]&lt;br&gt; &amp;nbsp; &amp;lt;profiles&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;profile&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;id&amp;gt;dev-env&amp;lt;/id&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;activation&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;activeByDefault&amp;gt;true&amp;lt;/activeByDefault&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/activation&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;dependencies&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;dependency&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;groupId&amp;gt;aspectj&amp;lt;/groupId&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;artifactId&amp;gt;aspectjrt&amp;lt;/artifactId&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;version&amp;gt;1.5.2a&amp;lt;/version&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/dependency&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/dependencies&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;build&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;plugins&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;plugin&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;artifactId&amp;gt;aspectj-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;executions&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;execution&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;goals&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;goal&amp;gt;compile&amp;lt;/goal&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/goals&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/execution&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/executions&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/plugin&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/plugins&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/build&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/profile&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;profile&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;id&amp;gt;dev-prod&amp;lt;/id&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;activation&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;property&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;name&amp;gt;env&amp;lt;/name&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;value&amp;gt;prod&amp;lt;/value&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/property&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/activation&amp;gt;&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/profile&amp;gt;&lt;br&gt; &amp;nbsp; &amp;lt;/profiles&amp;gt;&lt;br&gt; &amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You'll notice the use of Maven profiles to distinguish between development and production environments: the focus of this post being on contract enforcement at &lt;b&gt;development &lt;/b&gt;time, I wanted to handle the case where AspectJ would only be used for that purpose; we might want to weave the compile-time aspects only during development, and not leak the &lt;tt&gt;aspectjrt&lt;/tt&gt; dependency to the production environment (for instance, this might be an already existing project and our customer might not want to add a new dependency).&lt;br&gt; Of course, if AspectJ is used for anything else than these compile-time checks, profiles are not necessary: the &lt;tt&gt;&amp;lt;dependency&amp;gt;&lt;/tt&gt; and &lt;tt&gt;&amp;lt;build&amp;gt;&lt;/tt&gt; tags can be added directly under the &lt;tt&gt;&amp;lt;project&amp;gt;&lt;/tt&gt; element, and the aspects will be compiled and weaved in any case.&lt;br&gt; &lt;br&gt; Going back to project &lt;tt&gt;aop-test&lt;/tt&gt;, we can now try the two profiles:&lt;br&gt; &lt;ul&gt;   &lt;li&gt;launching&lt;tt&gt; mvn clean compile -Denv=prod &lt;/tt&gt;triggers the &lt;tt&gt;prod-env&lt;/tt&gt; profile, which bypasses the compile-time checks;&lt;/li&gt; &lt;/ul&gt; &lt;ul&gt;   &lt;li&gt;launching&lt;tt&gt; mvn clean compile &lt;/tt&gt;triggers the default &lt;tt&gt;dev-env&lt;/tt&gt; profile and compile-time checks are activated. The error is raised and the message even points us to the corresponding aspect:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[INFO] [aspectj:compile {execution: default}]&lt;br /&gt;[ERROR] substring can only be called from package com.acme.util&lt;br /&gt;[INFO] ------------------------------------------------------------------------&lt;br /&gt;[ERROR] BUILD ERROR&lt;br /&gt;[INFO] ------------------------------------------------------------------------&lt;br /&gt;[INFO] Compiler errors :&lt;br /&gt;error at myPostalCode.substring(0, 2);&lt;br /&gt;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br /&gt;D:\projects\tests\src\aop-test\src\main\java\com\acme\business\ExampleBusiness.j&lt;br /&gt;ava:19:0::0 substring can only be called from package com.acme.util&lt;br /&gt;        see also: D:\projects\tests\src\aop-test\src\main\aspect\com\acme\aspect&lt;br /&gt;s\CompileChecks.aj:21::0&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;However, I ran into a strange bug: running&lt;tt&gt; mvn compile &lt;/tt&gt;a second time does not invoke the AspectJ compiler, and the project compiles without any error!&lt;br&gt; &lt;br&gt; Running Maven with the&lt;tt&gt; -X &lt;/tt&gt;option, I noticed the following message: &lt;tt&gt;[DEBUG] No modifications found skipping aspectJ compile&lt;/tt&gt;. I localized it in the online sources of the Maven plugin: at line 459 of &lt;a  href="https://svn.codehaus.org/mojo/tags/aspectj-maven-plugin-1.0-beta-2/src/main/java/org/codehaus/mojo/aspectj/AbstractAjcCompiler.java"&gt;AbstractAjcCompiler.java&lt;/a&gt;, we can see in the &lt;tt&gt;isBuildNeeded()&lt;/tt&gt; method that the AspectJ compiler is only invoked when one of the following conditions is met:&lt;br&gt; &lt;ul&gt;   &lt;li&gt;we are running a new build from a clean project;&lt;/li&gt;   &lt;li&gt;the AspectJ configuration has changed since the last build (it is stored in &lt;tt&gt;target/classes/builddef.lst&lt;/tt&gt;);&lt;br&gt;   &lt;/li&gt;   &lt;li&gt;the project sources have changed.&lt;br&gt;   &lt;/li&gt; &lt;/ul&gt; Running the &lt;tt&gt;compile&lt;/tt&gt; phase two times in a row meets neither of these conditions, which explains the bug. We can suppose that this would not happen without any source modification in the meantime; however, leaving open a way to bypass the compile-time checks still bugs me. Possible solutions include:&lt;br&gt; &lt;ul&gt;   &lt;li&gt;running&lt;tt&gt; mvn clean compile &lt;/tt&gt;each and every time;&lt;/li&gt;   &lt;li&gt;adding a snippet of ANT code in the POM to manually delete &lt;tt&gt;builddef.lst&lt;/tt&gt;;&lt;br&gt;   &lt;/li&gt;   &lt;li&gt;filing a bug with the&lt;tt&gt; aspectj-maven-plugin &lt;/tt&gt;team, to request a switch to bypass the &lt;tt&gt;isBuildNeeded()&lt;/tt&gt; method.&lt;br&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/7524162926732063545-6911870933973630508?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/6911870933973630508/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=6911870933973630508' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/6911870933973630508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/6911870933973630508'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2007/08/compile-time-checks-with-aspectj-part-2.html' title='Compile-time checks with AspectJ - part 2'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-3804704529771848969</id><published>2007-08-14T15:22:00.001+02:00</published><updated>2007-08-14T16:04:09.191+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='aop'/><title type='text'>Compile-time checks with AspectJ</title><content type='html'>While reading &lt;a href="http://blog.theserverlabs.com/?p=6"&gt;a post on The Server Labs Blog&lt;/a&gt; the other day, this paragraph immediately caught my attention : &lt;i&gt;using the AspectJ DSL to specify domain pattern rules that should be checked at compile time&lt;/i&gt;.&lt;i&gt; [...] This technique can be used whenever you have large projects and there are developers with less experience, highlighting using compile-time warnings that they are violating the established architectural patterns.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This reminded me of a discussion I had with a colleague a few months ago : he complained that string manipulation methods were spread all over the business code. A single problem (for instance, extracting part of a string, converting to another type, etc.) would be handled in 30 different ways in 30 different methods. He was looking for a way to force developers to use utility classes, instead of using a different home-grown solution in each business method.&lt;br /&gt;&lt;br /&gt;I had never worked with AOP before (shame on me!), so I decided to give it a shot.&lt;br /&gt;&lt;i&gt;Disclaimer :&lt;/i&gt; there is nothing particularly innovative in this post (the contract enforcement example is &lt;a href="http://www.eclipse.org/aspectj/doc/released/progguide/starting-development.html#contract-enforcement"&gt;explained in the first chapter of the AspectJ Programming Guide&lt;/a&gt;); rather, my objective was to provide a complete running example.&lt;br /&gt;&lt;br /&gt;We start by creating a simple project with &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt;:&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;mvn archetype:create -DgroupId=com.acme -DartifactId=aop-test&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;Then we import it in Eclipse and delete the default generated classes (&lt;tt&gt;App.java&lt;/tt&gt; and &lt;tt&gt;TestApp.java&lt;/tt&gt;) as they won't be used.&lt;br /&gt;&lt;br /&gt;We add a utility class &lt;tt&gt;com.acme.util.PostalCodeUtils&lt;/tt&gt;, which handles the arduous task of extracting the province code from a spanish postal code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/**&lt;br /&gt; * Utility class to manipulate postal codes.&lt;br /&gt; */&lt;br /&gt;public class PostalCodeUtils {&lt;br /&gt; /**&lt;br /&gt;  * Extract the province code from a full postal code.&lt;br /&gt;  * &lt;br /&gt;  * @param postalCode&lt;br /&gt;  *            the full postal code.&lt;br /&gt;  * @return the province code.&lt;br /&gt;  */&lt;br /&gt; public static String getProvinceCode(String postalCode) {&lt;br /&gt;  return postalCode.substring(0, 2);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then we add a bogus business component called &lt;tt&gt;com.acme.business.ExampleBusiness&lt;/tt&gt;. Our objective will be to prevent the business layer from calling the &lt;tt&gt;substring&lt;/tt&gt; method directly (if you don't like this example, think of any other situation where you want to prevent an application layer to call a given method).&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/**&lt;br /&gt; * Example business component.&lt;br /&gt; */&lt;br /&gt;public class ExampleBusiness {&lt;br /&gt; /**&lt;br /&gt;  * Do something.&lt;br /&gt;  */&lt;br /&gt; public void doSomething() {&lt;br /&gt;  String myPostalCode = "28015";&lt;br /&gt;  &lt;br /&gt;  // The "right" way: using utility method&lt;br /&gt;  PostalCodeUtils.getProvinceCode(myPostalCode);&lt;br /&gt;  &lt;br /&gt;  // The "wrong" way: direct call to substring&lt;br /&gt;  myPostalCode.substring(0, 2);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;At this point we need to install the AspectJ Development Tools for Eclipse. This is done with Eclipse's software update, you can find the update site URL corresponding to your IDE version at &lt;a class="moz-txt-link-freetext" href="http://www.eclipse.org/ajdt/downloads"&gt;http://www.eclipse.org/ajdt/downloads&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;After installing and restarting the workbench, we need to convert the Eclipse project to be able to use AJDT : right-click on the project / &lt;i&gt;AspectJ Tools&lt;/i&gt; / &lt;i&gt;Convert to AspectJ Project&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;We can now create a new source directory &lt;tt&gt;src/main/aspect&lt;/tt&gt; and add an aspect : &lt;i&gt;File&lt;/i&gt; / &lt;i&gt;New&lt;/i&gt; / &lt;i&gt;Other&lt;/i&gt; / &lt;i&gt;AspectJ&lt;/i&gt; / &lt;i&gt;Aspect&lt;/i&gt;. We choose the name &lt;tt&gt;com.acme.aspects.CompileChecks&lt;/tt&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/**&lt;br /&gt; * Enforces project-specific development contracts.&lt;br /&gt; */&lt;br /&gt;public aspect CompileChecks {&lt;br /&gt; /**&lt;br /&gt;  * Matches calls to the String.substring method.&lt;br /&gt;  */&lt;br /&gt; pointcut callSubstring(): call(String String.substring(int,int));&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Matches code from the utility package.&lt;br /&gt;  */&lt;br /&gt; pointcut substringAllowed(): withincode(* com.acme.util..*.*(..));&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Raises a compile-time error if substring is called outside the utility&lt;br /&gt;  * package.&lt;br /&gt;  */&lt;br /&gt; declare error: callSubstring() &amp;&amp; !substringAllowed(): "substring can only be called&lt;br /&gt;from package com.acme.util";&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The code is pretty much self-explanatory (check the AspectJ documentation if you're not familiar with pointcut definitions). The &lt;tt&gt;declare error&lt;/tt&gt; instruction tells AspectJ to raise an error at compile time.&lt;br /&gt;&lt;br /&gt;As soon as Eclipse recompiles the project, the error pops out in the editor:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_acCbCYrl2jE/RsGtqiD2lqI/AAAAAAAAADA/uKRUQJUusSs/s1600-h/test-aop.jpg"&gt;&lt;img src="http://4.bp.blogspot.com/_acCbCYrl2jE/RsGtqiD2lqI/AAAAAAAAADA/uKRUQJUusSs/s400/test-aop.jpg" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_acCbCYrl2jE/RsGtqiD2lqI/AAAAAAAAADA/uKRUQJUusSs/s400/test-aop.jpg" alt="" id="BLOGGER_PHOTO_ID_5098547199369189026" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;That's it! Although the example itself is simplistic, I think it gives a pretty good overview of how development contracts can be enforced at compile-time. I'll try to cover Maven integration in a next post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-3804704529771848969?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/3804704529771848969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=3804704529771848969' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/3804704529771848969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/3804704529771848969'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2007/08/compile-time-checks-with-aspectj.html' title='Compile-time checks with AspectJ'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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/_acCbCYrl2jE/RsGtqiD2lqI/AAAAAAAAADA/uKRUQJUusSs/s72-c/test-aop.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7524162926732063545.post-201738864925383413</id><published>2007-08-13T09:35:00.002+02:00</published><updated>2010-06-04T07:08:49.366+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='scripting'/><title type='text'>EJB Dependency Graphing</title><content type='html'>One of the goals of &lt;a href="http://en.wikipedia.org/wiki/Service-oriented_architecture"&gt;SOA&lt;/a&gt; is to promote modularity of services. One of the projects I work on contains a bunch of EJBs that have been so far deployed as part of a monolithic EAR. Due to the lack of modularity in the development environment (all classes are configured as a single Eclipse project - ouch), the dependencies between these EJBs were not really clear. In order to partition the business logic into "silos", the first task was to assess the dependencies between the different components. Being a lazy person, I put together a set of tools and scripts to automatize this.&lt;br /&gt;&lt;br /&gt;The first step is an analysis of the Java dependencies between all the classes of the project, performed by the excellent &lt;a href="http://depfind.sourceforge.net/"&gt;Dependency Finder&lt;/a&gt; tool. The result of the analysis is stored in an XML file.&lt;br /&gt;&lt;br /&gt;Now, the expected granularity is EJB-level, not class-level, so two additional steps are required:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;"merge" the EJB classes and interfaces into a single unit. For instance, we want to transform the proposition "&lt;i&gt;the i&lt;/i&gt;&lt;i&gt;mplementation class of EJB &lt;tt&gt;Xxx&lt;/tt&gt; has a dependency on the home interface of EJB &lt;tt&gt;Yyy&lt;/tt&gt;&lt;/i&gt;" into : "&lt;i&gt;EJB &lt;tt&gt;Xxx &lt;/tt&gt;has a dependency on EJB &lt;tt&gt;Yyy&lt;/tt&gt;&lt;/i&gt;". To do this, I merge all the &lt;tt&gt;ejb-jar.xml&lt;/tt&gt; files (which contain information about which classes correspond to which EJB) and parse the result with an AWK script. This script creates a SED replacement file, which is in turn applied to the output of dependency finder to replace the java classes with the EJB name (a special naming convention is used to make sure there is no collision with existing classes). These replacements may generate duplicate dependencies in the file, but thankfully Dependency Finder doesn't complain about this in the next steps.&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;filter the results to keep only EJBs and DAOs. Once again, Dependency Finder does the job, however, there is a subtility : I want to keep regular classes that might be on a dependency path between two components. For instance, if EJB &lt;tt&gt;Xxx&lt;/tt&gt; depends on class &lt;tt&gt;Aaa     &lt;/tt&gt;that depends on EJB &lt;tt&gt;Yyy&lt;/tt&gt;, I want to keep class &lt;tt&gt;Aaa     &lt;/tt&gt;in the results. This is achieved by having Dependency Finder compute &lt;i&gt;closures&lt;/i&gt;, which are essentially all types that are reachable by following the dependencies from a given set of types. So I compute all classes that are accessible by following &lt;i&gt;outbound&lt;/i&gt; dependencies from the EJB and DAOs, then the same with &lt;i&gt;inbound&lt;/i&gt; dependencies. The intersection of the two sets (performed with the &lt;tt&gt;comm&lt;/tt&gt; UNIX command) corresponds to the set of classes that must be retained. These are included in the filtering process.&lt;br /&gt;&lt;/li&gt; &lt;/ul&gt; This pretty much sums up the extraction process. The information is then loaded into a &lt;a href="http://www.mysql.com/"&gt;MySQL&lt;/a&gt; database. The schema is straightforward: one table for components and one for dependencies. We also added tables to express membership to a silo (this information is hand-loaded and used in the reports).&lt;br /&gt;&lt;br /&gt;Finally, a set of scripts extract information from this database and generate comprehensive reports. In particular, I used &lt;a href="http://www.graphviz.org/"&gt;GraphViz&lt;/a&gt; to generate dependency graphs. This tool has a subgraph feature that allows me to put my silos in nice little boxes. The generated graphs can be navigated with &lt;a href="http://zvtm.sourceforge.net/zgrviewer.html"&gt;ZGRViewer&lt;/a&gt;, or printed to decorate office walls (I found a nice utility named &lt;a href="http://www.ctan.org/tex-archive/support/poster"&gt;poster&lt;/a&gt; to scale PostScript images on any number of pages).&lt;br /&gt;&lt;br /&gt;Here is an example of output (the names have been blurred to preserve the anonimity of the protagonists):&lt;br /&gt;&lt;div align="center"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_acCbCYrl2jE/RsAKZSD2lmI/AAAAAAAAACg/DxBKaQzKsSs/s1600-h/graph-metiers.jpg"&gt;&lt;img src="http://2.bp.blogspot.com/_acCbCYrl2jE/RsAKZSD2lmI/AAAAAAAAACg/DxBKaQzKsSs/s400/graph-metiers.jpg" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_acCbCYrl2jE/RsAKZSD2lmI/AAAAAAAAACg/DxBKaQzKsSs/s400/graph-metiers.jpg" alt="" id="BLOGGER_PHOTO_ID_5098086207644407394" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The blue houses are facade SLSBs, the red ellipses ellipses Entity Beans, the orange hexagons DAOs, the grey parallelograms regular classes, and the green boxes database tables.&lt;br /&gt;&lt;br /&gt;These reports help us refine silo definitions and identify dependencies that should be refactored.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-201738864925383413?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/201738864925383413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=201738864925383413' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/201738864925383413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/201738864925383413'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2007/08/ejb-dependency-graphing.html' title='EJB Dependency Graphing'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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/_acCbCYrl2jE/RsAKZSD2lmI/AAAAAAAAACg/DxBKaQzKsSs/s72-c/graph-metiers.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7524162926732063545.post-5838838938341516662</id><published>2007-08-06T19:14:00.001+02:00</published><updated>2007-08-06T19:30:13.842+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><title type='text'>Change POST data in Firefox</title><content type='html'>&lt;a href="http://tamperdata.mozdev.org/"&gt;Tamper Data&lt;/a&gt; is a Firefox extension to view and modify HTTP headers and POST data, and track and time requests. When you turn it on, each time the browser issues a POST, a window pops-up and allows you to change the data before the request is actually sent.&lt;br&gt; &lt;br&gt; Didn't solve the problem I had today (apparently a very badly handled exception on the server side), but it could be quite handy.&lt;br&gt; &lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-5838838938341516662?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/5838838938341516662/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=5838838938341516662' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/5838838938341516662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/5838838938341516662'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2007/08/tamper-data.html' title='Change POST data in Firefox'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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-7524162926732063545.post-2634382868876319041</id><published>2007-08-01T10:03:00.001+02:00</published><updated>2007-08-14T16:11:02.385+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='weblogic'/><title type='text'>BEA Workshop touchy about service packs</title><content type='html'>I had to deploy a web application developped with workshop yesterday. Upon accessing it, I kept getting the same JSP error for the &lt;tt&gt;netui-tag-*&lt;/tt&gt; tag library declarations:&lt;tt&gt;&lt;br /&gt;&lt;br /&gt;No tag library could be found with this URI&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;After checking and re-checking my configuration and the spec versions, I finally found a lead: the web application had been built with Weblogic Platform 8.1 SP4, while I was trying to deploy to 8.1 &lt;b&gt;SP5&lt;/b&gt;. I installed SP5 and updated my webapp's libraries by copying them from a newly created project. Then I rebuilt with SP5 and redeployed. That solved the problem.&lt;br /&gt;&lt;br /&gt;That's it, end of story. Not very fascinating stuff I admit, but since the initial error message wasn't very explicit, I think it was worth mentionning.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7524162926732063545-2634382868876319041?l=out-println.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://out-println.blogspot.com/feeds/2634382868876319041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7524162926732063545&amp;postID=2634382868876319041' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/2634382868876319041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7524162926732063545/posts/default/2634382868876319041'/><link rel='alternate' type='text/html' href='http://out-println.blogspot.com/2007/08/bea-workshop-touchy-about-service-packs.html' title='BEA Workshop touchy about service packs'/><author><name>Olivier</name><uri>http://www.blogger.com/profile/02226343019178357911</uri><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></feed>
