<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Pragmatic Coder : Java, Wicket and the Web</title>
	
	<link>http://www.richardnichols.net</link>
	<description>The blog of Richard Nichols.</description>
	<lastBuildDate>Thu, 29 Mar 2012 00:15:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<meta xmlns="http://www.w3.org/1999/xhtml" name="robots" content="noindex,follow" />
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/PragmaticCoder" /><feedburner:info uri="pragmaticcoder" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>How to get the running tasks for a Java Executor…</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/2XjSMLK-VzQ/</link>
		<comments>http://www.richardnichols.net/2012/01/how-to-get-the-running-tasks-for-a-java-executor/#comments</comments>
		<pubDate>Sun, 08 Jan 2012 02:41:33 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=1076</guid>
		<description><![CDATA[I just had the issue of debugging a large concurrent job that ran using Java&#8217;s Executor and ExecutorService classes for concurrency. The job comprised of roughly 50,000 tasks submitted recursively over a multi-GB data set that took 5hrs to process. &#8230; <a href="http://www.richardnichols.net/2012/01/how-to-get-the-running-tasks-for-a-java-executor/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/10/implementing-a-draft-mode-with-apache-wicket-forms/' rel='bookmark' title='Implementing a &#8220;Draft Mode&#8221; with Apache Wicket Forms'>Implementing a &#8220;Draft Mode&#8221; with Apache Wicket Forms</a></li>
<li><a href='http://www.richardnichols.net/2010/09/session-replication-with-guice-java-web-applications/' rel='bookmark' title='Clustering Guice Java Web Applications'>Clustering Guice Java Web Applications</a></li>
<li><a href='http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/' rel='bookmark' title='Implementing Facebook OAuth 2.0 Authentication in Java'>Implementing Facebook OAuth 2.0 Authentication in Java</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I just had the issue of debugging a large concurrent job that ran using Java&#8217;s <em>Executor</em> and <em>ExecutorService</em> classes for concurrency.</p>
<p>The job comprised of roughly 50,000 tasks submitted recursively over a multi-GB data set that took 5hrs to process. The bug left a single task in the queue hanging indefinitely, thus the job never completing. There&#8217;s no way to kill a Thread in Java, and if you have blocking I/O it can be difficult to implement<em> interrupt()</em> such that it works correctly.</p>
<p>This is the point I found it&#8217;s quite difficult to actually expose at run-time what the hell Java&#8217;s <em>Executor</em> is actually doing at any point in time.</p>
<p>The successful choice I found was to create a custom <em>ThreadPoolExecutor</em> which trapped the creation of a <em>FutureTask</em> and the start/stop of any given task. I expect these hooks are there for this purpose, but it sure isn&#8217;t obvious how to do this.</p>
<p>It seems odd that the API doesn&#8217;t include any way to gather info about what&#8217;s happening inside the <em>Executor</em>, and also, there&#8217;s not even a <em>toString()</em> implementation for wrapping classes like <em>FutureTask</em> which would bubble your <em>Runnable</em> or <em>Callable</em> classes&#8217; <em>toString()</em> methods.</p>
<p>Oh well!</p>
<p>Here&#8217;s an example:</p>
<pre class="prettyprint">
private static final int NUM_THREADS = 4;
private final Logger log = Logger.getLogger(getClass());

private LinkedBlockingQueue< Runnable> taskQueue = new LinkedBlockingQueue< Runnable>();
private List< Runnable> running = Collections.synchronizedList(new ArrayList());

public void doSomeStuffConcurrently() {
	Executor executor =
		new ThreadPoolExecutor(NUM_THREADS, NUM_THREADS,
			0L, TimeUnit.MILLISECONDS,
			taskQueue,
			Executors.defaultThreadFactory())
	{

		@Override
		protected < T> RunnableFuture< T> newTaskFor(final Runnable runnable, T value) {
			return new FutureTask< T>(runnable, value) {
				@Override
				public String toString() {
					return runnable.toString();
				}
			};
		}

		@Override
		protected void beforeExecute(Thread t, Runnable r) {
			super.beforeExecute(t, r);
			running.add(r);
		}

		@Override
		protected void afterExecute(Runnable r, Throwable t) {
			super.afterExecute(r, t);
			running.remove(r);
			log.info("RUNNING: " + running);
		}
	};

	executor.execute(new Runnable() {

		@Override
		public void run() {
			// so some stuff
		}

		@Override
		public String toString() {
			return "describe the task here!";
		}
	});
}
</pre>
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2012%2F01%2Fhow-to-get-the-running-tasks-for-a-java-executor%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2012%2F01%2Fhow-to-get-the-running-tasks-for-a-java-executor%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=Java,tips&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/10/implementing-a-draft-mode-with-apache-wicket-forms/' rel='bookmark' title='Implementing a &#8220;Draft Mode&#8221; with Apache Wicket Forms'>Implementing a &#8220;Draft Mode&#8221; with Apache Wicket Forms</a></li>
<li><a href='http://www.richardnichols.net/2010/09/session-replication-with-guice-java-web-applications/' rel='bookmark' title='Clustering Guice Java Web Applications'>Clustering Guice Java Web Applications</a></li>
<li><a href='http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/' rel='bookmark' title='Implementing Facebook OAuth 2.0 Authentication in Java'>Implementing Facebook OAuth 2.0 Authentication in Java</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=2XjSMLK-VzQ:GC2-0MwqzWM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=2XjSMLK-VzQ:GC2-0MwqzWM:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=2XjSMLK-VzQ:GC2-0MwqzWM:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=2XjSMLK-VzQ:GC2-0MwqzWM:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=2XjSMLK-VzQ:GC2-0MwqzWM:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=2XjSMLK-VzQ:GC2-0MwqzWM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=2XjSMLK-VzQ:GC2-0MwqzWM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=2XjSMLK-VzQ:GC2-0MwqzWM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=2XjSMLK-VzQ:GC2-0MwqzWM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=2XjSMLK-VzQ:GC2-0MwqzWM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=2XjSMLK-VzQ:GC2-0MwqzWM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=2XjSMLK-VzQ:GC2-0MwqzWM:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/2XjSMLK-VzQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2012/01/how-to-get-the-running-tasks-for-a-java-executor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2012/01/how-to-get-the-running-tasks-for-a-java-executor/</feedburner:origLink></item>
		<item>
		<title>Writing reflective unit tests to improve code quality</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/BWfApBWDGfQ/</link>
		<comments>http://www.richardnichols.net/2011/12/writing-reflective-unit-tests-to-improve-code-quality/#comments</comments>
		<pubDate>Thu, 08 Dec 2011 00:56:33 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[junit]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[visural-common]]></category>
		<category><![CDATA[warp-persist]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=1057</guid>
		<description><![CDATA[I&#8217;ve found that writing JUnit tests that do classpath scanning combined with reflection is a way to write unit tests that cross-cut the entire application. This can be useful to prevent anti-patterns, enforce code standards or just to prevent common &#8230; <a href="http://www.richardnichols.net/2011/12/writing-reflective-unit-tests-to-improve-code-quality/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2009/08/netbeans-6-7-broke-my-parameterized-tests/' rel='bookmark' title='NetBeans 6.7 Broke My Parameterized Tests'>NetBeans 6.7 Broke My Parameterized Tests</a></li>
<li><a href='http://www.richardnichols.net/2009/07/testing-abstract-classes-with-mockito-and-junit/' rel='bookmark' title='Testing Abstract Classes With Mockito and JUnit'>Testing Abstract Classes With Mockito and JUnit</a></li>
<li><a href='http://www.richardnichols.net/2009/08/using-bottom-up-iterative-object-database-layer-with-hbm2java-and-warp-persist/' rel='bookmark' title='Using Bottom-Up Iterative Object/Database Layer With hbm2java and warp-persist'>Using Bottom-Up Iterative Object/Database Layer With hbm2java and warp-persist</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/12/4903285815_ebbdb41ec3_z.jpg"><img class="alignright size-thumbnail wp-image-1067" title="Photo by zeeweez: http://www.flickr.com/photos/zeevveez/4903285815/sizes/z/in/photostream/" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/12/4903285815_ebbdb41ec3_z-150x150.jpg" alt="" width="150" height="150" /></a>I&#8217;ve found that writing JUnit tests that do classpath scanning combined with reflection is a way to write unit tests that cross-cut the entire application. This can be useful to prevent anti-patterns, enforce code standards or just to prevent common dumb errors.</p>
<p>It also notable that tests like this will not just cover code that exists today, but code that get&#8217;s written in the future too.</p>
<p>Generally these tests won&#8217;t actually execute classes found the class path, but instead reflect on class structure, annotations or method IO. But you could also conceivably write tests that instantiated classes and tested behavior too.</p>
<p>Here&#8217;s an example of a classpath scanning, reflective test case.</p>
<p><span style="text-decoration: underline;"><em>Background:</em></span> I&#8217;ve used <em>warp-persist</em> in the past to do JPA transactions with Guice projects. This gives you a <em>@Transactional</em> annotation which will apply a transaction across the method, unless exception(s) of specified types are thrown. Unfortunately, the warp-persist library has a design flaw, in that the default is that checked exceptions ROLLBACK, but runtime (non-checked) exceptions DO NOT. Why you&#8217;d want this is unclear to me, so we always end up writing {Exception.class, RuntimeException.class} to cover all cases &#8211; something that is easy to forget to do!</p>
<p>The test below, find&#8217;s all uses of the <em>@Transactional</em> annotation and verifies that each use of the annotation lists both <em>RuntimeException.class</em> and <em>Exception.class</em> as the rollback conditions.</p>
<p>By scanning the classpath, any new (or old) code will be flagged if the developer forgets this bit of housekeeping (this test has saved my bacon more than once).</p>
<pre class="prettyprint">package com.mycom;

import com.visural.common.ClassFinder;
import com.wideplay.warp.persist.Defaults.DefaultUnit;
import com.wideplay.warp.persist.Transactional;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import junit.framework.TestCase;

public class TransactionalTest extends TestCase {

    public void testTransactionalDoesntCreateBadBugs() throws ClassNotFoundException, Exception {
        ClassFinder cf = new ClassFinder("com.mycom", true);
        List < String >  invalid = new ArrayList < String > ();
        Set < Class >  classes = cf.find();
        for (Class c : classes) {
            for (Method m : c.getDeclaredMethods()) {
                if (m.getAnnotation(Transactional.class) != null) {
                    List < Class < ? extends Exception >  >  ex = Arrays.asList(m.getAnnotation(Transactional.class).rollbackOn());
                    if (!ex.contains(Exception.class) || !ex.contains(RuntimeException.class)) {
                        invalid.add(c.getName()+"#"+m.getName()+"\n");
                    }
                }
            }
        }
        if (!invalid.isEmpty()) {
            Collections.sort(invalid);
            throw new Exception("The following methods use @Transactional, but do not rollback on Exception &amp; RuntimeException: "+invalid.toString());
        }
    }
}</pre>
<p>This is a slightly contrived example, in the sense that it is working around a design flaw in a 3rd party library. But, this technique is useful in many cases where you have design patterns, standards or anti-patterns which you want to enforce or prevent.</p>
<p>Here&#8217;s a few examples:</p>
<ul>
<li>Enforce all model classes should be <em>Serializable</em></li>
<li>Enforce class or method naming conventions</li>
<li>Enforce specific package structures / hierarchies</li>
<li>Ensure that arguments/returns are not overly specific e.g. return <em>List</em> not <em>ArrayList</em></li>
</ul>
<p>The tests can be as broad or narrow as your design rules. I&#8217;m not suggesting that the above examples are good ideas in all cases. But writing tests like these is a way to formalise a team/project standard in a more useful way, than writing it down in a document or wiki.</p>
<p>There be exceptions to many of the rules or patterns being tested, but you can always write the exceptions into the test.</p>
<p>Overall the advantages of this approach are:</p>
<ul>
<li>An opportunity to express the design pattern in the actual product code base as an executable test.</li>
<li>A way to ensure that a new developer is made aware of the design pattern, at the time it is most relevant: <em>when they need to apply it</em>.</li>
<li>A place to document the exceptions to the pattern, and why they are allowable.</li>
<li>A way to keep everyone honest. Even experienced developers take short cuts, or are forgetful sometimes.</li>
</ul>
<p>It&#8217;s a win all round. Not all Java developers are comfortable with class-path scanning and reflection/introspection (maybe they should be), but not all developers will need to write these tests, as they are probably best handled by a technical lead.</p>
<p><strong>Footnote:</strong> if you want a general-purpose utility for doing class path scanning, then my library <a href="http://code.google.com/p/visural-common/">visural-common</a> has <a href="https://github.com/rjnichols/visural-common/blob/master/visural-common/src/com/visural/common/ClassFinder.java">ClassFinder.java</a> &#8211; a way to search the class path for specific classes (as illustrated above).
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F12%2Fwriting-reflective-unit-tests-to-improve-code-quality%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F12%2Fwriting-reflective-unit-tests-to-improve-code-quality%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=Java,junit,tips,visural-common,warp-persist&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2009/08/netbeans-6-7-broke-my-parameterized-tests/' rel='bookmark' title='NetBeans 6.7 Broke My Parameterized Tests'>NetBeans 6.7 Broke My Parameterized Tests</a></li>
<li><a href='http://www.richardnichols.net/2009/07/testing-abstract-classes-with-mockito-and-junit/' rel='bookmark' title='Testing Abstract Classes With Mockito and JUnit'>Testing Abstract Classes With Mockito and JUnit</a></li>
<li><a href='http://www.richardnichols.net/2009/08/using-bottom-up-iterative-object-database-layer-with-hbm2java-and-warp-persist/' rel='bookmark' title='Using Bottom-Up Iterative Object/Database Layer With hbm2java and warp-persist'>Using Bottom-Up Iterative Object/Database Layer With hbm2java and warp-persist</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=BWfApBWDGfQ:PqgdFLEMlDw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=BWfApBWDGfQ:PqgdFLEMlDw:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=BWfApBWDGfQ:PqgdFLEMlDw:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=BWfApBWDGfQ:PqgdFLEMlDw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=BWfApBWDGfQ:PqgdFLEMlDw:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=BWfApBWDGfQ:PqgdFLEMlDw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=BWfApBWDGfQ:PqgdFLEMlDw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=BWfApBWDGfQ:PqgdFLEMlDw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=BWfApBWDGfQ:PqgdFLEMlDw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=BWfApBWDGfQ:PqgdFLEMlDw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=BWfApBWDGfQ:PqgdFLEMlDw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=BWfApBWDGfQ:PqgdFLEMlDw:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/BWfApBWDGfQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/12/writing-reflective-unit-tests-to-improve-code-quality/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/12/writing-reflective-unit-tests-to-improve-code-quality/</feedburner:origLink></item>
		<item>
		<title>Quick Tip – Make Anything A Windows Service</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/fWnazs4GF3s/</link>
		<comments>http://www.richardnichols.net/2011/09/make-anything-a-windows-service/#comments</comments>
		<pubDate>Thu, 15 Sep 2011 07:39:42 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[open-source]]></category>
		<category><![CDATA[servers]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=1045</guid>
		<description><![CDATA[I recently had to get nginx running as a Windows service and I came across a little project called &#8220;winsw&#8221; (Windows Service Wrapper) which was created by Kohsuke Kawaguchi &#8211; creator of Hudson/Jenkins. Apparently he created it while at Sun for &#8230; <a href="http://www.richardnichols.net/2011/09/make-anything-a-windows-service/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2011/01/use-hudson-now-jenkins-to-restart-a-windows-service/' rel='bookmark' title='Use Hudson (now Jenkins) to restart a Windows service&#8230;'>Use Hudson (now Jenkins) to restart a Windows service&#8230;</a></li>
<li><a href='http://www.richardnichols.net/2010/08/install-memcached-on-windows-server/' rel='bookmark' title='Setting Up Memcached As A Windows Service'>Setting Up Memcached As A Windows Service</a></li>
<li><a href='http://www.richardnichols.net/2009/09/1-minute-guide-installing-redmine-on-windows/' rel='bookmark' title='1 Minute Guide &#8211; Installing Redmine on Windows'>1 Minute Guide &#8211; Installing Redmine on Windows</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I recently had to get <a href="http://nginx.org/" target="_blank">nginx </a>running as a Windows service and I came across a little project called<a href="http://projectkenai.com/projects/winsw/pages/Home" target="_blank"> &#8220;winsw&#8221; (Windows Service Wrapper)</a> which was created by Kohsuke Kawaguchi &#8211; creator of Hudson/Jenkins.</p>
<p>Apparently he created it while at Sun for Hudson. The other popular Java Service Wrapper for Windows (by Tanuki) is GPL licenced and has commercial licences available. Kohsuke created &#8220;winsw&#8221; so there was an option for Hudson available under a more permissive licence than GPL. </p>
<p>Conveniently, &#8220;winsw&#8221; can actually be used with pretty much any process you want to turn into a windows service, not just Java apps.</p>
<p>It&#8217;s got really simple configuration with an XML file e.g.</p>
<pre>&lt;service&gt;
  &lt;id&gt;fisheye&lt;/id&gt;
  &lt;name&gt;dev.net FishEye&lt;/name&gt;
  &lt;description&gt;FishEye&lt;/description&gt;
  &lt;executable&gt;%FISHEYE_HOME%\bin\fisheyectl.bat&lt;/executable&gt;
  &lt;logpath&gt;P:\dev\logs\os\windows\services&lt;/logpath&gt;
  &lt;logmode&gt;roll&lt;/logmode&gt;
  &lt;depend&gt;Spooler&lt;/depend&gt;
  &lt;startargument&gt;run&lt;/startargument&gt;
  &lt;stopargument&gt;stop&lt;/stopargument&gt;
&lt;/service&gt;</pre>
<p>And it&#8217;s basically just a single EXE file (31KB) and the XML config (although it does require .NET 3).</p>
<p>Anyhow, this is a nice little tool to have in your toolbelt, particularly for getting non-Windows friendly stuff running on Windows servers!
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F09%2Fmake-anything-a-windows-service%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F09%2Fmake-anything-a-windows-service%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=open-source,servers,tips,windows&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2011/01/use-hudson-now-jenkins-to-restart-a-windows-service/' rel='bookmark' title='Use Hudson (now Jenkins) to restart a Windows service&#8230;'>Use Hudson (now Jenkins) to restart a Windows service&#8230;</a></li>
<li><a href='http://www.richardnichols.net/2010/08/install-memcached-on-windows-server/' rel='bookmark' title='Setting Up Memcached As A Windows Service'>Setting Up Memcached As A Windows Service</a></li>
<li><a href='http://www.richardnichols.net/2009/09/1-minute-guide-installing-redmine-on-windows/' rel='bookmark' title='1 Minute Guide &#8211; Installing Redmine on Windows'>1 Minute Guide &#8211; Installing Redmine on Windows</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=fWnazs4GF3s:lZ1ntAkmHE8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=fWnazs4GF3s:lZ1ntAkmHE8:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=fWnazs4GF3s:lZ1ntAkmHE8:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=fWnazs4GF3s:lZ1ntAkmHE8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=fWnazs4GF3s:lZ1ntAkmHE8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=fWnazs4GF3s:lZ1ntAkmHE8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=fWnazs4GF3s:lZ1ntAkmHE8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=fWnazs4GF3s:lZ1ntAkmHE8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=fWnazs4GF3s:lZ1ntAkmHE8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=fWnazs4GF3s:lZ1ntAkmHE8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=fWnazs4GF3s:lZ1ntAkmHE8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=fWnazs4GF3s:lZ1ntAkmHE8:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/fWnazs4GF3s" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/09/make-anything-a-windows-service/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/09/make-anything-a-windows-service/</feedburner:origLink></item>
		<item>
		<title>visural-wicket 0.7.0 release with support for Wicket 1.5</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/iH_UkbBQ8dM/</link>
		<comments>http://www.richardnichols.net/2011/09/visural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5/#comments</comments>
		<pubDate>Fri, 09 Sep 2011 12:13:09 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Wicket]]></category>
		<category><![CDATA[open-source]]></category>
		<category><![CDATA[visural-common]]></category>
		<category><![CDATA[visural-wicket]]></category>
		<category><![CDATA[wicket]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=1040</guid>
		<description><![CDATA[Today I pushed out release 0.7.0 of visural-wicket. This release is primarily a bug-fix and minor enhancement release, with one major feature &#8211; support for Wicket 1.5 which was released as stable yesterday! You can get the downloads here (note &#8230; <a href="http://www.richardnichols.net/2011/09/visural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/11/visural-wicket-0-6-5-release-is-available/' rel='bookmark' title='visural-wicket 0.6.5 release is available!'>visural-wicket 0.6.5 release is available!</a></li>
<li><a href='http://www.richardnichols.net/2010/02/visural-wicket-0-5-released-ready-for-action/' rel='bookmark' title='visural-wicket 0.5 released &#8211; ready for action!'>visural-wicket 0.5 released &#8211; ready for action!</a></li>
<li><a href='http://www.richardnichols.net/2010/06/visural-wicket-0-6-released-new-components/' rel='bookmark' title='visural-wicket 0.6 released &#8211; lots of new components!'>visural-wicket 0.6 released &#8211; lots of new components!</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>Today I pushed out release 0.7.0 of visural-wicket. This release is primarily a bug-fix and minor enhancement release, with one major feature &#8211; support for <strong>Wicket 1.5</strong> which was released as stable yesterday!</p>
<p>You can get the downloads here (note there is a separate package for Wicket 1.4 and Wicket 1.5) -</p>
<ul>
<li><a href="http://code.google.com/p/visural-wicket/downloads/detail?name=visural-wicket-w15-0.7.0.zip">visural-wicket 0.7.0 for Wicket 1.5</a></li>
<li><a href="http://code.google.com/p/visural-wicket/downloads/detail?name=visural-wicket-w14-0.7.0.zip">visural-wicket 0.7.0 for Wicket 1.4</a></li>
</ul>
<div>
<p>Using Maven? Use <a href="http://code.google.com/p/visural-wicket/wiki/MavenSupport" target="_blank">this set up guide</a> instead.</p>
<p>The <a href="http://code.google.com/p/visural-wicket/issues/list?can=1&amp;q=milestone%3DRelease-0.7&amp;colspec=ID+Type+Status+Priority+Milestone+Owner+Summary&amp;cells=tiles">full list of changes is here</a>. Mostly these are bug fixes. Both the Wicket 1.4 and Wicket 1.5 versions incorporate the fixes.</p>
<p>The Wicket 1.5 library has not had extensive testing as yet, so please lodge any issues found on the <a href="http://code.google.com/p/visural-wicket/issues/list" target="_blank">project issue tracker</a>, or at the <a href="http://groups.google.com/group/visural-wicket" target="_blank">Google Group</a>.</p>
<p>Please note also, that the source for the project <a href="https://github.com/rjnichols/visural-wicket" target="_blank">migrated to GitHub</a> not long ago. If you&#8217;d like to contribute then I would welcome pull requests or patches!</p>
<p>Hope to get through some more of the issues lodged in the project tracker soon. I&#8217;m slowing adjusting to being a Dad, and still having time to work on my projects such as this <img src='http://d3araz99qvcc8b.cloudfront.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
</div>
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F09%2Fvisural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F09%2Fvisural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=Java,open-source,visural-common,visural-wicket,wicket&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/11/visural-wicket-0-6-5-release-is-available/' rel='bookmark' title='visural-wicket 0.6.5 release is available!'>visural-wicket 0.6.5 release is available!</a></li>
<li><a href='http://www.richardnichols.net/2010/02/visural-wicket-0-5-released-ready-for-action/' rel='bookmark' title='visural-wicket 0.5 released &#8211; ready for action!'>visural-wicket 0.5 released &#8211; ready for action!</a></li>
<li><a href='http://www.richardnichols.net/2010/06/visural-wicket-0-6-released-new-components/' rel='bookmark' title='visural-wicket 0.6 released &#8211; lots of new components!'>visural-wicket 0.6 released &#8211; lots of new components!</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=iH_UkbBQ8dM:ThDraQ-L1WA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=iH_UkbBQ8dM:ThDraQ-L1WA:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=iH_UkbBQ8dM:ThDraQ-L1WA:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=iH_UkbBQ8dM:ThDraQ-L1WA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=iH_UkbBQ8dM:ThDraQ-L1WA:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=iH_UkbBQ8dM:ThDraQ-L1WA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=iH_UkbBQ8dM:ThDraQ-L1WA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=iH_UkbBQ8dM:ThDraQ-L1WA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=iH_UkbBQ8dM:ThDraQ-L1WA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=iH_UkbBQ8dM:ThDraQ-L1WA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=iH_UkbBQ8dM:ThDraQ-L1WA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=iH_UkbBQ8dM:ThDraQ-L1WA:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/iH_UkbBQ8dM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/09/visural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/09/visural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5/</feedburner:origLink></item>
		<item>
		<title>Implementing security in Wicket with visural-wicket</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/a7MdOqoOQ74/</link>
		<comments>http://www.richardnichols.net/2011/09/securing-wicket-with-visural-wicket/#comments</comments>
		<pubDate>Mon, 05 Sep 2011 12:20:11 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Wicket]]></category>
		<category><![CDATA[guides]]></category>
		<category><![CDATA[open-source]]></category>
		<category><![CDATA[visural-wicket]]></category>
		<category><![CDATA[wicket]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=1027</guid>
		<description><![CDATA[Wicket has a nice mechanism for plugging in security whereby all components (including pages) have three cross-cutting hooks which can be validated by a security rule – Instantiation Render Enable You can build your own security framework using the IAuthorizationStrategy interface &#8230; <a href="http://www.richardnichols.net/2011/09/securing-wicket-with-visural-wicket/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/06/visural-wicket-0-6-released-new-components/' rel='bookmark' title='visural-wicket 0.6 released &#8211; lots of new components!'>visural-wicket 0.6 released &#8211; lots of new components!</a></li>
<li><a href='http://www.richardnichols.net/2010/11/visural-wicket-0-6-5-release-is-available/' rel='bookmark' title='visural-wicket 0.6.5 release is available!'>visural-wicket 0.6.5 release is available!</a></li>
<li><a href='http://www.richardnichols.net/2011/09/visural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5/' rel='bookmark' title='visural-wicket 0.7.0 release with support for Wicket 1.5'>visural-wicket 0.7.0 release with support for Wicket 1.5</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>Wicket has a nice mechanism for plugging in security whereby all components (including pages) have three cross-cutting hooks which can be validated by a security rule –</p>
<ul>
<li>Instantiation</li>
<li>Render</li>
<li>Enable</li>
</ul>
<p>You can build your own security framework using the <em>IAuthorizationStrategy</em> interface and setting an appropriate implementation in your Wicket Application class.</p>
<p>Alternatively, you can leverage a simple security framework that is included in my open source library <em><a href="http://code.google.com/p/visural-wicket/">visural-wicket</a></em>.</p>
<p>Visural-wicket’s security framework really is just the “glue” between Wicket’s <em>IAuthorizationStrategy</em> and something that you can start using immediately to control component level security.</p>
<p>There are two key interfaces – <a href="http://wicket.visural.net/javadoc/com/visural/wicket/security/IClient.html"><em>IClient</em> </a>and<em> <a href="http://wicket.visural.net/javadoc/com/visural/wicket/security/IPrivilege.html">IPrivilege</a></em>. The former represents some client of the application, generally a logged in user. The latter represents some security rule which is applied on rendering or enabling of a component.</p>
<p>They&#8217;re really simple interfaces -</p>
<pre class="prettyprint">
/**
 * A client is any user of your system, i.e. in most cases an authenticated User.
 */
public interface IClient < T extends Serializable> {
    /**
     * Return any unique identifier.
     * @return
     */
    T getId();
}

/**
 * A privilege is any condition that can be evaluated with respect to a {@link IClient}.
 */
public interface IPrivilege < T extends IClient> {

    /**
     * Determine whether the privilege applies to the client.
     * @param client
     * @return
     */
    boolean isGrantedToClient(T client);
}
</pre>
<p>In your application class you provide some glue to define how to retrieve the current <em>IClient</em> (e.g. from the session) –</p>
<pre class="prettyprint">
public class MyApp extends Application {

    public void init() {
        // ...
        getSecuritySettings().setAuthorizationStrategy(new com.visural.wicket.security.AuthorizationStrategy(new IClientProvider() {
            public IClient getCurrentClient() {
                return userService.getCurrentUser(); // for example
            }
        }));
        // ...
    }
}
</pre>
<p>Then any component which implements <em>ISecureRenderInstance </em>or <em>ISecureEnableInstance </em>can define the privilege required to display or enable it –</p>
<pre class="prettyprint">
public class MyPage extends WebPage implements ISecureRenderInstance {
    // ...

    public IPrivilege getRenderPrivilege() {
       return new IPrivilege < User>() {
           public boolean isGrantedToClient(User client) {
               return client != null &#038;&#038; client.isAdmin();
           }
       };
       // instead of returning a anonymous class like this, you could also
       // package up common privileges into a singleton instance,
       // e.g. return Privilege.ADMIN;
    }
}
</pre>
<p>Wicket and visural-wicket then work in conjunction to ensure that the privileges get evaluated automatically at run-time. Unlike manually coded security which is mixed with other visibility logic, you can guarantee that no component that fails its security check can get rendered to a user that shouldn’t see it. You can also define common security rules as privileges in your code base and refer to them from many pages and components rather than duplicating similar logic across the application.</p>
<p>It&#8217;s a simple security mechanism which is designed to fit in with pretty much any app. I hope others find it useful too.
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F09%2Fsecuring-wicket-with-visural-wicket%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F09%2Fsecuring-wicket-with-visural-wicket%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=guides,open-source,visural-wicket,wicket&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/06/visural-wicket-0-6-released-new-components/' rel='bookmark' title='visural-wicket 0.6 released &#8211; lots of new components!'>visural-wicket 0.6 released &#8211; lots of new components!</a></li>
<li><a href='http://www.richardnichols.net/2010/11/visural-wicket-0-6-5-release-is-available/' rel='bookmark' title='visural-wicket 0.6.5 release is available!'>visural-wicket 0.6.5 release is available!</a></li>
<li><a href='http://www.richardnichols.net/2011/09/visural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5/' rel='bookmark' title='visural-wicket 0.7.0 release with support for Wicket 1.5'>visural-wicket 0.7.0 release with support for Wicket 1.5</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=a7MdOqoOQ74:B-SJDTlEgX0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=a7MdOqoOQ74:B-SJDTlEgX0:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=a7MdOqoOQ74:B-SJDTlEgX0:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=a7MdOqoOQ74:B-SJDTlEgX0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=a7MdOqoOQ74:B-SJDTlEgX0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=a7MdOqoOQ74:B-SJDTlEgX0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=a7MdOqoOQ74:B-SJDTlEgX0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=a7MdOqoOQ74:B-SJDTlEgX0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=a7MdOqoOQ74:B-SJDTlEgX0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=a7MdOqoOQ74:B-SJDTlEgX0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=a7MdOqoOQ74:B-SJDTlEgX0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=a7MdOqoOQ74:B-SJDTlEgX0:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/a7MdOqoOQ74" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/09/securing-wicket-with-visural-wicket/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/09/securing-wicket-with-visural-wicket/</feedburner:origLink></item>
		<item>
		<title>Demystifying HttpServletRequest properties…</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/NcmiqSFbYJc/</link>
		<comments>http://www.richardnichols.net/2011/08/demystifying-httpservletrequest-properties/#comments</comments>
		<pubDate>Fri, 12 Aug 2011 02:09:43 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=1018</guid>
		<description><![CDATA[I always find myself writing little test cases to figure out which methods to call on HttpServletRequest to get path / parameter information when doing low level Servlet and Filter programming. The method naming and Javadoc is pretty poor for &#8230; <a href="http://www.richardnichols.net/2011/08/demystifying-httpservletrequest-properties/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/10/getting-a-non-relative-absolute-url-for-a-wicket-page/' rel='bookmark' title='Getting a non-relative (absolute) URL for a Wicket page'>Getting a non-relative (absolute) URL for a Wicket page</a></li>
<li><a href='http://www.richardnichols.net/2010/08/5-minute-guide-clustering-apache-tomcat/' rel='bookmark' title='5 Minute Guide to Clustering &#8211; Java Web Apps in Tomcat'>5 Minute Guide to Clustering &#8211; Java Web Apps in Tomcat</a></li>
<li><a href='http://www.richardnichols.net/2010/06/301-redirects-made-easy-in-java/' rel='bookmark' title='301 Redirects Made Easy In Java'>301 Redirects Made Easy In Java</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I always find myself writing little test cases to figure out which methods to call on HttpServletRequest to get path / parameter information when doing low level Servlet and Filter programming.</p>
<p>The method naming and Javadoc is pretty poor for this part of the Java API and it&#8217;s always confusing as to how to interrogate the request to figure out which bits of information you want from the request URL and parameters.</p>
<p>I thought I save myself (and you) the effort of doing this again, once and for all, by writing a quick post which summarises all the interesting &#8220;getters&#8221; on the HttpServletRequest:</p>
<p>Say I have a request going to a Java web application deployed at context path &#8220;WebApplication1&#8243; on my localhost sever, running on port 8080 &#8211; </p>
<p>URL = &#8220;http://localhost:8080/WebApplication1/test?q=123&#038;r=456&#8243;</p>
<table>
<tr>
<td>Method</td>
<td>Example Return Value</td>
<td>Description</td>
</tr>
<tr>
<td>getContextPath</td>
<td>/WebApplication1</td>
<td>Returns the deployed context path without the host/port, but including the preceding &#8220;/&#8221;</td>
</tr>
<tr>
<td>getQueryString </td>
<td>q=123&#038;r=456</td>
<td>Returns query parameters as provided in the url, everything to the right of the &#8220;?&#8221;</td>
</tr>
<tr>
<td>getRequestURI</td>
<td> /WebApplication1/test</td>
<td>Returns the request path, without query parameters or host</td>
</tr>
<tr>
<td>getRequestURL </td>
<td>http://localhost:8080/WebApplication1/test</td>
<td>Returns the full request URL, without query parameters</td>
</tr>
<tr>
<td>getServletPath</td>
<td> /test</td>
<td>Returns the relative path within your web application, not including query parameters</td>
</tr>
<tr>
<td>getServerName </td>
<td>localhost</td>
<td>Returns the server hostname as per URL</td>
</tr>
<tr>
<td>getServerPort</td>
<td> 8080</td>
<td>Returns server port as per URL</td>
</tr>
</table>
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F08%2Fdemystifying-httpservletrequest-properties%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F08%2Fdemystifying-httpservletrequest-properties%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=Java,tips,web&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/10/getting-a-non-relative-absolute-url-for-a-wicket-page/' rel='bookmark' title='Getting a non-relative (absolute) URL for a Wicket page'>Getting a non-relative (absolute) URL for a Wicket page</a></li>
<li><a href='http://www.richardnichols.net/2010/08/5-minute-guide-clustering-apache-tomcat/' rel='bookmark' title='5 Minute Guide to Clustering &#8211; Java Web Apps in Tomcat'>5 Minute Guide to Clustering &#8211; Java Web Apps in Tomcat</a></li>
<li><a href='http://www.richardnichols.net/2010/06/301-redirects-made-easy-in-java/' rel='bookmark' title='301 Redirects Made Easy In Java'>301 Redirects Made Easy In Java</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=NcmiqSFbYJc:quEDtblmQ_k:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=NcmiqSFbYJc:quEDtblmQ_k:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=NcmiqSFbYJc:quEDtblmQ_k:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=NcmiqSFbYJc:quEDtblmQ_k:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=NcmiqSFbYJc:quEDtblmQ_k:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=NcmiqSFbYJc:quEDtblmQ_k:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=NcmiqSFbYJc:quEDtblmQ_k:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=NcmiqSFbYJc:quEDtblmQ_k:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=NcmiqSFbYJc:quEDtblmQ_k:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=NcmiqSFbYJc:quEDtblmQ_k:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=NcmiqSFbYJc:quEDtblmQ_k:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=NcmiqSFbYJc:quEDtblmQ_k:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/NcmiqSFbYJc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/08/demystifying-httpservletrequest-properties/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/08/demystifying-httpservletrequest-properties/</feedburner:origLink></item>
		<item>
		<title>Book Review: Racing the Beam – The Atari Video Computer System</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/lpe-w70-fz4/</link>
		<comments>http://www.richardnichols.net/2011/05/book-review-racing-the-beam-the-atari-2600/#comments</comments>
		<pubDate>Tue, 31 May 2011 11:43:06 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[books]]></category>
		<category><![CDATA[history]]></category>
		<category><![CDATA[soap-box]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=1005</guid>
		<description><![CDATA[I just finished reading Racing the Beam: The Atari Video Computer System (Platform Studies) an interesting read about the Atari 2600 (or Atari VCS as it was orginally known). You might think that the Atari VCS was one of the &#8230; <a href="http://www.richardnichols.net/2011/05/book-review-racing-the-beam-the-atari-2600/">Continue reading <span class="meta-nav">&#8594;</span></a>
No related posts.]]></description>
			<content:encoded><![CDATA[<p>I just finished reading <a href="http://www.amazon.com/gp/product/026201257X/ref=as_li_ss_tl?ie=UTF8&amp;tag=pracodthebloo-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399349&amp;creativeASIN=026201257X">Racing the Beam: The Atari Video Computer System (Platform Studies)</a><img style="border: none !important; margin: 0px !important;" src="http://www.assoc-amazon.com/e/ir?t=&amp;l=as2&amp;o=1&amp;a=026201257X&amp;camp=217145&amp;creative=399349" border="0" alt="" width="1" height="1" /> an interesting read about the Atari 2600 (or Atari VCS as it was orginally known).</p>
<p>You might think that the Atari VCS was one of the early 2D home console systems, which had a number of 2D sprites to move around a two dimensional plane, but you&#8217;d be wrong.</p>
<p>The original Atari was more like a &#8220;one dimensional&#8221; console. That is, its graphics processor had no notion of a two dimensional surface whatsoever, no frame buffer, and not even the concept of two dimensional sprites. The TIA (the Atari VCS&#8217;s graphics processing chip) supported -</p>
<ul>
<li>Two one-line 8 pixel wide player sprites, of a single colour</li>
<li>A one-line &#8221;ball&#8221; up to 8 pixel wide single colour blob of pixels</li>
<li>Two one-line &#8221;missiles&#8221; up to 8 pixel wide single colour blob of pixels, tied to the colour of the player sprites</li>
<li>A one-line 20-bit (20 pixel stretched) single colour &#8220;playfield&#8221; which can be mirrored or copied across the two halves of the screen</li>
</ul>
<p>Oh, and the system had 128 bytes of RAM. That&#8217;s right BYTES.</p>
<p>The above graphic elements are one dimensional in the sense, for each scanline down the display, the programmer had to dynamically reprogram the objects if they needed to change appearance. If you didn&#8217;t do anything between scanlines the same row of pixels would get repeated down the screen.</p>
<p>This is what the book&#8217;s title &#8220;Racing the Beam&#8221; references, since for each scanline the Atari VCS developers were racing the CPU&#8217;s clock to setup the next scanline during the horizontal blank of the screen.</p>
<p>The names of the various graphic elements were named after Combat and Pong, the two games the system was actually designed to play. The company figured that if they could create other games for the system, then it was a bonus, but it was designed around Combat and Pong, which were popular arcade games at the time. It&#8217;s incredible to think that the VCS had one of the longest production runs in home console history with over 10 years of service!</p>
<p>Atari VCS ROMs were also 2K-4K for the most part (with 8K and 16K appearing late in the life of the system using bank switching). This small size meant developers would go to huge lengths to save space in the programs, often using graphic data as code, or code as graphics data.</p>
<p>A simply astonishing number of games were created for the Atari VCS which found innovative ways to overcome the limitations of the system (even when it probably wasn&#8217;t a good idea to try). The book covers a number of landmark games in the system&#8217;s history, such as Pacman (which is sometimes blamed for the North American game crash of 1983), Pitfall, Star Wars &#8211; The Empire Strikes Back (the first licenced Star Wars game) and others.</p>
<p>Pacman was interesting since the game requires Pacman and four ghost characters to be somehow fit into the &#8220;two player sprites&#8221; Atari VCS. This was accomplished by only drawing each ghost on every fourth frame, which makes the game pretty much unplayable in an emulator -</p>
<p><a href="http://www.youtube.com/watch?v=HL2p2ANFlQ4">www.youtube.com/watch?v=HL2p2ANFlQ4</a></p>
<p>But as you can see, on a traditional CRT television, it looks fine (thanks to the eye&#8217;s persistence of vision) -</p>
<p><a href="http://www.youtube.com/watch?v=juH2qHYX9aI">www.youtube.com/watch?v=juH2qHYX9aI</a></p>
<p>That said, it&#8217;s still a pretty poor rendition of Pacman.</p>
<p>Pitfall was also interesting as it&#8217;s pretty much the first &#8220;platform game&#8221; that has many recognisable elements of the genre by contemporary standards. The way the game was fit into the cartridge and how it came about from a design perspective is also fascinating and there&#8217;s an excellent talk on it by <a href="http://www.gdcvault.com/play/1014632/Classic-Game-Postmortem-PITFALL" target="_blank">David Crane given at this year&#8217;s GDC</a>.</p>
<p>Anyhow, I&#8217;d highly recommend picking up this book, if you were a kid in the 80&#8242;s, if you have an interest in early computing hardware, or just if you&#8217;re generally interested in computing, it&#8217;s a great read.</p>
<p>I&#8217;m actually tempted to write an Atari VCS game in assembler as a programming challenge. I used the 6502 quite a bit during my university degree, and the simplicity and purity of coding in against an 8-bit CPU like that is a lot of fun.</p>
<p>Amazon.com - <a href="http://www.amazon.com/gp/product/026201257X/ref=as_li_ss_tl?ie=UTF8&amp;tag=pracodthebloo-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399349&amp;creativeASIN=026201257X">Racing the Beam: The Atari Video Computer System (Platform Studies)</a><img src="http://www.assoc-amazon.com/e/ir?t=&amp;l=as2&amp;o=1&amp;a=026201257X&amp;camp=217145&amp;creative=399349" border="0" alt="" width="1" height="1" />
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F05%2Fbook-review-racing-the-beam-the-atari-2600%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F05%2Fbook-review-racing-the-beam-the-atari-2600%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=books,history,soap-box&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>No related posts.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=lpe-w70-fz4:ONpj32n_Awo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=lpe-w70-fz4:ONpj32n_Awo:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=lpe-w70-fz4:ONpj32n_Awo:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=lpe-w70-fz4:ONpj32n_Awo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=lpe-w70-fz4:ONpj32n_Awo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=lpe-w70-fz4:ONpj32n_Awo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=lpe-w70-fz4:ONpj32n_Awo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=lpe-w70-fz4:ONpj32n_Awo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=lpe-w70-fz4:ONpj32n_Awo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=lpe-w70-fz4:ONpj32n_Awo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=lpe-w70-fz4:ONpj32n_Awo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=lpe-w70-fz4:ONpj32n_Awo:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/lpe-w70-fz4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/05/book-review-racing-the-beam-the-atari-2600/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/05/book-review-racing-the-beam-the-atari-2600/</feedburner:origLink></item>
		<item>
		<title>Netbeans 7 + Git plugin on Windows Issues?</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/aRN3jDWZ8LQ/</link>
		<comments>http://www.richardnichols.net/2011/05/netbeans-7-git-plugin-on-windows-issues/#comments</comments>
		<pubDate>Thu, 26 May 2011 04:09:51 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[netbeans]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=1000</guid>
		<description><![CDATA[I just started checking out Netbeans 7 which has a nice Git plugin available now in the plugin manager. I was horrified though when I opened a project to find every single source file was being shown as &#8220;modified&#8221; by Netbeans, although &#8230; <a href="http://www.richardnichols.net/2011/05/netbeans-7-git-plugin-on-windows-issues/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2009/07/5-reasons-why-netbeans-rocks/' rel='bookmark' title='5 Reasons Why NetBeans Rocks'>5 Reasons Why NetBeans Rocks</a></li>
<li><a href='http://www.richardnichols.net/2009/11/automatic-release-packaging-w-version-numbers-for-netbeans-java-projects/' rel='bookmark' title='Automatic release packaging w/ version numbers for Netbeans Java Projects&#8230;'>Automatic release packaging w/ version numbers for Netbeans Java Projects&#8230;</a></li>
<li><a href='http://www.richardnichols.net/2009/08/netbeans-6-7-broke-my-parameterized-tests/' rel='bookmark' title='NetBeans 6.7 Broke My Parameterized Tests'>NetBeans 6.7 Broke My Parameterized Tests</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I just started checking out Netbeans 7 which has a nice Git plugin available now in the plugin manager.</p>
<p>I was horrified though when I opened a project to find every single source file was being shown as &#8220;modified&#8221; by Netbeans, although there were no diffs shown inside the files!</p>
<p>However, it turns out that it&#8217;s not Netbean&#8217;s fault.</p>
<p>If you&#8217;re using <strong>msysgit </strong>on Windows to check out your projects, you probably installed it and did the typical &#8220;<em>next-&gt;next-&gt;next</em>&#8221; through the installer. Including through the following screen&#8230;.</p>
<p style="text-align: center;"><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/05/Git-Setup_2011-05-26_13-06-57.png"><img class="size-medium wp-image-1001 aligncenter" title="Git Setup_2011-05-26_13-06-57" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/05/Git-Setup_2011-05-26_13-06-57-300x243.png" alt="" width="300" height="243" /></a></p>
<p>Well by default <strong>msysgit </strong>does line ending mutation so that if you checkout a source file to a Windows box, it will add Windows line ending (&#8220;\n\r&#8221;) to all source files, and when you push it back to the server, change the line ending to Unix style (&#8220;\n&#8221;). Unfortunately this causes Netbean&#8217;s Git plugin to (rightly) say, &#8220;Hey! You changed all these files!&#8221;.</p>
<p>Really the auto line ending change stuff is <em>a really bad idea</em>, and <strong>you should disable it.</strong></p>
<p>The command to do so is as follows -</p>
<pre> git config --global core.autocrlf false</pre>
<p>After disabling, the Git support seems to work really well.
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F05%2Fnetbeans-7-git-plugin-on-windows-issues%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F05%2Fnetbeans-7-git-plugin-on-windows-issues%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=git,Java,netbeans,tips&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2009/07/5-reasons-why-netbeans-rocks/' rel='bookmark' title='5 Reasons Why NetBeans Rocks'>5 Reasons Why NetBeans Rocks</a></li>
<li><a href='http://www.richardnichols.net/2009/11/automatic-release-packaging-w-version-numbers-for-netbeans-java-projects/' rel='bookmark' title='Automatic release packaging w/ version numbers for Netbeans Java Projects&#8230;'>Automatic release packaging w/ version numbers for Netbeans Java Projects&#8230;</a></li>
<li><a href='http://www.richardnichols.net/2009/08/netbeans-6-7-broke-my-parameterized-tests/' rel='bookmark' title='NetBeans 6.7 Broke My Parameterized Tests'>NetBeans 6.7 Broke My Parameterized Tests</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=aRN3jDWZ8LQ:B_0Pz8MFF6o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=aRN3jDWZ8LQ:B_0Pz8MFF6o:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=aRN3jDWZ8LQ:B_0Pz8MFF6o:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=aRN3jDWZ8LQ:B_0Pz8MFF6o:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=aRN3jDWZ8LQ:B_0Pz8MFF6o:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=aRN3jDWZ8LQ:B_0Pz8MFF6o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=aRN3jDWZ8LQ:B_0Pz8MFF6o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=aRN3jDWZ8LQ:B_0Pz8MFF6o:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=aRN3jDWZ8LQ:B_0Pz8MFF6o:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=aRN3jDWZ8LQ:B_0Pz8MFF6o:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=aRN3jDWZ8LQ:B_0Pz8MFF6o:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=aRN3jDWZ8LQ:B_0Pz8MFF6o:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/aRN3jDWZ8LQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/05/netbeans-7-git-plugin-on-windows-issues/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/05/netbeans-7-git-plugin-on-windows-issues/</feedburner:origLink></item>
		<item>
		<title>It’s Oh So Quiet…</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/GgqsDEqnlfM/</link>
		<comments>http://www.richardnichols.net/2011/05/its-oh-so-quiet/#comments</comments>
		<pubDate>Thu, 19 May 2011 21:38:05 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=995</guid>
		<description><![CDATA[Five months and no blog posts? Aiya! I&#8217;ve been extremely busy through the first half of 2011, mostly because my wife and I are expecting our first baby (only a few weeks to go), and most of my free time &#8230; <a href="http://www.richardnichols.net/2011/05/its-oh-so-quiet/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/05/onmydoorstep-com-au-officially-launched/' rel='bookmark' title='onmydoorstep.com.au &#8211; officially launched!'>onmydoorstep.com.au &#8211; officially launched!</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>Five months and no blog posts? Aiya!</p>
<p>I&#8217;ve been extremely busy through the first half of 2011, mostly because my wife and I are expecting our first baby (only a few weeks to go), and most of my free time has been spent getting our house in order, doing baby shopping and doing my part to support as best I can.</p>
<p>Work has also been very hectic with a lot going on. What little time I&#8217;ve had to work on personal projects, was spent implementing the new search features at <a href="http://www.onmydoorstep.com.au/search" target="_blank">onmydoorstep.com.au</a>, doing the initial Wicket 1.5 branch for visural-wicket and learning a bit about Android development.</p>
<p>I do have some blog posts sorted out though for the coming months. Mostly they&#8217;re not going to be long form in-depth posts, but there are a few things I&#8217;ve learned or been working on lately that I&#8217;d like to post about, but haven&#8217;t had a chance to write up before now.</p>
<p>Of course, once our son arrives in a few weeks, who knows what could happen! <img src='http://d3araz99qvcc8b.cloudfront.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F05%2Fits-oh-so-quiet%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F05%2Fits-oh-so-quiet%2F&amp;source=rn_tweets&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/05/onmydoorstep-com-au-officially-launched/' rel='bookmark' title='onmydoorstep.com.au &#8211; officially launched!'>onmydoorstep.com.au &#8211; officially launched!</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=GgqsDEqnlfM:c2nh6tvR6ck:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=GgqsDEqnlfM:c2nh6tvR6ck:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=GgqsDEqnlfM:c2nh6tvR6ck:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=GgqsDEqnlfM:c2nh6tvR6ck:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=GgqsDEqnlfM:c2nh6tvR6ck:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=GgqsDEqnlfM:c2nh6tvR6ck:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=GgqsDEqnlfM:c2nh6tvR6ck:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=GgqsDEqnlfM:c2nh6tvR6ck:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=GgqsDEqnlfM:c2nh6tvR6ck:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=GgqsDEqnlfM:c2nh6tvR6ck:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=GgqsDEqnlfM:c2nh6tvR6ck:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=GgqsDEqnlfM:c2nh6tvR6ck:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/GgqsDEqnlfM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/05/its-oh-so-quiet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/05/its-oh-so-quiet/</feedburner:origLink></item>
		<item>
		<title>Use Hudson (now Jenkins) to restart a Windows service…</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/Hynb2ZT9J2s/</link>
		<comments>http://www.richardnichols.net/2011/01/use-hudson-now-jenkins-to-restart-a-windows-service/#comments</comments>
		<pubDate>Fri, 21 Jan 2011 06:20:24 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[ci]]></category>
		<category><![CDATA[releases]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=977</guid>
		<description><![CDATA[Here&#8217;s a quick tip &#8211; you can easily make Hudson restart a windows service, by using its &#8220;Windows Batch Command&#8221; build step in combination with the command line windows &#8220;net&#8221; command. Here&#8217;s an example of how we can get Hudson &#8230; <a href="http://www.richardnichols.net/2011/01/use-hudson-now-jenkins-to-restart-a-windows-service/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2011/09/make-anything-a-windows-service/' rel='bookmark' title='Quick Tip &#8211; Make Anything A Windows Service'>Quick Tip &#8211; Make Anything A Windows Service</a></li>
<li><a href='http://www.richardnichols.net/2010/08/install-memcached-on-windows-server/' rel='bookmark' title='Setting Up Memcached As A Windows Service'>Setting Up Memcached As A Windows Service</a></li>
<li><a href='http://www.richardnichols.net/2009/09/1-minute-guide-installing-redmine-on-windows/' rel='bookmark' title='1 Minute Guide &#8211; Installing Redmine on Windows'>1 Minute Guide &#8211; Installing Redmine on Windows</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a quick tip &#8211; you can easily make Hudson restart a windows service, by using its &#8220;<em>Windows Batch Command</em>&#8221; build step in combination with the command line windows &#8220;<em>net</em>&#8221; command.</p>
<p>Here&#8217;s an example of how we can get Hudson to restart Apache running on the same host -</p>
<ol>
<li>Create a new Job, say &#8220;Restart Apache&#8221; as a standard Hudson job.</li>
<li>Add a new &#8220;Windows batch command&#8221; step, and in the box enter -
<pre>net stop Apache2</pre>
</li>
<li>Add another new &#8220;Windows batch command&#8221; step, and in the box enter -
<pre>net start Apache2</pre>
</li>
<li>Run the job, and behold!</li>
</ol>
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/add-batch-step.jpg"><img class="alignleft size-full wp-image-979" title="add-batch-step" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/add-batch-step.jpg" alt="" width="286" height="112" /></a></p>
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/Restart-Apache-Config-Hudson_1295590005694.jpeg"><img class="alignleft size-medium wp-image-980" title="Restart Apache Config [Hudson]" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/Restart-Apache-Config-Hudson_1295590005694-300x151.jpg" alt="" width="300" height="151" /></a></p>
<p>This is handy if you&#8217;re automating deployments usnig Hudson on Windows hosts. Particularly if you&#8217;re trying to avoid PermGen issues with hot-redeployments on say, Apache Tomcat.
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F01%2Fuse-hudson-now-jenkins-to-restart-a-windows-service%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F01%2Fuse-hudson-now-jenkins-to-restart-a-windows-service%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=automation,ci,Java,releases,windows&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2011/09/make-anything-a-windows-service/' rel='bookmark' title='Quick Tip &#8211; Make Anything A Windows Service'>Quick Tip &#8211; Make Anything A Windows Service</a></li>
<li><a href='http://www.richardnichols.net/2010/08/install-memcached-on-windows-server/' rel='bookmark' title='Setting Up Memcached As A Windows Service'>Setting Up Memcached As A Windows Service</a></li>
<li><a href='http://www.richardnichols.net/2009/09/1-minute-guide-installing-redmine-on-windows/' rel='bookmark' title='1 Minute Guide &#8211; Installing Redmine on Windows'>1 Minute Guide &#8211; Installing Redmine on Windows</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=Hynb2ZT9J2s:gL7t-z5-ft4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=Hynb2ZT9J2s:gL7t-z5-ft4:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=Hynb2ZT9J2s:gL7t-z5-ft4:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=Hynb2ZT9J2s:gL7t-z5-ft4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=Hynb2ZT9J2s:gL7t-z5-ft4:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=Hynb2ZT9J2s:gL7t-z5-ft4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=Hynb2ZT9J2s:gL7t-z5-ft4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=Hynb2ZT9J2s:gL7t-z5-ft4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=Hynb2ZT9J2s:gL7t-z5-ft4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=Hynb2ZT9J2s:gL7t-z5-ft4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=Hynb2ZT9J2s:gL7t-z5-ft4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=Hynb2ZT9J2s:gL7t-z5-ft4:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/Hynb2ZT9J2s" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/01/use-hudson-now-jenkins-to-restart-a-windows-service/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/01/use-hudson-now-jenkins-to-restart-a-windows-service/</feedburner:origLink></item>
		<item>
		<title>Face Detection in Java – Haar Cascade with JJIL (how-to)</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/xcWNWdQqmac/</link>
		<comments>http://www.richardnichols.net/2011/01/java-facial-recognition-haar-cascade-with-jjil-guide/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 09:02:04 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[guides]]></category>
		<category><![CDATA[images]]></category>
		<category><![CDATA[open-source]]></category>
		<category><![CDATA[ui]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=938</guid>
		<description><![CDATA[A requirement came up on a recent project to automatically crop displayed profile images of people to just the &#8220;face&#8221; area for a thumbnail. This seems like a job for a face detection algorithm. Searching for appropriate open-source Java implementations &#8230; <a href="http://www.richardnichols.net/2011/01/java-facial-recognition-haar-cascade-with-jjil-guide/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/09/how-to-add-dynamic-watermark-to-jpeg-java/' rel='bookmark' title='Adding a Dynamic Watermark to an Image &#8211; Java Web Application'>Adding a Dynamic Watermark to an Image &#8211; Java Web Application</a></li>
<li><a href='http://www.richardnichols.net/2010/08/5-minute-guide-clustering-apache-tomcat/' rel='bookmark' title='5 Minute Guide to Clustering &#8211; Java Web Apps in Tomcat'>5 Minute Guide to Clustering &#8211; Java Web Apps in Tomcat</a></li>
<li><a href='http://www.richardnichols.net/2010/07/detecting-which-browser-in-java-servlet-filter/' rel='bookmark' title='Detecting Which Browser In Java Servlet/Filter'>Detecting Which Browser In Java Servlet/Filter</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>A requirement came up on a recent project to automatically crop displayed profile images of people to just the &#8220;face&#8221; area for a thumbnail.</p>
<p>This seems like a job for a face detection algorithm. Searching for appropriate open-source Java implementations didn&#8217;t yield too many results, however I was successful with <a href="http://code.google.com/p/jjil" target="_blank">JJIL</a> &#8211; <em>Jon&#8217;s Java Imaging Library,</em> which is open sourced under the LGPL licence.</p>
<p>JJIL is targeted at Java ME / Android platforms and doesn&#8217;t have much documentation or a particularly intuitive API (not complaining, as clearly some stellar work has gone into it, kudos to Jon Webb, it&#8217;s creator).</p>
<p>In the end I muddled through, detecting faces in an image in a standard Java project, but given it took me a while to get everything working, I thought I&#8217;d write a quick guide to help out others that are trying to achieve similar results.</p>
<h2>Getting the Right JARs</h2>
<p>First things first, I had trouble getting the published JAR files to work happily together. There seems to be some sort of version mismatch issue between the core and J2SE versions.</p>
<p>So I built my own copy &#8211; you can download it here &#8211; <a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/JJIL-visural-build-20110112.zip">JJIL-visural-build-20110112.zip</a></p>
<p>This is a build of the current trunk JJIL code, and the Java SE additions (jjil-j2se).</p>
<p>This build is guaranteed to work with the code examples below.</p>
<h2>Basic Process</h2>
<p>I&#8217;m going to try to explain the basic process of detecting the faces in terms of input and output data.</p>
<p>The key file provided by JJIL for easy face (and other body part) detection is <em>Gray8DetectHaarMultiScale.java</em></p>
<p>This operation is applied to an 8-bit greyscale input image, in combination with a pre-defined Haar Cascade profile. The profile determines which areas of the image are &#8220;detected&#8221;. So you would want (for example) a profile to detect the frontal face features. JJIL provides several profiles out of the box.</p>
<p>The output image is a mask of the area of image where faces are detected (white) and the areas where no face was detected (black). This isn&#8217;t tremendously useful, as we&#8217;d usually rather just have the rectangular areas in coordinate form &#8211; I&#8217;ll address this later, after walking through the process.</p>
<p>1. Read an image from disk (.JPG, etc.)</p>
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/test.jpg"><img title="Test image for face detection" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/test-300x216.jpg" alt="" width="300" height="216" /></a><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/test.jpg"> </a><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/test.jpg"></a></p>
<p>2. Convert it into a <em>jjil.core.Image</em></p>
<p>3. Generally we&#8217;ll have an RGB image (colored image) and so need to convert it to 8-bit greyscale, which is what the <em>Gray8DetectHaarMultiScale </em>class requires.</p>
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/test-grey.png"><img class="alignnone size-medium wp-image-952" title="Test image for face detection (greyscale)" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/test-grey-300x216.png" alt="" width="300" height="216" /></a></p>
<p>4. Create a new instance of <em>Gray8DetectHaarMultiScale </em>with the Haar profile for detecting faces (or other body part if that&#8217;s what you&#8217;re looking for).</p>
<p>5. Apply <em>Gray8DetectHaarMultiScale </em>to our 8-bit grey image.</p>
<p>6. Retrieve result from <em>Gray8DetectHaarMultiScale</em>.</p>
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/result.jpg"><img class="alignnone size-medium wp-image-950" title="result" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/result-300x216.jpg" alt="Resulting Haar mask for test image for face detection" width="300" height="216" /></a></p>
<p>The figure below shows, the source image, overlayed with the resulting mask, from step #6</p>
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/test-overlay.png"><img class="alignnone size-medium wp-image-950" title="test-overlay" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/test-overlay-300x216.png" alt="" width="300" height="216" /></a></p>
<p>So as you can see, the masks correctly identify the faces the two people in the image.</p>
<h2>The Code</h2>
<p>Here&#8217;s a small Java class that demonstrates how to read an image and apply the process described above.</p>
<p><strong>Note: all the code in the article can be downloaded as a full project at the end of the article.</strong></p>
<pre class="prettyprint">package jjilexample;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import javax.imageio.ImageIO;
import jjil.algorithm.Gray8Rgb;
import jjil.algorithm.RgbAvgGray;
import jjil.core.Image;
import jjil.core.RgbImage;
import jjil.j2se.RgbImageJ2se;
import jjil.algorithm.Gray8DetectHaarMultiScale;

public class Main {
    public static void findFaces(BufferedImage bi, int minScale, int maxScale, File output) {
        try {
            // step #2 - convert BufferedImage to JJIL Image
            RgbImage im = RgbImageJ2se.toRgbImage(bi);
            // step #3 - convert image to greyscale 8-bits
            RgbAvgGray toGray = new RgbAvgGray();
            toGray.push(im);
            // step #4 - initialise face detector with correct Haar profile
            InputStream is  = Main.class.getResourceAsStream("/jjilexample/haar/HCSB.txt");
            Gray8DetectHaarMultiScale detectHaar = new Gray8DetectHaarMultiScale(is, minScale, maxScale);
            // step #5 - apply face detector to grayscale image
            detectHaar.push(toGray.getFront());
            // step #6 - retrieve resulting face detection mask
            Image i = detectHaar.getFront();
            // finally convert back to RGB image to write out to .jpg file
            Gray8Rgb g2rgb = new Gray8Rgb();
            g2rgb.push(i);
            RgbImageJ2se conv = new RgbImageJ2se();
            conv.toFile((RgbImage)g2rgb.getFront(), output.getCanonicalPath());
        } catch (Throwable e) {
            throw new IllegalStateException(e);
        }
    }

    public static void main(String[] args) throws Exception {
        // step #1 - read source image
        BufferedImage bi = ImageIO.read(Main.class.getResourceAsStream("test.jpg"));
        // onto following steps...
        findFaces(bi, 1, 40, new File("c:/Temp/result.jpg")); // change as needed
    }
}</pre>
<h2>Getting Face Rectangles Instead</h2>
<p>It would be more useful in many cases, to get a collection of Rectangles, in coordinate form, instead of an image mask.</p>
<p>There is a version of <em>DetectHaarMultiScale</em> in the JJIL project SVN, which implements a &#8220;getRectangles&#8221; method to retrieve this data. Unfortunately the source in incompatible with the rest of the library in SVN, so it may be WIP or an abandoned version of the code.</p>
<p>To get around this, I created my own version of <em>Gray8DetectHaarMultiScale</em>, which you can download here &#8211; <a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/Gray8DetectHaarMultiScale.zip">Gray8DetectHaarMultiScale</a></p>
<p>Here are the important changes below -</p>
<pre class="prettyprint">    public void push(Image image)  throws jjil.core.Error {
        pushAndReturn(image);
    }

    public List pushAndReturn(Image image) throws jjil.core.Error
    {
        List result = new ArrayList();
....
                    if (hcc.eval(imSub)) {
                        // Found something.
                        nxLastFound = imSub.getXOffset();
                        nyLastFound = imSub.getYOffset();
                        // assign Byte.MAX_VALUE to the feature area so we don't
                        // search it again
                        result.add(new Rect(nxLastFound*nScale, nyLastFound*nScale,
                                this.hcc.getWidth()*nScale,
                                this.hcc.getHeight()*nScale));

                        Gray8Rect gr = new Gray8Rect(nxLastFound,
                                nyLastFound,
                                this.hcc.getWidth(),
                                this.hcc.getHeight(),
                                Byte.MAX_VALUE);
                        gr.push(imMask);
                        imMask = (Gray8Image) gr.getFront();
                     }
....
        return result;
    }</pre>
<p>So now we can call &#8220;pushAndReturn(&#8230;)&#8221; instead of just push() to apply the process to our image, and get a List back of the detected faces. Perfect!</p>
<p>Using this here is a version of the example code above which prints out the rectangles where faces were detected -</p>
<pre class="prettyprint">package jjilexample;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.util.List;
import javax.imageio.ImageIO;
import jjil.algorithm.Gray8Rgb;
import jjil.algorithm.RgbAvgGray;
import jjil.core.Image;
import jjil.core.Rect;
import jjil.core.RgbImage;
import jjil.j2se.RgbImageJ2se;

public class Main {

    public static void findFaces(BufferedImage bi, int minScale, int maxScale, File output) {
        try {
            InputStream is  = Main.class.getResourceAsStream("/jjilexample/haar/HCSB.txt");
            Gray8DetectHaarMultiScale detectHaar = new Gray8DetectHaarMultiScale(is, minScale, maxScale);
            RgbImage im = RgbImageJ2se.toRgbImage(bi);
            RgbAvgGray toGray = new RgbAvgGray();
            toGray.push(im);
            List results = detectHaar.pushAndReturn(toGray.getFront());
            System.out.println("Found "+results.size()+" faces");
            Image i = detectHaar.getFront();
            Gray8Rgb g2rgb = new Gray8Rgb();
            g2rgb.push(i);
            RgbImageJ2se conv = new RgbImageJ2se();
            conv.toFile((RgbImage)g2rgb.getFront(), output.getCanonicalPath());
        } catch (Throwable e) {
            throw new IllegalStateException(e);
        }
    }

    public static void main(String[] args) throws Exception {
        BufferedImage bi = ImageIO.read(Main.class.getResourceAsStream("test.jpg"));
        findFaces(bi, 1, 40, new File("c:/Temp/result.jpg")); // change as needed
    }

}</pre>
<p>If you run this, you will note that it actually detects 3 faces in the image. This is common, as the way the Haar algorithm works, is by resizing the image to different scales and running a fixed size matrix over the image. It is possible for the same face to be detected at different scales and so you end up with rectangles within rectangles. It is a pretty trivial matter to remove these &#8220;extra&#8221; rectangles though by just checking if they are fully contained by another and ignoring them accordingly.</p>
<h2>Download the Project</h2>
<p>To save you some time, here&#8217;s the full example as a Netbeans project that you can download and run, play with, etc. Have fun!</p>
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2011/01/JJILExample.zip">JJILExample</a></p>
<p><em>Photo used in this article courtesy of <a href="http://www.flickr.com/photos/gillpenney/2762820382" target="_blank">Gill Penny</a>.</em>
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F01%2Fjava-facial-recognition-haar-cascade-with-jjil-guide%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2011%2F01%2Fjava-facial-recognition-haar-cascade-with-jjil-guide%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=guides,images,Java,open-source,ui&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/09/how-to-add-dynamic-watermark-to-jpeg-java/' rel='bookmark' title='Adding a Dynamic Watermark to an Image &#8211; Java Web Application'>Adding a Dynamic Watermark to an Image &#8211; Java Web Application</a></li>
<li><a href='http://www.richardnichols.net/2010/08/5-minute-guide-clustering-apache-tomcat/' rel='bookmark' title='5 Minute Guide to Clustering &#8211; Java Web Apps in Tomcat'>5 Minute Guide to Clustering &#8211; Java Web Apps in Tomcat</a></li>
<li><a href='http://www.richardnichols.net/2010/07/detecting-which-browser-in-java-servlet-filter/' rel='bookmark' title='Detecting Which Browser In Java Servlet/Filter'>Detecting Which Browser In Java Servlet/Filter</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=xcWNWdQqmac:_awoVdn1Ixc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=xcWNWdQqmac:_awoVdn1Ixc:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=xcWNWdQqmac:_awoVdn1Ixc:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=xcWNWdQqmac:_awoVdn1Ixc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=xcWNWdQqmac:_awoVdn1Ixc:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=xcWNWdQqmac:_awoVdn1Ixc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=xcWNWdQqmac:_awoVdn1Ixc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=xcWNWdQqmac:_awoVdn1Ixc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=xcWNWdQqmac:_awoVdn1Ixc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=xcWNWdQqmac:_awoVdn1Ixc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=xcWNWdQqmac:_awoVdn1Ixc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=xcWNWdQqmac:_awoVdn1Ixc:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/xcWNWdQqmac" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2011/01/java-facial-recognition-haar-cascade-with-jjil-guide/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2011/01/java-facial-recognition-haar-cascade-with-jjil-guide/</feedburner:origLink></item>
		<item>
		<title>Looking back on 2010…</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/yvV5AN_i-3c/</link>
		<comments>http://www.richardnichols.net/2010/12/looking-back-on-2010/#comments</comments>
		<pubDate>Thu, 30 Dec 2010 23:31:43 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[off-topic]]></category>
		<category><![CDATA[soap-box]]></category>
		<category><![CDATA[visural-common]]></category>
		<category><![CDATA[visural-wicket]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=926</guid>
		<description><![CDATA[Each year I try to look back over my year and take stock of what I&#8217;ve spent my time on, what I&#8217;d like to improve on, things I&#8217;d like to do more, or do less. This year was a very &#8230; <a href="http://www.richardnichols.net/2010/12/looking-back-on-2010/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/03/back-to-dreamhost/' rel='bookmark' title='Back to Dreamhost&#8230;'>Back to Dreamhost&#8230;</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2009/07/photo_3780_20090122.jpg"><img class="alignright size-medium wp-image-68" title="Wine Glasses (FreeDigitalPhotos.net)" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2009/07/photo_3780_20090122-188x300.jpg" alt="" width="188" height="300" /></a>Each year I try to look back over my year and take stock of what I&#8217;ve spent my time on, what I&#8217;d like to improve on, things I&#8217;d like to do more, or do less.</p>
<p>This year was a very busy year for me. February saw the initial release of my open source projects, <a href="http://code.google.com/p/visural-common/" target="_blank">visural-common</a> and <a href="http://code.google.com/p/visural-wicket/">visural-wicket</a>, with two subsequent releases during the year. The <em>visural-wicket</em> library was much more successful that I had guessed and has been downloaded by hundreds of developers of the course of the year.</p>
<p>The rest of the first half of the year were a combination of juggling work, personal life and building <a href="http://www.onmydoorstep.com.au">onmydoorstep.com.au</a>. Ultimately I was not successful in the AppMyState competition that I entered in to, but I continued to work on the site throughout the year with many of the features that I had planned initially finally making their way into the site over the following months.</p>
<p>Depsite not fulfilling its intended purpose, building <em>On My Doorstep</em> was a fantastic experience for me, and expanded my skills greatly, particularly in the areas of CSS, SEO, UI design and server administration. Having work mainly on internally hosted apps in the past, this site was a crash course in startup-dom which has been invaluable.</p>
<p>I dabbled in a little Python this year, having felt like I&#8217;ve &#8220;run my course&#8221; with Java recently. I like Python, but I don&#8217;t think I&#8217;m ready to switch over as yet. I think I&#8217;d like to dabble with a little Scala and Ruby first, before undertaking any &#8220;proper&#8221; project with a new language.</p>
<p>One thing that I felt consistently over the past year, is that I&#8217;ve been spreading myself too thin. I need to spend less time writing code, and try some new things in life.</p>
<p>This is reflected in my goals for 2011 below -</p>
<ul>
<li><strong>Get &#8220;On My Doorstep&#8221; to a &#8220;parkable&#8221; state.</strong><br />
By parkable, I don&#8217;t mean to abandon the project, but simply finish off the work in progress stuff and put it into &#8220;maintenance&#8221; for the time being.</li>
<li><strong>Write a novel.</strong><br />
This will be a new and much needed creative experience. I went from working on animated films in 2006 to working two jobs and cutting code 7 days a week. It&#8217;s time I put my creative energies in a less work-oriented direction.</li>
<li><strong>Dropping 10kgs.</strong><br />
Over the past 4 years I&#8217;ve slowly gained around 10 kgs in weight. This is since I dropped roughly 25 kgs between 2005/2006, dropping from 105kgs to 80kgs. This time it&#8217;s been mainly caused by too much <em>good food</em>, as opposed to bad food, and also excessive hours working with not enough exercise. My plan is to decrease the amount of food I eat (particularly carbs), but also try to schedule in some sustainable exercise.</li>
</ul>
<p>I&#8217;ve kept it to three, as I feel it&#8217;s not realistic to have more than that at a time.</p>
<p>That&#8217;s not to say everything else falls by the way-side, I expect to make another few releases of <em>visural-wicket</em> during the year, and other random projects. I will keep making new blog posts, but maybe not quite as frequently as I have this year (at one stage I was managing 1-2 posts per week).</p>
<p>Some things I&#8217;m looking forward to -</p>
<ul>
<li>spending more time with my family</li>
<li>getting through my bluray home-theatre backlog</li>
<li>Dragon Age 2 (hope they don&#8217;t screw it up, I&#8217;m being optimistic!)</li>
<li>Mass Effect 3 (hope it makes it for 2011)</li>
<li>Diablo 3 (I might be disappointed &#8211; 2012?)</li>
</ul>
<p>Anyway, here&#8217;s to a new year! I hope everyone has a good one, and finds it to be bigger, better and more enjoyable than the last.
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F12%2Flooking-back-on-2010%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F12%2Flooking-back-on-2010%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=off-topic,soap-box,visural-common,visural-wicket&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/03/back-to-dreamhost/' rel='bookmark' title='Back to Dreamhost&#8230;'>Back to Dreamhost&#8230;</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=yvV5AN_i-3c:t-zLh1L4Zpo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=yvV5AN_i-3c:t-zLh1L4Zpo:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=yvV5AN_i-3c:t-zLh1L4Zpo:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=yvV5AN_i-3c:t-zLh1L4Zpo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=yvV5AN_i-3c:t-zLh1L4Zpo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=yvV5AN_i-3c:t-zLh1L4Zpo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=yvV5AN_i-3c:t-zLh1L4Zpo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=yvV5AN_i-3c:t-zLh1L4Zpo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=yvV5AN_i-3c:t-zLh1L4Zpo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=yvV5AN_i-3c:t-zLh1L4Zpo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=yvV5AN_i-3c:t-zLh1L4Zpo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=yvV5AN_i-3c:t-zLh1L4Zpo:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/yvV5AN_i-3c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2010/12/looking-back-on-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2010/12/looking-back-on-2010/</feedburner:origLink></item>
		<item>
		<title>The JCP is a sham…</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/oEkzU2bJeyc/</link>
		<comments>http://www.richardnichols.net/2010/12/the-jcp-is-a-sham/#comments</comments>
		<pubDate>Thu, 23 Dec 2010 10:24:22 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[open-source]]></category>
		<category><![CDATA[soap-box]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=920</guid>
		<description><![CDATA[Reading the minutes from the key JCP EC meeting on Oracle&#8217;s refusal to grant Apache a TCK licence, I think this dialog is very telling - Doug asked Oracle to acknowledge that it was asking the ECs to condone breaking &#8230; <a href="http://www.richardnichols.net/2010/12/the-jcp-is-a-sham/">Continue reading <span class="meta-nav">&#8594;</span></a>
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Reading the <a href="http://jcp.org/aboutJava/communityprocess/summaries/2010/October2010-public-minutes.html">minutes from the key JCP EC meeting</a> on Oracle&#8217;s refusal to grant Apache a TCK licence, I think this dialog is very telling -</p>
<blockquote><p>Doug asked Oracle to acknowledge that it was asking the ECs to condone breaking the JSPA rules. He said that if he was put in a position where he had to condone breaking the rules he would have to resign. <strong>Ken said that he understood, and would regret it if Doug resigned, but pointed out the importance of allowing the conversation to go forward</strong>. Josh Bloch asked again whether Oracle, who were on record as saying that to deny Apache a license without FOU restrictions is a violation of the JSPA, still feel that way. Ken Glueck responded that Oracle were not prepared to answer a legal question. <strong>Josh responded that Oracle had been willing to vote on this matter twice in the past</strong>. Ken responded that this is the situation now. Tim Peierls noted that Oracle has had plenty of time to prepare an answer.</p>
<p><strong>Ken pointed out again that the platform is stuck and we need to move forward.</strong></p></blockquote>
<p>(my emphasis).</p>
<p>Firstly, the &#8220;conversation&#8221; that Oracle are saying &#8220;must go forward&#8221; is the proposed Java SE 7/8 JSRs which were not the focus of this part of the discussion. Secondly Oracle is on the record (in the past) as saying that the TCK licence issue is at conflict with the JSPA rules, but is now unwilling to fix it or even discuss it.</p>
<p>Instead it is apparent from the above and the rest of the discussion too, that Oracle has used the stagnation of the Java platform as leverage for JCP members to turn a blind eye on Oracle&#8217;s unwillingness to address the problems with TCK licencing the overall governance of the JCP.</p>
<p>I can&#8217;t help but be reminded of &#8220;The Empire Strikes Back&#8221; -</p>
<blockquote><p><strong>LANDO</strong>: You said they&#8217;d be left in the city under my supervision!</p>
<p><strong>VADER</strong>: I am altering the deal. Pray I don&#8217;t alter it any further.</p></blockquote>
<p>Given the current state of affairs, JCP members may find they are not equal negotiating terms with Oracle and have a difficult choice between two risky options. Stay with Oracle and hope they make favorable choices, or leave the JCP and hope for a change coming from the community or from the pressure back on Oracle.</p>
<p>Oracle declared at the start of the call that they were prepared to act with or without the ECs blessing. Those remarks should not have gone unchallenged.</p>
<p>The JCP is a sham.
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F12%2Fthe-jcp-is-a-sham%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F12%2Fthe-jcp-is-a-sham%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=Java,open-source,soap-box&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>No related posts.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=oEkzU2bJeyc:37sf7hiid-8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=oEkzU2bJeyc:37sf7hiid-8:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=oEkzU2bJeyc:37sf7hiid-8:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=oEkzU2bJeyc:37sf7hiid-8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=oEkzU2bJeyc:37sf7hiid-8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=oEkzU2bJeyc:37sf7hiid-8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=oEkzU2bJeyc:37sf7hiid-8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=oEkzU2bJeyc:37sf7hiid-8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=oEkzU2bJeyc:37sf7hiid-8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=oEkzU2bJeyc:37sf7hiid-8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=oEkzU2bJeyc:37sf7hiid-8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=oEkzU2bJeyc:37sf7hiid-8:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/oEkzU2bJeyc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2010/12/the-jcp-is-a-sham/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2010/12/the-jcp-is-a-sham/</feedburner:origLink></item>
		<item>
		<title>visural-wicket 0.6.5 release is available!</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/OfEVeV9HtYE/</link>
		<comments>http://www.richardnichols.net/2010/11/visural-wicket-0-6-5-release-is-available/#comments</comments>
		<pubDate>Thu, 25 Nov 2010 11:20:19 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Wicket]]></category>
		<category><![CDATA[open-source]]></category>
		<category><![CDATA[releases]]></category>
		<category><![CDATA[visural-wicket]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[wicket]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=899</guid>
		<description><![CDATA[It&#8217;s taken longer than I&#8217;d hoped, but the next release of the visural-wicket library for Apache Wicket is now available &#8211; 0.6.5 This version is mostly a minor enhancement and fix release, but includes almost 6 months worth of patches &#8230; <a href="http://www.richardnichols.net/2010/11/visural-wicket-0-6-5-release-is-available/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2011/09/visural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5/' rel='bookmark' title='visural-wicket 0.7.0 release with support for Wicket 1.5'>visural-wicket 0.7.0 release with support for Wicket 1.5</a></li>
<li><a href='http://www.richardnichols.net/2010/06/visural-wicket-0-6-released-new-components/' rel='bookmark' title='visural-wicket 0.6 released &#8211; lots of new components!'>visural-wicket 0.6 released &#8211; lots of new components!</a></li>
<li><a href='http://www.richardnichols.net/2009/11/announcing-visural-wicket/' rel='bookmark' title='Announcing &#8211; visural-wicket'>Announcing &#8211; visural-wicket</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s taken longer than I&#8217;d hoped, but the <a href="http://code.google.com/p/visural-wicket/downloads/list" target="_blank">next release of the visural-wicket library</a> for Apache Wicket is now available &#8211; <a href="http://code.google.com/p/visural-wicket/downloads/detail?name=visural-wicket-0.6.5.zip" target="_blank">0.6.5</a></p>
<p>This version is mostly a minor enhancement and fix release, but includes almost 6 months worth of patches based on production use of the library.</p>
<p>There are a number of fixes and enhancements based on user requests, and some new features and fixes based on my own work.</p>
<p><strong><span style="text-decoration: underline;">Note:</span></strong> this release separates the <em>visural-common</em> and <em>visural-wicket</em> library JARs.</p>
<p>Previously they were bundled together into a single JAR file, however this caused issues with release cycles for each library. However, I have included a <em>visural-common-and-wicket-0.6.5.jar</em> in the release package which leaves them bundled if you&#8217;d rather not have two JAR files attached to your project.</p>
<p><span style="font-size: 23px; color: #000000; line-height: 35px;">Enhancements</span></p>
<h3><strong>New Component:</strong> Client-side Tab-pages component</h3>
<p>This is a javascript based tab control, which renders all tabs contents into the page at render time, allowing instant tab switching after render.</p>
<p>Unlike other implementations I&#8217;ve seen, this tab control retains tab state even when updating via Ajax.</p>
<p>It also has an intuitive implementation pattern that requires only adding a wicket:id to a single wrapping &lt;div&gt; tag containing the tab&#8217;s &lt;div&gt;&#8217;s.</p>
<h3><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/11/Visural-Wicket-Examples-Client-side-Tabs-Javascript-Google-Chrome_2010-11-25_21-45-46.png"><img class="aligncenter size-medium wp-image-900" title="Visural Wicket Examples - Client-side Tabs (Javascript)" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/11/Visural-Wicket-Examples-Client-side-Tabs-Javascript-Google-Chrome_2010-11-25_21-45-46-300x151.png" alt="example of how the tab control looks" width="300" height="151" /></a></h3>
<h3><a rel="nofollow" href="http://fancybox.net/">Fancybox</a> updated to latest v1.3.1</h3>
<p>The new version of Fancybox (the image gallery component) has been integrated into visural-wicket, and it features an improved API with more options.</p>
<p>These options have been exposed in visural-wicket and javadoc has been included for each based on Fancybox&#8217;s API docs.</p>
<h3>Example app includes InputHint example</h3>
<p>The &#8220;InputHintBehavior&#8221; hasn&#8217;t changed at all, but there is now an example for it in the &#8220;live demo site&#8221; and examples application.</p>
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/11/Visural-Wicket-Examples-Input-Hint-Example-Google-Chrome_2010-11-25_21-58-41.png"><img class="aligncenter size-medium wp-image-901" title="Visural Wicket Examples - Input Hint Example" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/11/Visural-Wicket-Examples-Input-Hint-Example-Google-Chrome_2010-11-25_21-58-41-300x134.png" alt="" width="300" height="134" /></a></p>
<h3>DropDown control changes</h3>
<p>The DropDown control has had several fixes and improvements.</p>
<ul>
<li>The &#8220;Show All&#8221; / &#8220;Filter List&#8221; feature that would appear as the first line in the list is now optional and can be disabled.</li>
<li>The &#8220;arrow icon&#8221; that appears at the right of the control can now be switched off. This may be desirable when working as a &#8220;suggest&#8221; or &#8220;auto-complete&#8221; style control, rather than a DropDownChoice style control.</li>
<li>The drop list now appears as the width of the overall box and is positioned more consistently with the CSS styling of the control.</li>
</ul>
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/11/Visural-Wicket-Examples-Drop-Down-Combobox-Google-Chrome_2010-11-25_22-02-39.png"><img class="aligncenter size-medium wp-image-902" title="Visural Wicket Examples - Drop Down (Combobox) " src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/11/Visural-Wicket-Examples-Drop-Down-Combobox-Google-Chrome_2010-11-25_22-02-39-300x170.png" alt="" width="300" height="170" /></a></p>
<h3>Dialog&#8217;s Open / Close Javascript methods now <em>protected</em> access</h3>
<p>The dialog open and close Javascript generation methods are now protected. This allows developers to pre-fix or post-fix the open and close events with their own Javascript callbacks.</p>
<h3>All Components &#8211; Allow disable of JS &amp; CSS static header contributions</h3>
<p>To assist with static resource packing and packaging all components now have a -</p>
<pre class="prettyprint">    /**
     * Override and return false to suppress static Javascript and CSS contributions.
     * (May be desired if you are concatenating / compressing resources as part of build process)
     * @return
     */
    protected boolean autoAddToHeader() {
        return true;
    }</pre>
<p>Overriding, and returning false here will cause the component to avoid adding it&#8217;s resource contributions during construction. You are then free to repackage them as you see fit as part of your build process.</p>
<h3>No longer necessary to manually add excanvas.js for BeautyTipsBehavior</h3>
<p>Previously users had to manually add the ExCanvas.js header contributor for Internet Explorer support for the tool-tip behaviour &#8211; BeautyTips. This contributor will now be added automatically, so everything works &#8220;out of the box&#8221;. This won&#8217;t affect code that adds it manually, so it&#8217;s just a simplification for new users.</p>
<h3>JQuery 1.4+ and other JS library compatibility</h3>
<p>JQuery 1.4 comptability has been introduced and all components should now work under v1.4.</p>
<p>The JQuery resource reference now takes a version parameter and 1.3 and 1.4 versions of JQuery are included with visural-wicket out of the box.</p>
<p>For backward compatibility, if no version is provided 1.3 is used as the default. For existing projects this is no change.</p>
<p>Additionally, all of the generated code now uses &#8220;jQuery(&#8230;)&#8221; rather than &#8220;$(&#8230;)&#8221; so if you are using multiple libraries overriding the &#8220;$(..)&#8221; function then you should now be able to use visural-wicket in your project.</p>
<h3>All components implement security interfaces and have a serialVersionUID</h3>
<p>All of the visural-wicket components now implement ISecureEnableComponent, ISecureRenderComponent which lets them work seamlessly with the security features built into the library.</p>
<p>In additional all of the classes that may end up Serialized in a user session now have a serialVersionUID = 1, to reduce deserialization issues between releases.</p>
<h3>Add German date form (dd.mm.yyyy) to DateInputBehavior</h3>
<p>As per user request, the german-style date format of dd.mm.yyyy has been added DateFormat.DD_MM_YYYY_DOTS.</p>
<h2>Bug Fixes</h2>
<ul>
<li>Issues with rendering of modal dialog when using AJAX refreshes <a rel="nofollow" href="http://code.google.com/p/visural-wicket/issues/detail?id=49">Fix #49</a> <a rel="nofollow" href="http://code.google.com/p/visural-wicket/issues/detail?id=51">Fix #51</a></li>
<li><a rel="nofollow" href="http://code.google.com/p/visural-wicket/issues/detail?id=58">Input Hint and InvokeClientSideFormSubmitHandler broken by Wicket 1.4.11 (Fix #58)</a></li>
<li><a rel="nofollow" href="http://code.google.com/p/visural-wicket/issues/detail?id=59">Date Input popup can appear in the wrong location (Fix #59)</a></li>
<li><a rel="nofollow" href="http://code.google.com/p/visural-wicket/issues/detail?id=62">Depending on DOM placement, modal dialog overlay doesn&#8217;t cover whole screen (Fix #60)</a></li>
<li><a rel="nofollow" href="http://code.google.com/p/visural-wicket/issues/detail?id=62">Modal Indicator components do not appear above Modal Dialog (Fix #62)</a></li>
<li><a rel="nofollow" href="http://code.google.com/p/visural-wicket/issues/detail?id=72">Can&#8217;t select bottom record in a DropDown (firefox)</a></li>
</ul>
<p>So as you can see, this is a pretty decent release even if it was a while coming <img src='http://d3araz99qvcc8b.cloudfront.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Hope you find these changes useful, as always I welcome feedback, so if you have any ideas, questions or problems then please drop me a line.
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F11%2Fvisural-wicket-0-6-5-release-is-available%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F11%2Fvisural-wicket-0-6-5-release-is-available%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=Java,open-source,releases,visural-wicket,web,wicket&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2011/09/visural-wicket-0-7-0-release-with-support-for-apache-wicket-1-5/' rel='bookmark' title='visural-wicket 0.7.0 release with support for Wicket 1.5'>visural-wicket 0.7.0 release with support for Wicket 1.5</a></li>
<li><a href='http://www.richardnichols.net/2010/06/visural-wicket-0-6-released-new-components/' rel='bookmark' title='visural-wicket 0.6 released &#8211; lots of new components!'>visural-wicket 0.6 released &#8211; lots of new components!</a></li>
<li><a href='http://www.richardnichols.net/2009/11/announcing-visural-wicket/' rel='bookmark' title='Announcing &#8211; visural-wicket'>Announcing &#8211; visural-wicket</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=OfEVeV9HtYE:5GRYssg3lHU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=OfEVeV9HtYE:5GRYssg3lHU:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=OfEVeV9HtYE:5GRYssg3lHU:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=OfEVeV9HtYE:5GRYssg3lHU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=OfEVeV9HtYE:5GRYssg3lHU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=OfEVeV9HtYE:5GRYssg3lHU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=OfEVeV9HtYE:5GRYssg3lHU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=OfEVeV9HtYE:5GRYssg3lHU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=OfEVeV9HtYE:5GRYssg3lHU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=OfEVeV9HtYE:5GRYssg3lHU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=OfEVeV9HtYE:5GRYssg3lHU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=OfEVeV9HtYE:5GRYssg3lHU:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/OfEVeV9HtYE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2010/11/visural-wicket-0-6-5-release-is-available/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2010/11/visural-wicket-0-6-5-release-is-available/</feedburner:origLink></item>
		<item>
		<title>How to: 10000 photos from Adobe Photoshop Album 2 to Picasa</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/_Q3FS7r8J3s/</link>
		<comments>http://www.richardnichols.net/2010/11/how-to-10000-photos-from-adobe-photoshop-album-2-to-picasa/#comments</comments>
		<pubDate>Wed, 03 Nov 2010 00:34:25 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[off-topic]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=874</guid>
		<description><![CDATA[If you&#8217;re (un)fortunate enough to have your entire photo collection stored in the now-ancient Adobe Photoshop Album 2, you&#8217;re going to be rather stuck. In theory, it should be possible to do &#8220;backup&#8221; operation from Album 2.0 and import into &#8230; <a href="http://www.richardnichols.net/2010/11/how-to-10000-photos-from-adobe-photoshop-album-2-to-picasa/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2009/08/netbeans-6-7-broke-my-parameterized-tests/' rel='bookmark' title='NetBeans 6.7 Broke My Parameterized Tests'>NetBeans 6.7 Broke My Parameterized Tests</a></li>
<li><a href='http://www.richardnichols.net/2010/07/java-web-datauris-lesscss-javascript-css-compression/' rel='bookmark' title='ResourceTransformFilter &#8211; DataUris, LessCSS, Javascript and CSS Compression Made Easy!'>ResourceTransformFilter &#8211; DataUris, LessCSS, Javascript and CSS Compression Made Easy!</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re (un)fortunate enough to have your entire photo collection stored in the now-ancient <em>Adobe Photoshop Album 2</em>, you&#8217;re going to be rather stuck.</p>
<p>In theory, it should be possible to do &#8220;backup&#8221; operation from <em>Album 2.0</em> and import into it&#8217;s successor <em>Photoshop Elements</em>.</p>
<p>My research suggested that this may be hit-and-miss with several people experiencing bugs that rendered the backup useless on import. I tried &#8211; and experienced exactly the same issue.</p>
<p>Anyhow, after some consideration I decided to switch to <em>Picasa</em>, since it&#8217;s -</p>
<ul>
<li>free</li>
<li>multi-platform</li>
<li>has face recognition</li>
<li>integrates with my Google account</li>
<li>stores meta data inside the image files by default (i.e. captions &amp; tags)</li>
</ul>
<p>So the next challenge was &#8211; how do I get all the photos from <em>Photoshop Album</em> to <em>Picasa</em> with all the meta-data intact?</p>
<h3>Step 1 &#8211; Get the meta-data out of Photoshop Album</h3>
<p>Fortunately someone has already solved this part of the problem. I found <a href="http://www.impulseadventure.com/photo/convert-psa-imatch.html" target="_blank">this post here</a> which links to a (no longer available) tool for reading the meta data out of Album&#8217;s (Access format?) ODBC data source.</p>
<p>I&#8217;ve cached a copy of the tool here &#8211; <a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/11/psatools.zip">psatools.zip</a></p>
<p>I tried running the tool on the actual Photoshop Album database in the C:\Program Files folder, however it failed with a weird error. I found a workaround to that issue &#8211; export a full backup through Photoshop Album, and then run the PSATool on the backup file, e.g.</p>
<pre>psatool /if-print /fp /xml "backup.psb" &gt; output.xml</pre>
<p>This will output the content of the Photoshop Album backup as XML with all the meta-data intact (captions, tags, albums). The &#8220;/fp&#8221; switch is required to output the full path to the original image file. We&#8217;ll need this for the following step.</p>
<h3>Step 2 &#8211; Clean up, reorganise and apply meta-data to image files</h3>
<p>There are two components required for this step.</p>
<p>One is <a href="http://www.sno.phy.queensu.ca/~phil/exiftool/" target="_blank">exiftool </a>- a command line tool for reading and writing meta data from image files.</p>
<p>The second is a custom Java program which I wrote (listed below). The Java program iterates through the XML meta data exported from the <em>Photoshop Album </em>backup and simultaneously reorganises (renames and copies) the images based on their captions and collections and adds this meta data (captions and tags) into the image using <em>exiftool</em>.</p>
<p>You&#8217;ll need a couple of libraries for the Java code to run -</p>
<ul>
<li><a href="http://javolution.org/" target="_blank">Javolution</a> &#8211; a fast XML parser</li>
<li><a href="http://code.google.com/p/visural-common">visural-common</a> &#8211; my utility library which short-hands a lot of common stuff</li>
</ul>
<p>You&#8217;ll probably also need to revise the code below to suit your own needs. It&#8217;s posted as a starting point only.</p>
<p>Be aware this is really rough and nasty code &#8211; it&#8217;s not intended to be used more than once. <img src='http://d3araz99qvcc8b.cloudfront.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>It assumes that the output XML from step 1 is in &#8220;I:\Temp\output.xml&#8221;, the source picture files are accessible on the current PC and that you want to output to &#8220;I:\Temp\output&#8221; folder for the converted images.</p>
<pre>import com.visural.common.Function;
import com.visural.common.Function;
import com.visural.common.StringUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.HashSet;
import java.util.Set;
import javolution.text.CharArray;
import javolution.xml.stream.XMLInputFactory;
import javolution.xml.stream.XMLStreamConstants;
import javolution.xml.stream.XMLStreamReader;

/**
 *
 * @author Richard Nichols
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("i:/temp/output.xml"));

        Set&lt;Photo&gt; photos = new HashSet&lt;Photo&gt;();
        Photo photo = null;
        CharArray blank = new CharArray("");

        while (reader.getEventType() != XMLStreamConstants.END_DOCUMENT) {
            switch (reader.next()) {
                case XMLStreamConstants.START_ELEMENT:
                    if (reader.getLocalName().equals("file")) {
                        // Reads primitive types (int) attributes directly (no memory allocation).
                        String type = Function.nvl(reader.getAttributeValue(null, "type"), blank).toString();
                        String name = Function.nvl(reader.getAttributeValue(null, "name"), blank).toString();
                        String caption = Function.nvl(reader.getAttributeValue(null, "caption"), blank).toString();
                        if (type.equals("photo")) {
                            if (name.toLowerCase().endsWith(".jpg") || name.toLowerCase().endsWith(".jpeg")) {
                                photo = new Photo(name, caption);
                                photos.add(photo);
                            } else {
                                System.out.println("Skipped photo: "+name);
                            }
                        }
                    }
                    if (reader.getLocalName().equals("folder")) {
                        if (photo != null) {
                            String type = Function.nvl(reader.getAttributeValue(null, "type"), blank).toString();
                            String value = Function.nvl(reader.getElementText(), blank).toString();
                            if (StringUtil.isNotBlankStr(value)) {
                                if ("Tag".equalsIgnoreCase(type)) {
                                    photo.getTags().add(value);
                                }
                                if ("Collection".equalsIgnoreCase(type)) {
                                    if (value.startsWith("&#92;"")) {
                                        value = value.substring(1);
                                    }
                                    if (value.endsWith("&#92;"")) {
                                        value = value.substring(0, value.length()-1);
                                    }
                                    photo.getCollections().add(value);
                                }
                            }
                        }
                    }
                    break;
                case XMLStreamConstants.END_ELEMENT:
                    if (reader.getLocalName().equals("file")) {
                        photo = null;
                    }
                    break;
            }
        }
        reader.close(); 

        // fix filenames &amp; collections
        Set&lt;String&gt; collections = new HashSet&lt;String&gt;();
        int numTwo = 0;
        for (Photo p : photos) {
            // remove any unwanted collections here
            p.getCollections().remove("unwanted collection");

            if (p.getCollections().isEmpty()) {
                p.getCollections().add("No Collection");
            } else if (p.getCollections().size() &gt; 1) {
                numTwo++;
            }
            collections.addAll(p.getCollections());
        }

        for (String s : collections) {
            new File("i:/temp/output/" + safeFilename(s)).mkdirs();
        }

        int n = 0;
        for (Photo p : photos) {
            n++;
            if (n%50 == 0) {
                System.out.println(n+" of "+photos.size());
            }

            String collection = p.getCollections().iterator().next();
            File i = new File(p.getFilename());
            if (!i.exists()) {
                System.err.println("MISSING FILE: "+p.getFilename());
                continue;
            }
            String outname = p.getCaption();
            if (StringUtil.isBlankStr(outname)) {
                outname = p.getFilename().substring(p.getFilename().lastIndexOf('&#92;&#92;'));
            }
            File o = new File("i:/temp/output/" + safeFilename(collection)+"/"+safeFilename(outname)+".jpg");
            if (o.exists()) { // allows continue after partial conversion
                continue;
            }
            copyFile(i, o);
            tagAndCapFile(o, p.getCaption(), p.getTags());
        }
    }

    private static String safeFilename(String name) {
        for (char c : StringUtil.FILENAME_INVALID_CHARS) {
            name = name.replace(String.valueOf(c), " ");
        }
        return name.trim();
    }

    public static void copyFile(File in, File out) throws IOException {
        FileChannel inChannel = new FileInputStream(in).getChannel();
        FileChannel outChannel = new FileOutputStream(out).getChannel();
        try {
            inChannel.transferTo(0, inChannel.size(),
                    outChannel);
        } catch (IOException e) {
            throw e;
        } finally {
            if (inChannel != null) {
                inChannel.close();
            }
            if (outChannel != null) {
                outChannel.close();
            }
        }
    }

    private static void tagAndCapFile(File o, String caption, Set&lt;String&gt; tags) throws IOException, InterruptedException {
        //System.out.println("Tagging and capping: "+o.getCanonicalPath());
        {
            String run = "lib&#92;&#92;exiftool.exe &#92;"-iptc:caption-abstract="+caption.replace('&#92;"', ' ')+"&#92;" &#92;""+o.getCanonicalPath()+"&#92;" -overwrite_original";
            Process p = Runtime.getRuntime().exec(run);
            int i = p.waitFor();
            if (i != 0) {
                System.err.println("Failed running: "+i+"&#92;n"+run);
            }
        }

        for (String tag : tags) {
            String run = "lib&#92;&#92;exiftool.exe &#92;"-iptc:keywords+="+tag.replace('&#92;"', ' ').trim()+"&#92;" &#92;""+o.getCanonicalPath()+"&#92;" -overwrite_original";
            Process p = Runtime.getRuntime().exec(run);
            int i = p.waitFor();
            if (i != 0) {
                System.err.println("Failed running: "+i+"&#92;n"+run);
            }
        }

    }
}

/**
 *
 * @author Richard Nichols
 */
public class Photo {
    private String filename;
    private String caption;
    private final Set&lt;String&gt; collections = new HashSet&lt;String&gt;();
    private final Set&lt;String&gt; tags = new HashSet&lt;String&gt;();

    public Photo(String filename, String caption) {
        this.filename = filename;
        this.caption = caption;
    }

    public String getCaption() {
        return caption;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    public String getFilename() {
        return filename;
    }

    public Set&lt;String&gt; getCollections() {
        return collections;
    }

    public Set&lt;String&gt; getTags() {
        return tags;
    }

}</pre>
<p>After an hour or so while this buzzed away on 10000 odd pics I then ended up with a nicely arranged image collection with all the meta-data attached!
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F11%2Fhow-to-10000-photos-from-adobe-photoshop-album-2-to-picasa%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F11%2Fhow-to-10000-photos-from-adobe-photoshop-album-2-to-picasa%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=automation,Java,off-topic&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2009/08/netbeans-6-7-broke-my-parameterized-tests/' rel='bookmark' title='NetBeans 6.7 Broke My Parameterized Tests'>NetBeans 6.7 Broke My Parameterized Tests</a></li>
<li><a href='http://www.richardnichols.net/2010/07/java-web-datauris-lesscss-javascript-css-compression/' rel='bookmark' title='ResourceTransformFilter &#8211; DataUris, LessCSS, Javascript and CSS Compression Made Easy!'>ResourceTransformFilter &#8211; DataUris, LessCSS, Javascript and CSS Compression Made Easy!</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=_Q3FS7r8J3s:f8JcDiHYjGw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=_Q3FS7r8J3s:f8JcDiHYjGw:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=_Q3FS7r8J3s:f8JcDiHYjGw:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=_Q3FS7r8J3s:f8JcDiHYjGw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=_Q3FS7r8J3s:f8JcDiHYjGw:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=_Q3FS7r8J3s:f8JcDiHYjGw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=_Q3FS7r8J3s:f8JcDiHYjGw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=_Q3FS7r8J3s:f8JcDiHYjGw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=_Q3FS7r8J3s:f8JcDiHYjGw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=_Q3FS7r8J3s:f8JcDiHYjGw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=_Q3FS7r8J3s:f8JcDiHYjGw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=_Q3FS7r8J3s:f8JcDiHYjGw:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/_Q3FS7r8J3s" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2010/11/how-to-10000-photos-from-adobe-photoshop-album-2-to-picasa/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2010/11/how-to-10000-photos-from-adobe-photoshop-album-2-to-picasa/</feedburner:origLink></item>
		<item>
		<title>Implementing a “Draft Mode” with Apache Wicket Forms</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/HiB2Dixmp9I/</link>
		<comments>http://www.richardnichols.net/2010/10/implementing-a-draft-mode-with-apache-wicket-forms/#comments</comments>
		<pubDate>Wed, 20 Oct 2010 04:27:11 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Wicket]]></category>
		<category><![CDATA[guides]]></category>
		<category><![CDATA[ui]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[wicket]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=807</guid>
		<description><![CDATA[A question came up on wicket-users recently about whether it&#8217;s possible to implement a form in Wicket whereby you can bypass the validation temporarily so that users could save prior to submitting the form. Think something along the lines of &#8230; <a href="http://www.richardnichols.net/2010/10/implementing-a-draft-mode-with-apache-wicket-forms/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2011/09/securing-wicket-with-visural-wicket/' rel='bookmark' title='Implementing security in Wicket with visural-wicket'>Implementing security in Wicket with visural-wicket</a></li>
<li><a href='http://www.richardnichols.net/2010/06/less-css-in-wicket-using-mozilla-rhino/' rel='bookmark' title='LessCSS available in Java and Wicket &#8211; less.js'>LessCSS available in Java and Wicket &#8211; less.js</a></li>
<li><a href='http://www.richardnichols.net/2010/06/visural-wicket-0-6-released-new-components/' rel='bookmark' title='visural-wicket 0.6 released &#8211; lots of new components!'>visural-wicket 0.6 released &#8211; lots of new components!</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/10/Compose-Mail.png"><img src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/10/Compose-Mail-300x280.png" alt="" title="Compose Mail" width="300" height="280" class="alignright size-medium wp-image-858" /></a>A question came up on <em>wicket-users</em> recently about whether it&#8217;s possible to implement a form in Wicket whereby you can bypass the validation temporarily so that users could save prior to submitting the form.</p>
<p>Think something along the lines of &#8220;save draft&#8221; in a mail client like GMail.</p>
<p>It&#8217;s possible but requires a bit of Wicket-foo. I did post a short snippet on the mailing list, but I thought a longer explanation might be helpful.</p>
<p>First of all, let&#8217;s get something out of the way; it&#8217;s not possible to accept data that the model backing your components do not accept.</p>
<p>For example, you can&#8217;t accept &#8220;asdf&#8221; into a model field backed by an Integer &#8211; it ain&#8217;t going to work whichever way you slice it. <em>(Though, you can accept any input if you build a model that consists only of Strings and add validation for numerics etc. further down the line).</em></p>
<p>Here&#8217;s the key steps to making a &#8220;draft mode&#8221; Wicket form -</p>
<ol>
<li>Override the form&#8217;s process() method to set a &#8220;draft mode&#8221; flag based on the component that submitted the form.</li>
<li>Create validators that apply based on the mode that form is in.</li>
<li>You&#8217;re probably going to have multiple submit buttons on the screen which do different things, thus your form&#8217;s onSubmit() handler will probably do nothing.</li>
</ol>
<p>This means that you can&#8217;t use Wicket&#8217;s built in validators as they are applied regardless of any notion of &#8220;mode&#8221; that you may have in your form.</p>
<p>Here&#8217;s an example of how this might hang together:</p>
<pre class="prettyprint">
class MyForm extends Form {
    private final SubmitButton submitButton;
    private final SubmitButton saveDraftButton;
    private final TextField textField;
    private boolean draftMode = true;

    public MyForm(String id) {
        super(id);
        add(textField = new TextField("textField"));
        add(saveDraftButton= new SubmitButton("draft") {
            @Override
            public void onSubmit() {
                myService.saveDraft(); // or whatever
            }
        });
        add(submitButton = new SubmitButton("submit") {
            @Override
            public void onSubmit() {
                myService.submit(); // or whatever
            }
        });
        // works like a required field validator
        textField.add(new IValidator() {
            @Override
            public void validate(IValidatable validatable) {
                if (validatable != null &#038;&#038; !MyForm.this.draftMode &#038;&#038;
                    validatable.getValue() == null || validatable.getValue().toString().equals(""))
                {
                    validatable.error(new IValidationError() {
                        public String getErrorMessage(IErrorMessageSource messageSource) {
                            return "Required.";
                        }
                    });
                }
            }
        });
    }

    @Override
    public void process(IFormSubmittingComponent submittingComponent) {
        draftMode = !(submittingComponent == submitButton);
        super.process(submittingComponent);
    }

    @Override
    public void onSubmit() {
        // do nothing
    }
}
</pre>
<p>This work can be standardised in your own sub-class of Form for example, with a bunch of validators that integrate with it.</p>
<p>Also, you can support even more complex use-cases by using a &#8220;mode&#8221; enum instead of a simple &#8220;draft&#8221; boolean. And make all the validators conditional on Mode.</p>
<p>This approach works just fine, but it would be nice if there was some sort of formal abstraction in Wicket to do this, since the current approach assumes quite a bit about the type of applications that will be implemented.
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F10%2Fimplementing-a-draft-mode-with-apache-wicket-forms%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F10%2Fimplementing-a-draft-mode-with-apache-wicket-forms%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=guides,Java,ui,web,wicket&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2011/09/securing-wicket-with-visural-wicket/' rel='bookmark' title='Implementing security in Wicket with visural-wicket'>Implementing security in Wicket with visural-wicket</a></li>
<li><a href='http://www.richardnichols.net/2010/06/less-css-in-wicket-using-mozilla-rhino/' rel='bookmark' title='LessCSS available in Java and Wicket &#8211; less.js'>LessCSS available in Java and Wicket &#8211; less.js</a></li>
<li><a href='http://www.richardnichols.net/2010/06/visural-wicket-0-6-released-new-components/' rel='bookmark' title='visural-wicket 0.6 released &#8211; lots of new components!'>visural-wicket 0.6 released &#8211; lots of new components!</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=HiB2Dixmp9I:1G3DMqQKsTQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=HiB2Dixmp9I:1G3DMqQKsTQ:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=HiB2Dixmp9I:1G3DMqQKsTQ:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=HiB2Dixmp9I:1G3DMqQKsTQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=HiB2Dixmp9I:1G3DMqQKsTQ:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=HiB2Dixmp9I:1G3DMqQKsTQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=HiB2Dixmp9I:1G3DMqQKsTQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=HiB2Dixmp9I:1G3DMqQKsTQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=HiB2Dixmp9I:1G3DMqQKsTQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=HiB2Dixmp9I:1G3DMqQKsTQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=HiB2Dixmp9I:1G3DMqQKsTQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=HiB2Dixmp9I:1G3DMqQKsTQ:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/HiB2Dixmp9I" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2010/10/implementing-a-draft-mode-with-apache-wicket-forms/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2010/10/implementing-a-draft-mode-with-apache-wicket-forms/</feedburner:origLink></item>
		<item>
		<title>Getting a non-relative (absolute) URL for a Wicket page</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/cG8dO2OaXe0/</link>
		<comments>http://www.richardnichols.net/2010/10/getting-a-non-relative-absolute-url-for-a-wicket-page/#comments</comments>
		<pubDate>Tue, 12 Oct 2010 01:27:38 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Wicket]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[wicket]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=840</guid>
		<description><![CDATA[Just a quick Wicket tid-bit I found today &#8211; generally with Wicket, when you create a BookmarkablePageLink or use &#8220;urlFor(&#8230;)&#8220;, the resulting URL is stated as a relative path, e.g. &#8220;../../something/mypage&#8221; (i.e. those that contain &#8220;..&#8221;). Sometimes you need to &#8230; <a href="http://www.richardnichols.net/2010/10/getting-a-non-relative-absolute-url-for-a-wicket-page/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/03/apache-wicket-force-page-reload-to-fix-ajax-back/' rel='bookmark' title='Wicket &#8211; forcing page reload on browser back button&#8230;'>Wicket &#8211; forcing page reload on browser back button&#8230;</a></li>
<li><a href='http://www.richardnichols.net/2011/09/securing-wicket-with-visural-wicket/' rel='bookmark' title='Implementing security in Wicket with visural-wicket'>Implementing security in Wicket with visural-wicket</a></li>
<li><a href='http://www.richardnichols.net/2011/08/demystifying-httpservletrequest-properties/' rel='bookmark' title='Demystifying HttpServletRequest properties&#8230;'>Demystifying HttpServletRequest properties&#8230;</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>Just a quick Wicket tid-bit I found today &#8211; generally with Wicket, when you create a <em>BookmarkablePageLink </em>or use &#8220;<em>urlFor(&#8230;)</em>&#8220;, the resulting URL is stated as a relative path, e.g. &#8220;<em>../../something/mypage</em>&#8221; (i.e. those that contain &#8220;..&#8221;).</p>
<p>Sometimes you need to get a &#8220;fully qualified&#8221; URL such as   &#8220;<em>/pages/something/mypage</em>&#8221; or &#8220;<em>http://localhost:8080/myapp/pages/something/mypage</em>&#8220;.</p>
<p>Although there is nothing on the core Wicket objects to do this, there is a little utility included with Wicket which will allow you to convert a relative URL to an absolute URL &#8211; <a href="http://wicket.apache.org/apidocs/1.4/org/apache/wicket/protocol/http/RequestUtils.html#toAbsolutePath%28java.lang.String%29" target="_blank">org.apache.wicket.protocol.http.RequestUtils</a></p>
<p>It&#8217;s dead simple to use &#8211; just call <em>RequestUtils.toAbsolutePath(&#8230;) </em>and pass in the relative URL as a string. Assuming the relative URL was generated from the current Wicket Page, it will convert from &#8220;<em>../../something/mypage</em>&#8221; to &#8220;<em>http://localhost:8080/myapp/pages/something/mypage</em>&#8221;</p>
<p>Handy!
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F10%2Fgetting-a-non-relative-absolute-url-for-a-wicket-page%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F10%2Fgetting-a-non-relative-absolute-url-for-a-wicket-page%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=Java,tips,web,wicket&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/03/apache-wicket-force-page-reload-to-fix-ajax-back/' rel='bookmark' title='Wicket &#8211; forcing page reload on browser back button&#8230;'>Wicket &#8211; forcing page reload on browser back button&#8230;</a></li>
<li><a href='http://www.richardnichols.net/2011/09/securing-wicket-with-visural-wicket/' rel='bookmark' title='Implementing security in Wicket with visural-wicket'>Implementing security in Wicket with visural-wicket</a></li>
<li><a href='http://www.richardnichols.net/2011/08/demystifying-httpservletrequest-properties/' rel='bookmark' title='Demystifying HttpServletRequest properties&#8230;'>Demystifying HttpServletRequest properties&#8230;</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=cG8dO2OaXe0:UCaTUNwLZ8E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=cG8dO2OaXe0:UCaTUNwLZ8E:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=cG8dO2OaXe0:UCaTUNwLZ8E:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=cG8dO2OaXe0:UCaTUNwLZ8E:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=cG8dO2OaXe0:UCaTUNwLZ8E:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=cG8dO2OaXe0:UCaTUNwLZ8E:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=cG8dO2OaXe0:UCaTUNwLZ8E:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=cG8dO2OaXe0:UCaTUNwLZ8E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=cG8dO2OaXe0:UCaTUNwLZ8E:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=cG8dO2OaXe0:UCaTUNwLZ8E:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=cG8dO2OaXe0:UCaTUNwLZ8E:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=cG8dO2OaXe0:UCaTUNwLZ8E:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/cG8dO2OaXe0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2010/10/getting-a-non-relative-absolute-url-for-a-wicket-page/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2010/10/getting-a-non-relative-absolute-url-for-a-wicket-page/</feedburner:origLink></item>
		<item>
		<title>Guice / Java IoC best practices – using annotations for configuration</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/6tbCIYPwO7w/</link>
		<comments>http://www.richardnichols.net/2010/09/guice-java-ioc-best-practices-annotation-configuration/#comments</comments>
		<pubDate>Wed, 29 Sep 2010 03:01:21 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[developer]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[guice]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=812</guid>
		<description><![CDATA[18 months ago I introduced Guice 2.0 into my workplace development team. So far it has been doing a good job of making inversion of control / dependency injection approachable, light-weight and helpful for the whole team. The biggest issue &#8230; <a href="http://www.richardnichols.net/2010/09/guice-java-ioc-best-practices-annotation-configuration/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/09/session-replication-with-guice-java-web-applications/' rel='bookmark' title='Clustering Guice Java Web Applications'>Clustering Guice Java Web Applications</a></li>
<li><a href='http://www.richardnichols.net/2009/06/the-5-minute-guice-primer/' rel='bookmark' title='The 5 Minute Guice Primer'>The 5 Minute Guice Primer</a></li>
<li><a href='http://www.richardnichols.net/2010/05/aop-annotation-based-caching-solution-for-guice-projects/' rel='bookmark' title='AOP, Annotation-based caching solution for Guice projects&#8230;'>AOP, Annotation-based caching solution for Guice projects&#8230;</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/4775162612_28515aba751.jpg"><img src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/4775162612_28515aba751-300x199.jpg" alt="" title="Google Juice - http://www.flickr.com/photos/johannes-p-osterhoff/4775162612/sizes/m/in/photostream/" width="300" height="199" class="alignright size-medium wp-image-833" /></a>18 months ago I introduced Guice 2.0 into my workplace development team.</p>
<p>So far it has been doing a good job of making inversion of control / dependency injection approachable, light-weight and helpful for the whole team.</p>
<p>The biggest issue we&#8217;ve had with Guice has been unexpected bugs relating to object scoping misunderstandings.</p>
<p>These are bugs that originate from a mistake on the part of the developer, either forgetting or misunderstanding the scope of objects being interacted with and subsequently accessing the objects outside of their intended scope, or accessing the objects in a scope that turns out to be more expensive than intended (e.g. an object intended to be a singleton, being accessed with no scope and re-instantiated over and over).</p>
<p>What we&#8217;ve found is that as a standard it is best to use Guice&#8217;s annotation based configuration mechanism to configure objects in their &#8220;intended configuration&#8221;, rather than using &#8220;Guice modules&#8221;.</p>
<p>Let me give an example of the two mechanisms -</p>
<p>With module &#8211; </p>
<pre class="prettyprint">
public interface MyService {
   void serviceOperation1();
   void serviceOperation2();
   void serviceOperation3();
}

public class MyServiceImpl implements MyService {
   @Inject
   public MyServiceImpl() {
   }
   public void serviceOperation1() {
      // ...
   }
   public void serviceOperation2() {
      // ...
   }
   public void serviceOperation3() {
      // ...
   }
}

public class MyServiceModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(MyService.class).to(MyServiceImpl.class).in(Scopes.SINGLETON);
    }
}
</pre>
<p>With annotations &#8211; </p>
<pre class="prettyprint">
@ImplementedBy(MyServiceImpl.class)
public interface MyService {
   void serviceOperation1();
   void serviceOperation2();
   void serviceOperation3();
}

@Singleton
public class MyServiceImpl implements MyService {
   @Inject
   public MyServiceImpl() {
   }
   public void serviceOperation1() {
      // ...
   }
   public void serviceOperation2() {
      // ...
   }
   public void serviceOperation3() {
      // ...
   }
}
</pre>
<p>These two examples are functionally identical, the only difference is how the Guice injector gets bootstrapped.</p>
<p>The common argument for Guice modules over annotations is that the application configuration is kept separate from the code, and can be changed in one central location. On the face of it, that seems like a pretty good argument.</p>
<p>In practice though, few objects can be arbitrarily rescoped without affecting the assumptions on which they were built, particularly where they have dependencies on other objects which have implicit scope. The only way to guarantee everything works as intended is to use Provider&lt;MyDependency&gt; everywhere to make sure things can continue working even if you monkey with the scoping in some unexpected way.</p>
<p>To me that seems like code-pollution which has rapidly diminishing returns.</p>
<p>The argument for @annotation based configuration is simple &#8211; understanding the intended scope and default implementation of an interface / object is an important signal to a developer reading the code for the first time. The best place for that information is in the code where the developer is reading it.</p>
<p>And best of all, this isn&#8217;t an either-or decision.</p>
<p>The annotation based configuration only specifies the default configuration of your Guice application. If you specify a different scoping or binding in a Guice module, it will override anything specified using annotations.</p>
<p>So with this approach you retain the flexibility (and explicit definition) provided by modules, but still solve the &#8220;developer usability&#8221; issue of in-your-face scoping/bindings.</p>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 451px; width: 1px; height: 1px; overflow: hidden;">common</div>
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F09%2Fguice-java-ioc-best-practices-annotation-configuration%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F09%2Fguice-java-ioc-best-practices-annotation-configuration%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=developer,Google,guice,Java,tips&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/09/session-replication-with-guice-java-web-applications/' rel='bookmark' title='Clustering Guice Java Web Applications'>Clustering Guice Java Web Applications</a></li>
<li><a href='http://www.richardnichols.net/2009/06/the-5-minute-guice-primer/' rel='bookmark' title='The 5 Minute Guice Primer'>The 5 Minute Guice Primer</a></li>
<li><a href='http://www.richardnichols.net/2010/05/aop-annotation-based-caching-solution-for-guice-projects/' rel='bookmark' title='AOP, Annotation-based caching solution for Guice projects&#8230;'>AOP, Annotation-based caching solution for Guice projects&#8230;</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=6tbCIYPwO7w:rU-igaR94Mk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=6tbCIYPwO7w:rU-igaR94Mk:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=6tbCIYPwO7w:rU-igaR94Mk:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=6tbCIYPwO7w:rU-igaR94Mk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=6tbCIYPwO7w:rU-igaR94Mk:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=6tbCIYPwO7w:rU-igaR94Mk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=6tbCIYPwO7w:rU-igaR94Mk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=6tbCIYPwO7w:rU-igaR94Mk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=6tbCIYPwO7w:rU-igaR94Mk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=6tbCIYPwO7w:rU-igaR94Mk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=6tbCIYPwO7w:rU-igaR94Mk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=6tbCIYPwO7w:rU-igaR94Mk:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/6tbCIYPwO7w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2010/09/guice-java-ioc-best-practices-annotation-configuration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2010/09/guice-java-ioc-best-practices-annotation-configuration/</feedburner:origLink></item>
		<item>
		<title>Java String “substring” – an example of lazy error messages…</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/E4Iy6MPlbcU/</link>
		<comments>http://www.richardnichols.net/2010/09/java-string-substring-an-example-of-lazy-error-messages/#comments</comments>
		<pubDate>Mon, 20 Sep 2010 00:38:46 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[soap-box]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=795</guid>
		<description><![CDATA[What does this error mean? Exception in thread &#8220;main&#8221; java.lang.StringIndexOutOfBoundsException: String index out of range: -1 That&#8217;s easy right? You&#8217;ve passed &#8220;-1&#8243; as an argument to a Java String&#8217;s &#8220;substring&#8221; method. Wrong. Here&#8217;s some code that gives the same error &#8230; <a href="http://www.richardnichols.net/2010/09/java-string-substring-an-example-of-lazy-error-messages/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/' rel='bookmark' title='Implementing Facebook OAuth 2.0 Authentication in Java'>Implementing Facebook OAuth 2.0 Authentication in Java</a></li>
<li><a href='http://www.richardnichols.net/2011/01/java-facial-recognition-haar-cascade-with-jjil-guide/' rel='bookmark' title='Face Detection in Java &#8211; Haar Cascade with JJIL (how-to)'>Face Detection in Java &#8211; Haar Cascade with JJIL (how-to)</a></li>
<li><a href='http://www.richardnichols.net/2010/06/301-redirects-made-easy-in-java/' rel='bookmark' title='301 Redirects Made Easy In Java'>301 Redirects Made Easy In Java</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>What does this error mean?</p>
<blockquote><p>Exception in thread &#8220;main&#8221; java.lang.StringIndexOutOfBoundsException: String index out of range: -1</p></blockquote>
<p>That&#8217;s easy right? You&#8217;ve passed &#8220;-1&#8243; as an argument to a Java String&#8217;s &#8220;substring&#8221; method.</p>
<p>Wrong.</p>
<p>Here&#8217;s some code that gives the same error -</p>
<pre>"fred smith".substring(4, 3);</pre>
<p>See the bug? The start index is after the end index (by 1 character).</p>
<p>To me, this is pretty poor API design. Neither of the arguments are out of bounds of the String&#8217;s length, so why raise a <em>StringIndexOutOfBoundsException</em>?</p>
<p>Worse, the index reported is neither of the indices passed.</p>
<p>And finally, the exact same error message is reported for another common mistake, e.g. </p>
<pre>"fred smith".substring(-1, 3)</pre>
<p>Here&#8217;s the offending code in Java&#8217;s core String.java &#8211; </p>
<pre class="prettyprint">
    public String substring(int beginIndex, int endIndex) {
	if (beginIndex < 0) {
	    throw new StringIndexOutOfBoundsException(beginIndex);
	}
	if (endIndex > count) {
	    throw new StringIndexOutOfBoundsException(endIndex);
	}
	if (beginIndex > endIndex) {
	    throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
	}
	return ((beginIndex == 0) &#038;&#038; (endIndex == count)) ? this :
	    new String(offset + beginIndex, endIndex - beginIndex, value);
    }
</pre>
<p>For what it&#8217;s worth, this should probably be an IllegalArgumentException, since the argument&#8217;s have nothing to do with being out of bounds of the string and are just illegal with respect to one another. This would also allow for a meaningful error message such as &#8220;Start index (4) is before end index (3)&#8221;.</p>
<p>It&#8217;s funny the stuff you find when fixing gnarly bugs <img src='http://d3araz99qvcc8b.cloudfront.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F09%2Fjava-string-substring-an-example-of-lazy-error-messages%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F09%2Fjava-string-substring-an-example-of-lazy-error-messages%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=Java,soap-box&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/' rel='bookmark' title='Implementing Facebook OAuth 2.0 Authentication in Java'>Implementing Facebook OAuth 2.0 Authentication in Java</a></li>
<li><a href='http://www.richardnichols.net/2011/01/java-facial-recognition-haar-cascade-with-jjil-guide/' rel='bookmark' title='Face Detection in Java &#8211; Haar Cascade with JJIL (how-to)'>Face Detection in Java &#8211; Haar Cascade with JJIL (how-to)</a></li>
<li><a href='http://www.richardnichols.net/2010/06/301-redirects-made-easy-in-java/' rel='bookmark' title='301 Redirects Made Easy In Java'>301 Redirects Made Easy In Java</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=E4Iy6MPlbcU:Ku6pLt6P48I:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=E4Iy6MPlbcU:Ku6pLt6P48I:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=E4Iy6MPlbcU:Ku6pLt6P48I:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=E4Iy6MPlbcU:Ku6pLt6P48I:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=E4Iy6MPlbcU:Ku6pLt6P48I:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=E4Iy6MPlbcU:Ku6pLt6P48I:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=E4Iy6MPlbcU:Ku6pLt6P48I:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=E4Iy6MPlbcU:Ku6pLt6P48I:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=E4Iy6MPlbcU:Ku6pLt6P48I:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=E4Iy6MPlbcU:Ku6pLt6P48I:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=E4Iy6MPlbcU:Ku6pLt6P48I:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=E4Iy6MPlbcU:Ku6pLt6P48I:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/E4Iy6MPlbcU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2010/09/java-string-substring-an-example-of-lazy-error-messages/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2010/09/java-string-substring-an-example-of-lazy-error-messages/</feedburner:origLink></item>
		<item>
		<title>Converting Ebook Formats – .mobi to .epub</title>
		<link>http://feedproxy.google.com/~r/PragmaticCoder/~3/mn80pWH0uMo/</link>
		<comments>http://www.richardnichols.net/2010/09/converting-ebook-formats-mobi-to-epub/#comments</comments>
		<pubDate>Mon, 13 Sep 2010 16:30:57 +0000</pubDate>
		<dc:creator>Richard Nichols</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[apple]]></category>
		<category><![CDATA[ebook]]></category>
		<category><![CDATA[off-topic]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://www.richardnichols.net/?p=779</guid>
		<description><![CDATA[As I recently blogged, I picked up an iPad, and have been using it (mainly) as an ebook reader. I prefer using the Kindle app on the iPad to read ebooks, and the Amazon Kindle book store seems to have &#8230; <a href="http://www.richardnichols.net/2010/09/converting-ebook-formats-mobi-to-epub/">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/09/thoughts-on-the-ipad/' rel='bookmark' title='Thoughts on the iPad&#8230;'>Thoughts on the iPad&#8230;</a></li>
<li><a href='http://www.richardnichols.net/2010/01/ebooks-drm-fail/' rel='bookmark' title='eBooks + DRM = Fail'>eBooks + DRM = Fail</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>As I <a href="http://www.richardnichols.net/2010/09/thoughts-on-the-ipad/">recently blogged</a>, I picked up an iPad, and have been using it (mainly) as an ebook reader.</p>
<p>I prefer using the Kindle app on the iPad to read ebooks, and the Amazon Kindle book store seems to have the best price/range as well.</p>
<p>But I recently had a situation where I had bought a digital copy of <a href="http://www.amazon.com/gp/product/0981531601?ie=UTF8&amp;tag=pracodthebloo-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0981531601">Programming in Scala: A Comprehensive Step-by-step Guide</a> which only comes in PDF and<em> &#8220;.mobi&#8221;</em> versions. .mobi is the format used by the Kindle, so I thought &#8220;woo hoo&#8221; this should be easy, right?</p>
<p>Wrong.</p>
<p>It&#8217;s not possible to get <em>.mobi</em> books into the Kindle app that weren&#8217;t purchased from Amazon right now. I did some googling and found a number of forum posts recommending iPad/iPhone file system tools to drop the ebook into the Kindle folder. Unfortunately on Windows I wasn&#8217;t able to get these to show the Kindle app&#8217;s folder.</p>
<p>So I tried looking for another solution, and although the iBooks app isn&#8217;t as good as the Kindle app for reading, I figured converting the <em>.mobi</em> book to an <em>.epub</em> book for iBooks would be an easier task.</p>
<p>As it turns out, it was! Here&#8217;s how to do it -</p>
<blockquote><p>The same process can also be used to convert books from/to other ebook formats.</p></blockquote>
<ol>
<li>The key tool here is &#8220;Calibre&#8221; &#8211; an open source ebook management tool. Download a copy from <a href="http://calibre-ebook.com/">http://calibre-ebook.com/</a>
</li>
<li>Install it, I&#8217;ll assume that you&#8217;re installing on Windows and with the default settings.
</li>
<li>Start the program when installation is complete. When you&#8217;re prompted as below, choose &#8220;Apple&#8221; as your default reader.
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/calibre-welcome-wizard_2010-09-11_17-51-32.png"><img class="aligncenter size-full wp-image-780" title="calibre welcome wizard - choose the reader" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/calibre-welcome-wizard_2010-09-11_17-51-32.png" alt="" width="589" height="514" /></a>
</li>
<li>Once it&#8217;s loaded, use the &#8220;Add button to add the .mobi (or other format) book to Calibre.
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/calibre-Calibre-Library_2010-09-11_17-53-06.png"><img class="aligncenter size-full wp-image-781" title="calibre - add ebook button" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/calibre-Calibre-Library_2010-09-11_17-53-06.png" alt="" width="213" height="192" /></a></p>
<p>It should then show up in the list of books.
</li>
<li>Click the &#8220;Convert&#8221; button.
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/calibre-Calibre-Library_2010-09-11_17-59-52.png"><img class="aligncenter size-full wp-image-782" title="calibre - convert ebook button" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/calibre-Calibre-Library_2010-09-11_17-59-52.png" alt="" width="267" height="248" /></a></p>
<p>When the conversion options dialog appears, use the default settings and click OK.
</li>
<li>You should see a &#8220;Job&#8221; appear in the Jobs monitor in the bottom right hand corner of the screen. Wait for the book to be converted and the Job count to return to zero.
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/Programming-in-Scala-1092-2_2010-09-11_18-03-29.png"><img class="aligncenter size-full wp-image-784" title="Calibre - job monitor" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/Programming-in-Scala-1092-2_2010-09-11_18-03-29.png" alt="" width="289" height="145" /></a>
</li>
<li>Right click the book and choose the &#8220;Save to disk -&gt; Save only EPUB format to disk&#8221; option and choose where to save the resulting ebook.
<p><a href="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/calibre-Calibre-Library_2010-09-11_17-55-03.png"><img class="aligncenter size-medium wp-image-783" title="calibre - save to disk .epub" src="http://d3araz99qvcc8b.cloudfront.net/wp-content/uploads/2010/09/calibre-Calibre-Library_2010-09-11_17-55-03-300x122.png" alt="" width="300" height="122" /></a>
</li>
<li>The &#8220;.epub&#8221; book can now be dragged from the file system to iTunes and synced on the iPad.</li>
</ol>
<p><a href="http://calibre-ebook.com/">Calibre</a> seems to be another great open source tool that I&#8217;ve never heard of. It&#8217;s a shame the ebook distributors such as Apple and Amazon can&#8217;t  settle on a single format, and/or provide better interoperability between their formats/devices, but I guess vendor lock-in is still the modus operandi for the time being.</p>
<p>Anyhow, open-source ftw!
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F09%2Fconverting-ebook-formats-mobi-to-epub%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.richardnichols.net%2F2010%2F09%2Fconverting-ebook-formats-mobi-to-epub%2F&amp;source=rn_tweets&amp;style=normal&amp;hashtags=apple,ebook,off-topic,tips&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Related posts:<ol>
<li><a href='http://www.richardnichols.net/2010/09/thoughts-on-the-ipad/' rel='bookmark' title='Thoughts on the iPad&#8230;'>Thoughts on the iPad&#8230;</a></li>
<li><a href='http://www.richardnichols.net/2010/01/ebooks-drm-fail/' rel='bookmark' title='eBooks + DRM = Fail'>eBooks + DRM = Fail</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=mn80pWH0uMo:cs1LsYySodQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=mn80pWH0uMo:cs1LsYySodQ:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=mn80pWH0uMo:cs1LsYySodQ:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=mn80pWH0uMo:cs1LsYySodQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=mn80pWH0uMo:cs1LsYySodQ:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=mn80pWH0uMo:cs1LsYySodQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=mn80pWH0uMo:cs1LsYySodQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=mn80pWH0uMo:cs1LsYySodQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=mn80pWH0uMo:cs1LsYySodQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=mn80pWH0uMo:cs1LsYySodQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PragmaticCoder?a=mn80pWH0uMo:cs1LsYySodQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/PragmaticCoder?i=mn80pWH0uMo:cs1LsYySodQ:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/PragmaticCoder/~4/mn80pWH0uMo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.richardnichols.net/2010/09/converting-ebook-formats-mobi-to-epub/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		<feedburner:origLink>http://www.richardnichols.net/2010/09/converting-ebook-formats-mobi-to-epub/</feedburner:origLink></item>
	</channel>
</rss><!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Content Delivery Network via Amazon Web Services: CloudFront: d3araz99qvcc8b.cloudfront.net

Served from: www.richardnichols.net @ 2012-04-27 09:04:07 -->

