<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D0EEQng7eip7ImA9WhVRGU4.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856</id><updated>2012-03-28T13:53:23.602+02:00</updated><title>Axel Fontaine</title><subtitle type="html">Software Development Expert</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.axelfontaine.com/" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/axelfontaine" /><feedburner:info uri="axelfontaine" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>axelfontaine</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry gd:etag="W/&quot;AkEBSXsyeCp7ImA9WhZVF0s.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-8422992459963219563</id><published>2011-05-30T17:17:00.000+02:00</published><updated>2011-05-30T17:17:38.590+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-30T17:17:38.590+02:00</app:edited><title>One Minute Book Review: Getting To Yes</title><content type="html">Today I take a look at a big classic from the field of negotiation: Roger Fisher's and William Ury's&lt;br /&gt;
&lt;a href="http://www.amazon.de/gp/product/1844131467/ref=as_li_tf_tl?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=1844131467"&gt;&lt;b&gt;Getting to Yes: Negotiating an agreement without giving in&lt;/b&gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=1844131467" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;p align="center"&gt;&lt;a href="http://www.amazon.de/gp/product/1844131467/ref=as_li_tf_il?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=1844131467"&gt;&lt;img border="0" src="http://files.axelfontaine.com/amazon/51iFEMT6sqL._SL160_.jpg" /&gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=1844131467" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;b&gt;Negotiation&lt;/b&gt; is really only about one thing: &lt;b&gt;getting what you want&lt;/b&gt;. The prize can be anything from the choice of dinner for this evening, to the amount of your next raise or the details of a new strategic partnership. Private or professional life, it doesn't matter. We negotiate &lt;b&gt;all the time&lt;/b&gt; and the outcome of our negotiations &lt;b&gt;greatly influences&lt;/b&gt; our lives.&lt;br /&gt;
&lt;br /&gt;
And yet, this is a skill most of us in software engineering &lt;b&gt;didn't receive any formal training&lt;/b&gt; in. Professionally the matter is even worse. Most of our "opponents", ranging from managers to sales people, have both more practice and better training. This leaves us fighting an uphill battle!&lt;br /&gt;
&lt;br /&gt;
We must stand up and level the playing field!&lt;br /&gt;
&lt;br /&gt;
I found Roger Fisher and William Ury to be powerful allies for this quest.&lt;br /&gt;
&lt;br /&gt;
Getting To Yes makes the case for &lt;b&gt;principled negotiation&lt;/b&gt;. The main focus is reaching a &lt;b&gt;mutually satisfying agreement&lt;/b&gt;. This implies meeting the needs of both parties, and resisting the urge of trying to "win" against your opponent.&lt;br /&gt;
&lt;br /&gt;
The reason they designed this method, is because most people get &lt;b&gt;stuck bargaining over positions&lt;/b&gt;, effectively creating a win-lose situation.&lt;br /&gt;
&lt;br /&gt;
The alternative is to take a step back and understand what your opponent really wants. Once his &lt;b&gt;interests&lt;/b&gt; have been &lt;b&gt;uncovered&lt;/b&gt;, you can then look whether the pie can be divided or whether &lt;b&gt;new options&lt;/b&gt; should be &lt;b&gt;invented for mutual gain&lt;/b&gt;. A good way to achieve this is by looking if the pie can not be expanded instead. Adding new elements to the negotiation opens up new scenarios and increases the chances of reaching an agreement.&lt;br /&gt;
&lt;br /&gt;
If the negotiation gets difficult, make sure you &lt;b&gt;focus on the problem and not on the people&lt;/b&gt;. You should always insist on &lt;b&gt;objective criterias&lt;/b&gt;. And if all that doesn't work, you should have another plan ready: your BATNA (&lt;b&gt;Best Alternative To Negotiated Agreement&lt;/b&gt;).&lt;br /&gt;
&lt;br /&gt;
I found this book to be immensely useful. And I am not alone thinking this: they have sold millions of copies!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Highly recommended.&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-8422992459963219563?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/kK_M5VYBAsY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/8422992459963219563/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2011/05/one-minute-book-review-getting-to-yes.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/8422992459963219563?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/8422992459963219563?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/kK_M5VYBAsY/one-minute-book-review-getting-to-yes.html" title="One Minute Book Review: Getting To Yes" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.axelfontaine.com/2011/05/one-minute-book-review-getting-to-yes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMCQXc9eip7ImA9WhZVFEU.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-6530904291391085330</id><published>2011-05-27T10:54:00.000+02:00</published><updated>2011-05-27T10:54:20.962+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-27T10:54:20.962+02:00</app:edited><title>Continuous Delivery Talk on Parleys</title><content type="html">Earlier this month I was at the &lt;a href="http://www.bejug.org/confluenceBeJUG/display/BeJUG/Continuous+Delivery"&gt;BeJUG&lt;/a&gt; in Leuven to present my &lt;b&gt;Continuous Delivery&lt;/b&gt; talk.&lt;br /&gt;
&lt;br /&gt;
It was great fun and I really enjoyed meeting lots of interesting people. But what is extra nice about the BeJUG, is that it is organized by &lt;a href="https://twitter.com/#!/Stephan007"&gt;Stephan Janssen&lt;/a&gt; of &lt;a href="http://www.devoxx.com"&gt;Devoxx&lt;/a&gt; and &lt;a href="http://parleys.com"&gt;Parleys&lt;/a&gt; fame. And so, with the precious help of &lt;a href="https://twitter.com/#!/danieldeluca"&gt;Daniel De Luca&lt;/a&gt; they made the talk &lt;a href="http://parleys.com/#id=2443&amp;sl=0&amp;st=5"&gt;available online at Parleys.com&lt;/a&gt; as well!&lt;br /&gt;
&lt;br /&gt;
Here are some pictures of the event (more on the &lt;a href="http://www.bejug.org/confluenceBeJUG/display/BeJUG/Continuous+Delivery"&gt;BeJUG&lt;/a&gt; page):&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" height="132" width="200" src="http://2.bp.blogspot.com/-CAMBhaHKjRU/Td9jiHRUoCI/AAAAAAAAADg/wL0slc6Q7tU/s200/DSC_1369.jpg" style="padding: 5px;" /&gt; &lt;img border="0" height="132" width="200" src="http://4.bp.blogspot.com/-SpuPOc41UuQ/Td9jqypLLII/AAAAAAAAADo/GrKDHjE0Ahk/s200/DSC_1397.jpg" style="padding: 5px;" /&gt; &lt;img border="0" height="132" width="200" src="http://2.bp.blogspot.com/-NT396-V45RQ/Td9jzvDaaNI/AAAAAAAAADw/WACgATFoRxk/s200/DSC_1401.jpg" style="padding: 5px;" /&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
And here is the presentation on &lt;a href="http://parleys.com/#sl=0&amp;st=5&amp;id=2443"&gt;Parleys&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object width="660" height="590"&gt;
  &lt;param name="movie" value="http://www.parleys.com/share/parleysshare2.swf?pageId=2443"/&gt;  &lt;param name="allowFullScreen" value="true"/&gt;  &lt;param name="pageId" value="2443"/&gt;  &lt;embed src="http://www.parleys.com/share/parleysshare2.swf?pageId=2443" type="application/x-shockwave-flash" allowfullscreen="true" width="660" height="590"/&gt;
&lt;/object&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
Thank you very much to all the ones that came. It was an absolute pleasure for me. And for all the ones who didn't have the chance to come, enjoy watching it online!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-6530904291391085330?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/IyfSwrCX7Xw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/6530904291391085330/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2011/05/continuous-delivery-talk-on-parleys.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/6530904291391085330?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/6530904291391085330?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/IyfSwrCX7Xw/continuous-delivery-talk-on-parleys.html" title="Continuous Delivery Talk on Parleys" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-CAMBhaHKjRU/Td9jiHRUoCI/AAAAAAAAADg/wL0slc6Q7tU/s72-c/DSC_1369.jpg" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://www.axelfontaine.com/2011/05/continuous-delivery-talk-on-parleys.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8NQ3wyfip7ImA9WhZVFko.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-4341444368362866864</id><published>2011-05-26T12:03:00.001+02:00</published><updated>2011-05-29T14:41:32.296+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-29T14:41:32.296+02:00</app:edited><title>Environment Detection</title><content type="html">One of the key aspects of my &lt;a href="http://www.axelfontaine.com/2011/04/continuous-delivery-talk-at-rheinjug-in.html"&gt;&lt;b&gt;Continuous&lt;/b&gt;&lt;/a&gt; &lt;a href="http://parleys.com/#st=5&amp;id=2443"&gt;&lt;b&gt;Delivery&lt;/b&gt;&lt;/a&gt; talks is applications being aware of where they are.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Environment Detection&lt;/b&gt; stands for the ability to sense in which environment an application is currently deployed using the simplest means at its disposal.&lt;br /&gt;
&lt;br /&gt;
Once this information is available you can act on it in a number of meaningful ways, such as loading the appropriate configuration or enabling/disabling features for the current environment.&lt;br /&gt;
&lt;br /&gt;
This is powerful and simpler than it sounds. I'll show you a number of ways to implement the detection and then, we'll look at how to integrate it in an application. But always remember: use the simplest technique that works for you.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The most common detection strategies are:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;IP Address/Range&lt;/li&gt;
&lt;li&gt;HostName&lt;/li&gt;
&lt;li&gt;File contents&lt;/li&gt;
&lt;li&gt;Operating System&lt;/li&gt;
&lt;li&gt;System Property&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Let's have a look at how to implement them in Java.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;IP Address/Range&lt;/h4&gt;&lt;pre class="brush: java"&gt;// Assuming 1.2.3.4 is the IP Address of your DEV machine
// and 5.6.7.x is the IP Range of your PROD environment
String ipAddress = InetAddress.getLocalHost().getHostAddress();
if ("1.2.3.4".equals(ipAddress)) {
    // DEV
} else if (ipAddress.startsWith("5.6.7.")) {
    // PROD
}&lt;/pre&gt;&lt;br /&gt;
&lt;h4&gt;HostName&lt;/h4&gt;&lt;pre class="brush: java"&gt;// Assuming abc and def are the hostNames of your DEV and PROD servers
String hostName = InetAddress.getLocalHost().getHostName();
if ("abc".equals(hostName)) {
    // DEV
} else if ("def".equals(hostName)) {
    // PROD
}
&lt;/pre&gt;&lt;br /&gt;
&lt;h4&gt;File contents&lt;/h4&gt;&lt;pre class="brush: java"&gt;import org.springframework.util.FileCopyUtils;

// Assuming /etc/my.env exists
// and contains the name of the environment such as DEV, TEST, PROD, ...
String environment = FileCopyUtils.copyToString(new FileReader("/etc/my.env"));
&lt;/pre&gt;&lt;br /&gt;
&lt;h4&gt;Operating System&lt;/h4&gt;&lt;pre class="brush: java"&gt;// Assuming DEV is on Windows and PROD on Linux
String operatingSystem = System.getProperty("os.name");
if (operatingSystem.startsWith("Windows")) {
    // DEV
} else {
    // PROD
}
&lt;/pre&gt;&lt;br /&gt;
&lt;h4&gt;System Property&lt;/h4&gt;&lt;pre class="brush: java"&gt;// Assuming my.env is set
// and contains the name of the environment such as DEV, TEST, PROD, ...
String environment = System.getProperty("my.env");
&lt;/pre&gt;&lt;br /&gt;
And that's all there is to it !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Here is a &lt;b&gt;quick example&lt;/b&gt; of how to leverage this newly acquired piece of information:&lt;br /&gt;
&lt;br /&gt;
Say we use a framework like Spring and want to easily load the &lt;b&gt;appropriate configuration for the current environment&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
We use an EnvironmentDetectionService to detect the environment and store the result in a System Property called my.env. The configuration for each environment is stored in a separate folder.&lt;br /&gt;
&lt;br /&gt;
We can now load the appropriate configuration like this:&lt;br /&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;bean id="environmentDetectionService" class="my.pkg.EnvironmentDetectionService"
    init-method="detectEnvironment"/&amp;gt;

&amp;lt;bean
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
    depends-on="environmentDetectionService"&amp;gt;
    &amp;lt;property name="location" value="/config/${my.env}/my.properties"/&amp;gt;
&amp;lt;/bean&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Environment Detection&lt;/b&gt; is a simple, yet very powerful capability. Start using it today and you'll never look back!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-4341444368362866864?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/MKVglIRaWwo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/4341444368362866864/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2011/05/environment-detection.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/4341444368362866864?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/4341444368362866864?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/MKVglIRaWwo/environment-detection.html" title="Environment Detection" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.axelfontaine.com/2011/05/environment-detection.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcESHg4fSp7ImA9WhZREE8.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-7454241352372998788</id><published>2011-04-05T19:03:00.000+02:00</published><updated>2011-04-05T19:03:29.635+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-05T19:03:29.635+02:00</app:edited><title>Continuous Delivery Talk at the Rheinjug (in German)</title><content type="html">On Thursday I had the pleasure to go and present my &lt;b&gt;Continuous Delivery&lt;/b&gt; talk (in German) at the &lt;a href="http://rheinjug.de/"&gt;&lt;b&gt;rheinjug&lt;/b&gt;&lt;/a&gt; in Düsseldorf.&lt;br /&gt;
&lt;br /&gt;
I really enjoyed my visit. The organisation was great, and it drew a large and interesting crowd. We had a great Q&amp;amp;A session, and the conversation continued for a few more hours around some fine beers at the social event.&lt;br /&gt;
&lt;br /&gt;
I've made the slides of the talk available on &lt;a href="http://www.slideshare.net/axelfontaine/continuous-delivery-7524266"&gt;slideshare&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;div id="__ss_7524266" style="text-align: center; width: 100%;"&gt;&lt;object height="520" id="__sse7524266" width="640"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=continuousdeliveryrheinjug-110405111733-phpapp02&amp;stripped_title=continuous-delivery-7524266&amp;userName=axelfontaine" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse7524266" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=continuousdeliveryrheinjug-110405111733-phpapp02&amp;stripped_title=continuous-delivery-7524266&amp;userName=axelfontaine" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="520"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;
The video is now &lt;a href="http://rheinjug.de/videos/gse.lectures.app/Talk.html#ContinuousDelivery"&gt;online&lt;/a&gt; as well:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://rheinjug.de/videos/gse.lectures.app/Talk.html#ContinuousDelivery"&gt;&lt;img border="0" height="422" src="http://3.bp.blogspot.com/-u5TxvqQJWjs/TZtHr9xaJXI/AAAAAAAAADY/hMR26AMGdNM/s640/video.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Thanks to everyone who came. I hope you enjoyed it. I sure did :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-7454241352372998788?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/wSFBa7o2__U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/7454241352372998788/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2011/04/continuous-delivery-talk-at-rheinjug-in.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/7454241352372998788?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/7454241352372998788?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/wSFBa7o2__U/continuous-delivery-talk-at-rheinjug-in.html" title="Continuous Delivery Talk at the Rheinjug (in German)" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-u5TxvqQJWjs/TZtHr9xaJXI/AAAAAAAAADY/hMR26AMGdNM/s72-c/video.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.axelfontaine.com/2011/04/continuous-delivery-talk-at-rheinjug-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cDQH44fCp7ImA9Wx9bEk0.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-5036598580090898418</id><published>2011-02-20T14:30:00.001+01:00</published><updated>2011-02-20T14:37:51.034+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-20T14:37:51.034+01:00</app:edited><title>One Minute Book Review: Inbound Marketing</title><content type="html">Over the Christmas holiday, I finally got around to something I had planned for a while: reading Brian Halligan's and Dharmesh Shah's very popular&lt;br /&gt;
&lt;b&gt;&lt;a href="http://www.amazon.de/gp/product/0470499311?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=0470499311"&gt;Inbound Marketing&lt;/a&gt;&lt;img src="http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=0470499311" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;: Get Found using Google, Social Media, and Blogs&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p align="center"&gt;&lt;a href="http://www.amazon.de/gp/product/0470499311?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=0470499311"&gt;&lt;img border="0" src="http://files.axelfontaine.com/amazon/51WgPVrnY-L._SL160_.jpg"&gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=0470499311" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/p&gt;&lt;br /&gt;
&lt;b&gt;The business world is changing. And it's changing fast.&lt;/b&gt; One of the most interesting statistics supporting this does not appear until the last chapter of the book. Here it is:&lt;br /&gt;
&lt;br /&gt;
Between 1955 and 1995, on average, every year there were 20 companies leaving the Fortune 500 and 20 new ones joining. Since 1995 this number doubled to 40. &lt;b&gt;Of the 500 companies in the Fortune 500 in 1995, only 250 remained in 2009!&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
So why did companies like Amazon, eBay and Google replace other ones likes Toys 'R' Us and Polaroid? The answer to this question is very much related to why Obama defeated McCain in the 2008 US presidential elections.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;So what did the Obama campaign have in common with Amazon, eBay and Google?&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
They realized that throwing the most money at traditional media (television, print) to repeat the same message to as many people as possible as often as possible may not be the most effective anymore.&lt;br /&gt;
&lt;br /&gt;
The point Brian and Dharmesh make is that this &lt;b&gt;50 year era of outbound marketing is coming to a close&lt;/b&gt;. People are getting increasingly better at blocking out these messages.&lt;br /&gt;
&lt;br /&gt;
We are now at the dawn of a new era in the field of marketing: &lt;b&gt;inbound marketing&lt;/b&gt;. Instead of focusing on bombarding as many people as possible with a message they don't want to hear, there are new rules that must be mastered on the road to success. &lt;b&gt;Producing remarkable content&lt;/b&gt; that people want to read about is the way forward. &lt;b&gt;Turning customers into fans&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
And it turns out, we live in an age where it has never been easier. And yet it has never been harder. Google, Facebook, Blogs and Twitter enable anyone to produce great content and get found. &lt;b&gt;Quality trumps dollars&lt;/b&gt;. And yet, all of a sudden the &lt;b&gt;competition became global&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;How can you and your company stand out and become better at this game?&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
This book is filled with practical advice on how to get there. Putting Google, Twitter, Facebook , LinkedIn and your blog to use, to achieve a loyal following who will help you spreading the word. And the work they will spread is one about how it is worth their time to be involved with the remarkable things you do!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Highly recommended.&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-5036598580090898418?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/0AYoUD2mJuk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/5036598580090898418/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2011/02/one-minute-book-review-inbound.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/5036598580090898418?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/5036598580090898418?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/0AYoUD2mJuk/one-minute-book-review-inbound.html" title="One Minute Book Review: Inbound Marketing" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.axelfontaine.com/2011/02/one-minute-book-review-inbound.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMEQ3YzcCp7ImA9Wx9UFko.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-5978072456994878967</id><published>2011-02-10T00:28:00.005+01:00</published><updated>2011-02-14T10:06:42.888+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-14T10:06:42.888+01:00</app:edited><title>Maven Releases on Steroids (3): Rounding it up with Jenkins</title><content type="html">In &lt;a href="http://www.axelfontaine.com/2011/01/maven-releases-on-steroids-2-preparing.html"&gt;&lt;b&gt;Part 2&lt;/b&gt;&lt;/a&gt;, we looked at what changes where necessary to the Maven POMs to make it all work.&lt;br /&gt;
&lt;br /&gt;
In this final part, we'll put the finishing touch by choosing a &lt;b&gt;version number&lt;/b&gt; strategy and  &lt;b&gt;integrating&lt;/b&gt; what we have so far &lt;b&gt;with Jenkins&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Version Number&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
A good version number has a number of properties:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;Natural order:&lt;/b&gt; it should be possible to determine at a glance between two versions which one is newer&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Maven support:&lt;/b&gt; Maven should be able to deal with the format of the version number to enfore the natural order&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Machine incrementable:&lt;/b&gt; so you don't have to specify it explicitely every time&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Typical candidates can be:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;build number&lt;/li&gt;
&lt;li&gt;timestamp (in a suitable format such as yyyy.MM.dd.HH.mm)&lt;/li&gt;
&lt;li&gt;revision number (SVN only)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
We must now find one we can use. Luckily for us, it turns out Jenkins has a very useful feature for this. During each build Jenkins exposes &lt;a href="http://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project"&gt;a number of environments variables&lt;/a&gt;. A few of these are particularly interesting:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&lt;table border="1"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th style="padding: 10px;"&gt;Environment Variable&lt;/th&gt; &lt;th&gt;Description&lt;/th&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style="padding: 10px;"&gt;BUILD_NUMBER&lt;/td&gt; &lt;td style="padding: 10px;"&gt;The current build number, such as "153"&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style="padding: 10px;"&gt;BUILD_ID&lt;/td&gt; &lt;td style="padding: 10px;"&gt;The current build id, such as "2005-08-22_23-59-59" (YYYY-MM-DD_hh-mm-ss)&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style="padding: 10px;"&gt;SVN_REVISION&lt;/td&gt; &lt;td style="padding: 10px;"&gt;For Subversion-based projects, this variable contains the revision number of the module. If you have more than one module specified, this won't be set.&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/blockquote&gt;&lt;br /&gt;
In this article, we''ll use the &lt;b&gt;BUILD_NUMBER&lt;/b&gt; variable as a version number for our releases. We could have used one of the others as well, but this one fits our need perfectly: a fine machine-incremented number with a natural order supported by Maven.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Jenkins&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The first thing to do is to set up a new Maven 2/3 project.&lt;br /&gt;
&lt;br /&gt;
In this project you must&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;configure the &lt;b&gt;SCM URL&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;set the &lt;b&gt;Maven Goals and options&lt;/b&gt; to&lt;br /&gt;
clean deploy scm:tag -DVERSION_NUMBER=&lt;b&gt;${BUILD_NUMBER}&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_MrqrMUHR5FA/TVMUZnO7uZI/AAAAAAAAAC4/-QOyba8cjS0/s1600/JenkinsConfig.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TVMUZnO7uZI/AAAAAAAAAC4/-QOyba8cjS0/s640/JenkinsConfig.png" width="568" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
And that's it! Every time this job is run, a new release is produced, the artifacts will be deployed and the source code will be tagged. The version of the release will be the BUILD_NUMBER of the Jenkins project. Nice and simple.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;A small note for Nexus users:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
In order to allow Maven to &lt;b&gt;upload the corrected POMs&lt;/b&gt; from Part 2 of this article, you need to set the &lt;b&gt;Deployment Policy&lt;/b&gt; of the &lt;i&gt;Releases&lt;/i&gt; repository to &lt;b&gt;Allow Redeploy&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_MrqrMUHR5FA/TVMXzCRXt2I/AAAAAAAAADA/0IBuOJvvFkg/s1600/NexusConfig.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://1.bp.blogspot.com/_MrqrMUHR5FA/TVMXzCRXt2I/AAAAAAAAADA/0IBuOJvvFkg/s640/NexusConfig.png" width="596" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Next step&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
You're now ready to add a build trigger on SCM changes in Jenkins. Once you have this, &lt;b&gt;every&lt;/b&gt; commit causing a &lt;b&gt;green build&lt;/b&gt; will produce a &lt;b&gt;new release&lt;/b&gt;. It's the next step up.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Download&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Last, but not least, here is a sample &lt;b&gt;multi-module Maven Project&lt;/b&gt; with all the POMs correctly set up available for &lt;a href="http://files.axelfontaine.com/releasesonsteroids.zip"&gt;&lt;b&gt;download&lt;/b&gt;&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Looking back at the workflow of the Release Plugin we discussed in &lt;a href="http://www.axelfontaine.com/2011/01/maven-releases-on-steroids-adios.html"&gt;&lt;b&gt;Part 1&lt;/b&gt;&lt;/a&gt;, we have come a long way!&lt;br /&gt;
&lt;br /&gt;
If you're willing to live with 3 simple things:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;you do NOT depend on SNAPSHOTs, ever.&lt;/li&gt;
&lt;li&gt;the POM does not contain the version number&lt;/li&gt;
&lt;li&gt;you ALWAYS build releases from a CI server, and NEVER locally on a developer's machine&lt;/li&gt; 
&lt;/ul&gt;&lt;br /&gt;
you can now enjoy &lt;b&gt;very fast (3x) and robust releases&lt;/b&gt;, without the headaches of the Release Plugin.&lt;br /&gt;
&lt;br /&gt;
For reference:&lt;br /&gt;
&lt;blockquote&gt;&lt;table border="1"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th style="padding: 10px;"&gt;Releases on Steroids&lt;/th&gt; &lt;th style="padding: 10px;"&gt;Release Plugin&lt;/th&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style="padding: 10px;"&gt;clean/compile/test cycle&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;b&gt;1 &lt;/b&gt;&lt;/td&gt; &lt;td style="padding: 10px;"&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&lt;b&gt;3&lt;/b&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style="padding: 10px;"&gt;POM transformations&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;b&gt;0 &lt;/b&gt;&lt;/td&gt; &lt;td style="padding: 10px;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;2&lt;/span&gt;&lt;/b&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style="padding: 10px;"&gt;commits&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;b&gt;0 &lt;/b&gt;&lt;/td&gt; &lt;td style="padding: 10px;"&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&lt;b&gt;2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td style="padding: 10px;"&gt;SCM revisons&lt;/td&gt;&lt;td style="padding: 10px;"&gt;&lt;b&gt;1 &lt;/b&gt;&lt;/td&gt; &lt;td style="padding: 10px;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;3&lt;/span&gt;&lt;/b&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Enjoy !&lt;/b&gt; (You'll never look back :-) )&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-5978072456994878967?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/bc7S1KUEkz8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/5978072456994878967/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2011/02/maven-releases-on-steroids-3-rounding.html#comment-form" title="17 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/5978072456994878967?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/5978072456994878967?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/bc7S1KUEkz8/maven-releases-on-steroids-3-rounding.html" title="Maven Releases on Steroids (3): Rounding it up with Jenkins" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_MrqrMUHR5FA/TVMUZnO7uZI/AAAAAAAAAC4/-QOyba8cjS0/s72-c/JenkinsConfig.png" height="72" width="72" /><thr:total>17</thr:total><feedburner:origLink>http://www.axelfontaine.com/2011/02/maven-releases-on-steroids-3-rounding.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8CRHgzfSp7ImA9Wx9UE0o.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-4993257412484732357</id><published>2011-01-29T16:54:00.004+01:00</published><updated>2011-02-10T22:37:45.685+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-10T22:37:45.685+01:00</app:edited><title>Maven Releases on Steroids (2): Preparing the POMs</title><content type="html">In &lt;a href="http://www.axelfontaine.com/2011/01/maven-releases-on-steroids-adios.html"&gt;&lt;b&gt;Part 1&lt;/b&gt;&lt;/a&gt;, I wrote about the problems with the Maven Release Plugin and what could be a better way to perform releases with Maven.&lt;br /&gt;
&lt;br /&gt;
In this part, we will make the necessary adjustments to the POMs to make it all work.&lt;br /&gt;
&lt;br /&gt;
Our goal is to have a &lt;b&gt;single command&lt;/b&gt; to:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Build and Test the SCM revision currently checked out&lt;/li&gt;
&lt;li&gt;Deploy the binary artifacts to the Artifact Repository&lt;/li&gt;
&lt;li&gt;Tag the SCM revision with the version number of the artifacts&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
As we only want one commit instead of 3 per release, the &lt;b&gt;version number can not be contained inside the POM&lt;/b&gt; anymore, as this would make it impossible to update it without updating the POM itself.&lt;br /&gt;
We have to balance this against the need for a &lt;b&gt;default version number&lt;/b&gt; when performing local, &lt;b&gt;non-release builds&lt;/b&gt;, as we don't want to pass in a version number for every build.&lt;br /&gt;
&lt;br /&gt;
This means we have the following requirements:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Version number settable from outside for release builds&lt;/li&gt;
&lt;li&gt;Default version number for local, non-release builds&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
This can be solved by introducing a &lt;b&gt;VERSION_NUMBER&lt;/b&gt; property:&lt;br /&gt;
&lt;br /&gt;
Parent POM:&lt;br /&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;project ...&amp;gt;
  ...
  &amp;lt;version&amp;gt;${VERSION_NUMBER}&amp;lt;/version&amp;gt;
  ...
  &amp;lt;properties&amp;gt;
    ...
    &amp;lt;VERSION_NUMBER&amp;gt;1.0-SNAPSHOT&amp;lt;/VERSION_NUMBER&amp;gt;
    ...
  &amp;lt;/properties&amp;gt;
  ...
&lt;/pre&gt;&lt;br /&gt;
Child POMs:&lt;br /&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;project ...&amp;gt;
  ...
  &amp;lt;parent&amp;gt;
    ...
    &amp;lt;version&amp;gt;${VERSION_NUMBER}&amp;lt;/version&amp;gt;
    ...
  &amp;lt;/parent&amp;gt;
  ...
  &amp;lt;version&amp;gt;${VERSION_NUMBER}&amp;lt;/version&amp;gt;
  ...
&lt;/pre&gt;&lt;br /&gt;
The VERSION_NUMBER property now determines the version of our project.&lt;br /&gt;
&lt;br /&gt;
By default it is set to 1.0-SNAPSHOT for local, non-release builds.&lt;br /&gt;
It can also be set externally using -DVERSION_NUMBER=... for release builds.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;And normally, this should be it!&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Unfortunately, Maven has a &lt;a href="http://jira.codehaus.org/browse/MNG-2971"&gt;&lt;b&gt;minefield&lt;/b&gt;&lt;/a&gt; &lt;a href="http://jira.codehaus.org/browse/MNG-4223"&gt;&lt;b&gt;of&lt;/b&gt;&lt;/a&gt; &lt;a href="http://jira.codehaus.org/browse/MINSTALL-50"&gt;&lt;b&gt;bugs&lt;/b&gt;&lt;/a&gt; we need to work around. What it basically boils down to, is that Maven neglects to replace variables in installed (local repo) and deployed (remote repo) POMs. This means our POMs get deployed with &amp;lt;version&amp;gt;${VERSION_NUMBER}&amp;lt;/version&amp;gt;, which causes problems at runtime.&lt;br /&gt;
&lt;br /&gt;
We will need to overwrite the broken POMs with a new version that has its variables replaced with their values.&lt;br /&gt;
&lt;br /&gt;
The first thing we need to add (only to our parent POM) is a way to distinguisch between snapshot and release builds:&lt;br /&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;project ...&amp;gt;
  ...
  &amp;lt;properties&amp;gt;
    ...
    &amp;lt;releaseRepoUrl&amp;gt;http://my.release.repo&amp;lt;/releaseRepoUrl&amp;gt;
    &amp;lt;snapshotRepoUrl&amp;gt;http://my.snapshot.repo&amp;lt;/snapshotRepoUrl&amp;gt;
    &amp;lt;deployRepoUrl&amp;gt;${releaseRepoUrl}&amp;lt;/deployRepoUrl&amp;gt;
    &amp;lt;isRelease&amp;gt;true&amp;lt;/isRelease&amp;gt;
    ...
  &amp;lt;/properties&amp;gt;
  ...
  &amp;lt;profiles&amp;gt;
    &amp;lt;profile&amp;gt;
      &amp;lt;id&amp;gt;snapshot-deploy-url-override&amp;lt;/id&amp;gt;
      &amp;lt;activation&amp;gt;
        &amp;lt;property&amp;gt;
          &amp;lt;name&amp;gt;!VERSION_NUMBER&amp;lt;/name&amp;gt;
        &amp;lt;/property&amp;gt;
      &amp;lt;/activation&amp;gt;
      &amp;lt;properties&amp;gt;
        &amp;lt;deployRepoUrl&amp;gt;${snapshotRepoUrl}&amp;lt;/deployRepoUrl&amp;gt;
        &amp;lt;isRelease&amp;gt;false&amp;lt;/isRelease&amp;gt;
      &amp;lt;/properties&amp;gt;
    &amp;lt;/profile&amp;gt;
  &amp;lt;/profiles&amp;gt;
  ...
  &amp;lt;distributionManagement&amp;gt;
    &amp;lt;snapshotRepository&amp;gt;
      &amp;lt;id&amp;gt;snapshots-repo&amp;lt;/id&amp;gt;
      &amp;lt;name&amp;gt;Snapshots Repo&amp;lt;/name&amp;gt;
      &amp;lt;url&amp;gt;${snapshotRepoUrl}&amp;lt;/url&amp;gt;
    &amp;lt;/snapshotRepository&amp;gt;
    &amp;lt;repository&amp;gt;
      &amp;lt;id&amp;gt;releases-repo&amp;lt;/id&amp;gt;
      &amp;lt;name&amp;gt;Releases Repo&amp;lt;/name&amp;gt;
      &amp;lt;url&amp;gt;${releaseRepoUrl}&amp;lt;/url&amp;gt;
    &amp;lt;/repository&amp;gt;
  &amp;lt;/distributionManagement&amp;gt;
  ...
&lt;/pre&gt;&lt;br /&gt;
And now comes the real juicy part (only necessary in the parent POM):&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Fixing the POM by substituting the variables&lt;/li&gt;
&lt;li&gt;Overwriting the existing POM in the local repo&lt;/li&gt;
&lt;li&gt;Overwriting the existing POM in the remote repo&lt;/li&gt;
&lt;/ul&gt;&lt;pre class="brush: xml"&gt;&amp;lt;project ...&amp;gt;
  ...
  &amp;lt;build&amp;gt;
    ...
    &amp;lt;plugins&amp;gt;
      &amp;lt;plugin&amp;gt;
        &amp;lt;artifactId&amp;gt;maven-resources-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;2.4.3&amp;lt;/version&amp;gt;
        &amp;lt;executions&amp;gt;
          &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;replace-pom-placeholder&amp;lt;/id&amp;gt;
            &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;
            &amp;lt;goals&amp;gt;
              &amp;lt;goal&amp;gt;copy-resources&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
            &amp;lt;configuration&amp;gt;
              &amp;lt;resources&amp;gt;
                &amp;lt;resource&amp;gt;
                  &amp;lt;directory&amp;gt;${basedir}&amp;lt;/directory&amp;gt;
                  &amp;lt;includes&amp;gt;
                    &amp;lt;include&amp;gt;pom.xml&amp;lt;/include&amp;gt;
                  &amp;lt;/includes&amp;gt;
                  &amp;lt;filtering&amp;gt;true&amp;lt;/filtering&amp;gt;
                &amp;lt;/resource&amp;gt;
              &amp;lt;/resources&amp;gt;
              &amp;lt;outputDirectory&amp;gt;${project.build.directory}/pom-install-deploy-fix&amp;lt;/outputDirectory&amp;gt;
            &amp;lt;/configuration&amp;gt;
          &amp;lt;/execution&amp;gt;
        &amp;lt;/executions&amp;gt;
      &amp;lt;/plugin&amp;gt;

      &amp;lt;plugin&amp;gt;
        &amp;lt;artifactId&amp;gt;maven-install-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;2.3.1&amp;lt;/version&amp;gt;
        &amp;lt;executions&amp;gt;
          &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;overwrite-pom&amp;lt;/id&amp;gt;
            &amp;lt;phase&amp;gt;install&amp;lt;/phase&amp;gt;
            &amp;lt;goals&amp;gt;
              &amp;lt;goal&amp;gt;install-file&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
            &amp;lt;configuration&amp;gt;
              &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;
              &amp;lt;file&amp;gt;target/pom-install-deploy-fix/pom.xml&amp;lt;/file&amp;gt;
              &amp;lt;pomFile&amp;gt;target/pom-install-deploy-fix/pom.xml&amp;lt;/pomFile&amp;gt;
              &amp;lt;version&amp;gt;${project.version}&amp;lt;/version&amp;gt;
            &amp;lt;/configuration&amp;gt;
          &amp;lt;/execution&amp;gt;
        &amp;lt;/executions&amp;gt;
      &amp;lt;/plugin&amp;gt;

      &amp;lt;plugin&amp;gt;
        &amp;lt;artifactId&amp;gt;maven-deploy-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;2.5&amp;lt;/version&amp;gt;
        &amp;lt;executions&amp;gt;
          &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;overwrite-pom&amp;lt;/id&amp;gt;
            &amp;lt;phase&amp;gt;deploy&amp;lt;/phase&amp;gt;
            &amp;lt;goals&amp;gt;
              &amp;lt;goal&amp;gt;deploy-file&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
            &amp;lt;configuration&amp;gt;
              &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;
              &amp;lt;file&amp;gt;target/pom-install-deploy-fix/pom.xml&amp;lt;/file&amp;gt;
              &amp;lt;pomFile&amp;gt;target/pom-install-deploy-fix/pom.xml&amp;lt;/pomFile&amp;gt;
              &amp;lt;url&amp;gt;${deployRepoUrl}&amp;lt;/url&amp;gt;
              &amp;lt;version&amp;gt;${project.version}&amp;lt;/version&amp;gt;
              &amp;lt;updateReleaseInfo&amp;gt;${isRelease}&amp;lt;/updateReleaseInfo&amp;gt;
              &amp;lt;uniqueVersion&amp;gt;false&amp;lt;/uniqueVersion&amp;gt;
            &amp;lt;/configuration&amp;gt;
          &amp;lt;/execution&amp;gt;
        &amp;lt;/executions&amp;gt;
      &amp;lt;/plugin&amp;gt;
      ...
    &amp;lt;/plugins&amp;gt;
    ...
  &amp;lt;/build&amp;gt;
  ...
&lt;/pre&gt;&lt;br /&gt;
If you also want to deploy &lt;b&gt;source artifacts&lt;/b&gt;, check out the &lt;a href="http://maven.apache.org/plugins/maven-source-plugin/usage.html"&gt;Maven Source Plugin&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
So far, so good: we now have taken care of the &lt;b&gt;deployment in the Artifact Repository&lt;/b&gt;!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's add the final bit to enable &lt;b&gt;SCM tagging&lt;/b&gt;...&lt;br /&gt;
&lt;br /&gt;
First add the scm section to your parent POM:&lt;br /&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;project ...&amp;gt;
  ...
  &amp;lt;scm&amp;gt;
    &amp;lt;connection&amp;gt;scm:my-provider:my-read-url&amp;lt;/connection&amp;gt;
    &amp;lt;developerConnection&amp;gt;scm:my-provider:my-read-write-url&amp;lt;/developerConnection&amp;gt;
  &amp;lt;/scm&amp;gt;
  ...
&lt;/pre&gt;&lt;br /&gt;
And now add the scm plugin to the plugins section of the parent POM:&lt;br /&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;plugin&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-scm-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.4&amp;lt;/version&amp;gt;
    &amp;lt;configuration&amp;gt;
      &amp;lt;tag&amp;gt;${project.artifactId}-${VERSION_NUMBER}&amp;lt;/tag&amp;gt;
    &amp;lt;/configuration&amp;gt;
  &amp;lt;/plugin&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
Done!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;publish new snapshots&lt;/b&gt; using&lt;br /&gt;
mvn clean deploy&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;release and tag new versions&lt;/b&gt; using&lt;br /&gt;
mvn clean deploy scm:tag -DVERSION_NUMBER=1.2.3&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
In &lt;a href="http://www.axelfontaine.com/2011/02/maven-releases-on-steroids-3-rounding.html"&gt;&lt;b&gt;Part 3&lt;/b&gt;&lt;/a&gt;, we conclude our adventure by choosing a version number strategy and looking at Jenkins integration.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-4993257412484732357?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/34ZjM_3KdnY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/4993257412484732357/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2011/01/maven-releases-on-steroids-2-preparing.html#comment-form" title="15 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/4993257412484732357?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/4993257412484732357?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/34ZjM_3KdnY/maven-releases-on-steroids-2-preparing.html" title="Maven Releases on Steroids (2): Preparing the POMs" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><thr:total>15</thr:total><feedburner:origLink>http://www.axelfontaine.com/2011/01/maven-releases-on-steroids-2-preparing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08EQHs-cSp7ImA9Wx9UE0o.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-3582047714607680523</id><published>2011-01-23T14:50:00.003+01:00</published><updated>2011-02-10T23:10:01.559+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-10T23:10:01.559+01:00</app:edited><title>Maven Releases on Steroids: Adios Release Plugin!</title><content type="html">One of the central themes of my current series of talks about Continuous Delivery is &lt;b&gt;releasing software&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Releasing software encompasses a number of activities such as&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Picking a version number&lt;/li&gt;
&lt;li&gt;Checking out the latest revision from SCM&lt;/li&gt;
&lt;li&gt;Building and Testing binaries&lt;/li&gt;
&lt;li&gt;Tagging the SCM revison with the version number&lt;/li&gt;
&lt;li&gt;Publishing the binary artifacts in an Artifact Repository&lt;/li&gt;
&lt;li&gt;Writing release notes, announcement e-mails, etc...&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
In order to avoid the &lt;a href="http://www.codinghorror.com/blog/2007/03/the-works-on-my-machine-certification-program.html"&gt;&lt;b&gt;Works On My Machine&lt;/b&gt;&lt;/a&gt; syndrome, releases are typically built centrally on a &lt;b&gt;continuous integration server&lt;/b&gt; such as &lt;strike&gt;Hudson&lt;/strike&gt; &lt;a href="http://jenkins-ci.org/"&gt;Jenkins&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
The Continuous Integration server serves as a choreographer between the following components:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;SCM (&lt;a href="http://subversion.apache.org/"&gt;Subversion&lt;/a&gt;, &lt;a href="http://mercurial.selenic.com/"&gt;Mercurial&lt;/a&gt;, &lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt;, ...)&lt;/li&gt;
&lt;li&gt;Build Tool (&lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt;, &lt;a href="http://ant.apache.org/"&gt;Ant&lt;/a&gt;, &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt;, ...)&lt;/li&gt;
&lt;li&gt;Artifact Repository (&lt;a href="http://nexus.sonatype.org/"&gt;Nexus&lt;/a&gt;, &lt;a href="http://www.jfrog.org/products.php"&gt;Artifactory&lt;/a&gt;, ...)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
On &lt;b&gt;Maven projects&lt;/b&gt;, the Building, Testing, Tagging and Publishing steps have traditionally been handled by the &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/"&gt;&lt;b&gt;Maven Release Plugin&lt;/b&gt;&lt;/a&gt;. It works, to a reasonable degree, and it has a decent &lt;a href="http://wiki.jenkins-ci.org/display/HUDSON/M2+Release+Plugin"&gt;Jenkins plugin&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Using Jenkins and the Release Plugin, here are the typical steps performed by the various components:&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;Safety Notice:&lt;/span&gt;&lt;/b&gt; buckle up, it's going to be a wild ride!)&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Jenkins &lt;b&gt;checks out&lt;/b&gt; the latest revision from SCM&lt;/li&gt;
&lt;li&gt;Maven &lt;b&gt;compiles&lt;/b&gt; the sources and runs the &lt;b&gt;tests&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Release Plugin &lt;b&gt;transforms the POMs&lt;/b&gt; with the new version number&lt;/li&gt;
&lt;li&gt;Maven &lt;b&gt;compiles&lt;/b&gt; the sources and runs the &lt;b&gt;tests&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Release Plugin &lt;b&gt;commits&lt;/b&gt; the new POMs into SCM&lt;/li&gt;
&lt;li&gt;Release Plugin &lt;b&gt;tags&lt;/b&gt; the new SCM revision with the version number&lt;/li&gt;
&lt;li&gt;Release Plugin &lt;b&gt;transforms the POMs&lt;/b&gt; to version n+1 -SNAPSHOT&lt;/li&gt;
&lt;li&gt;Release Plugin &lt;b&gt;commits&lt;/b&gt; the new new POMs into SCM&lt;/li&gt;
&lt;li&gt;Release Plugin &lt;b&gt;checks out&lt;/b&gt; the new tag from SCM&lt;/li&gt;
&lt;li&gt;Maven &lt;b&gt;compiles&lt;/b&gt; the sources and runs the &lt;b&gt;tests&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Maven &lt;b&gt;publishes&lt;/b&gt; the binaries into the Artifact Repository&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Phew! Did you count it?&lt;br /&gt;
&lt;br /&gt;
That's &lt;b&gt;3 full clean/compile/test cycles&lt;/b&gt;, &lt;b&gt;2 POM transformation rounds&lt;/b&gt; and &lt;b&gt;3 different SCM revisions&lt;/b&gt;!&lt;br /&gt;
&lt;br /&gt;
No wonder this thing has proved to be error prone and frustrating to many developers for years now. And let's not even get me started on how well this thing blows up when another team member unsuspectingly checks in a change to the POM in the middle of this multiple transform and commit carousel...&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;So is there another way?&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
What if we could deal with only a &lt;b&gt;single SCM revision&lt;/b&gt; (the one we want to release) going through a &lt;b&gt;single clean/compile/test run&lt;/b&gt; before &lt;b&gt;tagging&lt;/b&gt; the source and &lt;b&gt;publishing&lt;/b&gt; the binaries?&lt;br /&gt;
&lt;br /&gt;
Let me say this loud and clear: yes, we can!&lt;br /&gt;
&lt;br /&gt;
The &lt;b&gt;solution&lt;/b&gt; I present in part 2 does just that. This is what it looks like:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Jenkins &lt;b&gt;checks out&lt;/b&gt; the latest revision from SCM&lt;/li&gt;
&lt;li&gt;Maven &lt;b&gt;compiles&lt;/b&gt; the sources and runs the &lt;b&gt;tests&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Maven &lt;b&gt;tags&lt;/b&gt; the SCM revision with the version number&lt;/li&gt;
&lt;li&gt;Maven &lt;b&gt;publishes&lt;/b&gt; the binaries into the Artifact Repository&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;b&gt;Simple and to the point.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Continue to &lt;a href="http://www.axelfontaine.com/2011/01/maven-releases-on-steroids-2-preparing.html"&gt;&lt;b&gt;Part 2&lt;/b&gt;&lt;/a&gt; where we go into the adjustments to make to the POMs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-3582047714607680523?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/RBUi-Ina2U4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/3582047714607680523/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2011/01/maven-releases-on-steroids-adios.html#comment-form" title="18 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/3582047714607680523?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/3582047714607680523?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/RBUi-Ina2U4/maven-releases-on-steroids-adios.html" title="Maven Releases on Steroids: Adios Release Plugin!" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><thr:total>18</thr:total><feedburner:origLink>http://www.axelfontaine.com/2011/01/maven-releases-on-steroids-adios.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4MR3o5fCp7ImA9Wx9WEk0.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-2240303019203299990</id><published>2011-01-16T20:53:00.002+01:00</published><updated>2011-01-16T20:59:46.424+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-16T20:59:46.424+01:00</app:edited><title>Ubuntu Server 10.10 on Virtual PC under Windows 7</title><content type="html">&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;A while ago, I described how to &lt;a href="http://www.axelfontaine.com/2009/11/taming-beasts-getting-ubuntu-server-910.html"&gt;get Ubuntu Server 9.10 to run Windows Virtual PC&lt;/a&gt;.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;As it turned out though, the beasts were only tamed for a release or two. For Ubuntu Server 10.10 this guide needed an update, so here it is!&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;These are the steps required to get &lt;b&gt;Ubuntu Server 10.10&lt;/b&gt; to run on &lt;b&gt;Windows Virtual PC&lt;/b&gt; under &lt;b&gt;Windows 7&lt;/b&gt;.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;For this to work you will need:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Windows 7 with Virtual PC installed&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;The &lt;a href="http://www.ubuntu.com/server/get-ubuntu/download"&gt;Ubuntu Server 10.10 32-bit ISO&lt;/a&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;(Virtual PC still does not support 64-bit guests)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
Ready? Let's go !&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;1.&amp;nbsp;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;In the&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&lt;b&gt;Virtual Machines&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;folder, create a new VM. Before launching it, edit the settings to&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&lt;b&gt;&amp;nbsp;mount the Ubuntu ISO&lt;br /&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #333333;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit; font-size: 15px; line-height: 20px;"&gt;2. Launch the VM and select your language.&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #333333;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit; font-size: 15px; line-height: 20px;"&gt;3. Press &lt;b&gt;F4&lt;/b&gt; and select &lt;b&gt;Install a minimum virtual machine&lt;br /&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_MrqrMUHR5FA/TTNKFwpl3HI/AAAAAAAAAB4/nhFWVCH6QhI/s1600/mode-select.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="330" src="http://1.bp.blogspot.com/_MrqrMUHR5FA/TTNKFwpl3HI/AAAAAAAAAB4/nhFWVCH6QhI/s400/mode-select.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="color: #333333;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit; font-size: 15px; line-height: 20px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;4. Perform the installation all the way through.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;5. After the reboot, in Grub, select the &lt;b&gt;first entry&lt;/b&gt; and press "&lt;b&gt;e&lt;/b&gt;" to edit it.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;6.&amp;nbsp;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;Add "&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&lt;b&gt;noreplace-paravirt vga=771&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;" (no quotes) before "&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&lt;b&gt;quiet&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;" on the second last line and press&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&lt;b&gt;Ctrl+x&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;to boot&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;7.&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;Log in and edit the file called "&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;&lt;b&gt;/etc/default/grub&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-size: 15px; line-height: 20px;"&gt;" as root. Change the line with &lt;b&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/b&gt; in:&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;pre class="brush: shell"&gt;GRUB_CMDLINE_LINUX_DEFAULT="noreplace-paravirt vga=771 quiet"
&lt;/pre&gt;8. Execute this command:&lt;br /&gt;
&lt;pre class="brush: shell"&gt;sudo update-grub&lt;/pre&gt;9. Reboot&lt;br /&gt;
&lt;br /&gt;
10. &lt;b&gt;Welcome to Ubuntu Server 10.10 under Virtual PC on Windows 7!&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_MrqrMUHR5FA/TTNMk63CSAI/AAAAAAAAAB8/y4wV595uvM4/s1600/login-prompt.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="215" src="http://4.bp.blogspot.com/_MrqrMUHR5FA/TTNMk63CSAI/AAAAAAAAAB8/y4wV595uvM4/s400/login-prompt.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-2240303019203299990?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/XDqNNnro9L0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/2240303019203299990/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2011/01/ubuntu-server-1010-on-windows-virtual.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/2240303019203299990?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/2240303019203299990?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/XDqNNnro9L0/ubuntu-server-1010-on-windows-virtual.html" title="Ubuntu Server 10.10 on Virtual PC under Windows 7" /><author><name>Axel Fontaine</name><uri>http://www.blogger.com/profile/10171437570584982231</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://3.bp.blogspot.com/_MrqrMUHR5FA/TSNjTa1ki_I/AAAAAAAAAAM/41KQ-hmLvng/S220/photo.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_MrqrMUHR5FA/TTNKFwpl3HI/AAAAAAAAAB4/nhFWVCH6QhI/s72-c/mode-select.png" height="72" width="72" /><thr:total>5</thr:total><feedburner:origLink>http://www.axelfontaine.com/2011/01/ubuntu-server-1010-on-windows-virtual.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYBRXYyfip7ImA9Wx9VEEo.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-2475187205748987437</id><published>2009-11-24T11:29:00.003+01:00</published><updated>2011-01-26T21:35:54.896+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-26T21:35:54.896+01:00</app:edited><title>The 600 Euro upgrade that cut build times in half</title><content type="html">In the past, I have talked &lt;a href="http://blog.axelfontaine.eu/2009/11/taming-beasts-getting-ubuntu-server-910.html"&gt;here&lt;/a&gt; and &lt;a href="http://blog.axelfontaine.eu/2009/11/running-ie-6-7-and-8-simultaneously-on.html"&gt;here&lt;/a&gt; about my test environment for &lt;a href="http://www.veturanto.com/"&gt;Veturanto&lt;/a&gt;. Today I'll talk about my development environment instead.&lt;br /&gt;
&lt;br /&gt;
My main workstation used to have the following hardware configuration:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Intel Core 2 Duo (dual core) @ 1.86 Ghz&lt;/li&gt;
&lt;li&gt;4 GB DDR2 RAM &lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Western Digital VelociRaptor 300 GB @ 10000 RPM&lt;/li&gt;
&lt;/ul&gt;Decent, but not the absolute latest.&lt;br /&gt;
&lt;br /&gt;
About two and a half months ago, a worthy successor of the &lt;i&gt;Core 2 Duo&lt;/i&gt; arrived on the market: the &lt;b&gt;&lt;i&gt;Intel Core i5&lt;/i&gt;&lt;/b&gt;. By that time, Intel had also released the &lt;b&gt;second generation of its high-performance SSDs&lt;/b&gt;. It was time for an upgrade.&lt;br /&gt;
&lt;br /&gt;
I decided to take the plunge and invested about 600 Euro in the following hardware:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Intel Core i5 750 (quad core) @ 3.01 Ghz (overclocked from 2.67 Ghz)&lt;/li&gt;
&lt;li&gt;Scythe Ninja 2 Cooler (yes, I do share &lt;a href="http://www.codinghorror.com/blog/archives/000707.html"&gt;Jeff Atwood's giant heatsink fettish&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Asus P7P55D Pro motherboard &lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;8 GB DDR3 RAM&lt;/li&gt;
&lt;li&gt;Intel Postville 34nm SSD 80 GB&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_-pOGRs8-Xu0/Swur_6WqwOI/AAAAAAAAAE4/rD-Aoo5yF9E/s1600/WindowsExperienceIndex.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_-pOGRs8-Xu0/Swur_6WqwOI/AAAAAAAAAE4/rD-Aoo5yF9E/s640/WindowsExperienceIndex.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;But what kind of performance do you get out of this?&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Let's compare two day to day activities: the&lt;b&gt; full build&lt;/b&gt; and the&lt;b&gt; application startup&lt;/b&gt; times.&lt;br /&gt;
&lt;br /&gt;
Here is how they fared:&lt;br /&gt;
&lt;table height="105" style="border: 1px solid; padding: 5px; width: 453px;"&gt;&lt;tbody&gt;
&lt;tr align="left"&gt;&lt;td&gt;&lt;/td&gt; &lt;td style="text-align: center;"&gt;&lt;i&gt;&lt;b&gt;&lt;span style="font-size: small;"&gt;Core 2 Duo + Raptor&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;/td&gt; &lt;td style="text-align: center;"&gt;&lt;i&gt;&lt;b&gt;Core i5 + SSD&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;/td&gt; &lt;/tr&gt;
&lt;tr align="left"&gt;     &lt;td&gt;Full build&lt;br /&gt;
&lt;/td&gt;     &lt;td style="color: red; text-align: center;"&gt;1 minute 50 seconds&lt;br /&gt;
&lt;/td&gt;     &lt;td style="color: #38761d; text-align: center;"&gt;&lt;b&gt;45 seconds &lt;/b&gt;&lt;br /&gt;
&lt;/td&gt;   &lt;/tr&gt;
&lt;tr&gt;     &lt;td style="text-align: left;"&gt;Application startup&lt;br /&gt;
&lt;/td&gt;     &lt;td style="color: red; text-align: center;"&gt;17 seconds&lt;br /&gt;
&lt;/td&gt;     &lt;td style="color: #38761d; text-align: center;"&gt;&lt;b&gt;5 seconds &lt;/b&gt;&lt;br /&gt;
&lt;/td&gt;   &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
&lt;b&gt;The difference is nothing short of phenomenal !&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Go out, get a modern processor and a high-performance SSD and you'll never look back !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-2475187205748987437?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/Qv23bFbMYX8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/2475187205748987437/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2009/11/600-euro-upgrade-that-cut-build-times.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/2475187205748987437?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/2475187205748987437?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/Qv23bFbMYX8/600-euro-upgrade-that-cut-build-times.html" title="The 600 Euro upgrade that cut build times in half" /><author><name>Axel Fontaine</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/TRpSbvk7ZvI/AAAAAAAAAFQ/9iUViVJCNnw/S220/photo.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_-pOGRs8-Xu0/Swur_6WqwOI/AAAAAAAAAE4/rD-Aoo5yF9E/s72-c/WindowsExperienceIndex.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.axelfontaine.com/2009/11/600-euro-upgrade-that-cut-build-times.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cDRnwyfip7ImA9WxNbFUk.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-1092694281831696865</id><published>2009-11-18T11:44:00.001+01:00</published><updated>2009-11-18T11:44:37.296+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-18T11:44:37.296+01:00</app:edited><title>One Minute Book Review: Crossing the Chasm</title><content type="html">Last week, I finished reading Geoffrey Moore's excellent&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt; &lt;a href="http://www.amazon.com/Crossing-Chasm-Marketing-High-Tech-Mainstream/dp/0066620023"&gt;Crossing the Chasm&lt;/a&gt;: Marketing and Selling high-tech products to mainstream customers.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_-pOGRs8-Xu0/SwPCuM651YI/AAAAAAAAAEQ/pqOD18HRx6k/s1600/Chossing-the-chasm-cover.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_-pOGRs8-Xu0/SwPCuM651YI/AAAAAAAAAEQ/pqOD18HRx6k/s400/Chossing-the-chasm-cover.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size: x-small;"&gt;(image courtesy of &lt;a href="http://en.wikipedia.org/wiki/Crossing_the_Chasm"&gt;wikipedia&lt;/a&gt;) &lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
Moore sets out by describing the&lt;i&gt; &lt;/i&gt;&lt;b&gt;technology adoption lifecycle&lt;/b&gt;, and the different demographics that compose it:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="color: #0b5394;"&gt;&lt;b&gt;&lt;i&gt;&lt;span style="font-size: large;"&gt;Innovators&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;The &lt;b&gt;Technology Enthusiasts&lt;/b&gt; live on the bleeding edge and take pride to being the first try out new things. They generate the first buzz, but lack loyalty.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="color: #0b5394;"&gt;&lt;span style="font-size: large;"&gt;&lt;i&gt;&lt;b&gt;Early Adopters&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;The &lt;b&gt;Visionaries&lt;/b&gt; see great new strategic opportunities in new products, and are willing the invest and participate heavily in the product development to get a game changing advantage over the competition.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="color: #0b5394;"&gt;&lt;i&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Early Majority&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;/div&gt;The &lt;b&gt;Pragmatists &lt;/b&gt;stand for continuity. They want a proven solution helping them make an incremental, predictable improvement to their business.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; color: #0b5394;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;i&gt;Late Majority&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;The &lt;b&gt;Conservatives &lt;/b&gt;believe more in tradition than progress. They will finally adopt new technologies when I becomes inconvenient not do so. By that time, the products have become a commodity, that is well tested and sells with low margins.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="color: #0b5394;"&gt;&lt;span style="font-size: large;"&gt;&lt;i&gt;&lt;b&gt;Laggards&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;The &lt;b&gt;Skeptics &lt;/b&gt;pride themselves in intentionally being behind the mainstream. They do not participate in the high-tech marketplace, except to block purchases. Their contribution is feedback about the discrepancies between sales claims and delivered products.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
But then comes the key observation: the technology adaption lifecycle does not look like a nicely shaped bell-curve, but more like this:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_-pOGRs8-Xu0/SwPCr1QEKRI/AAAAAAAAAEI/ZxtcqNWoPN8/s1600/800px-Technology-Adoption-Lifecycle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_-pOGRs8-Xu0/SwPCr1QEKRI/AAAAAAAAAEI/ZxtcqNWoPN8/s400/800px-Technology-Adoption-Lifecycle.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;span style="font-size: x-small;"&gt;(image courtesy of &lt;a href="http://en.wikipedia.org/wiki/Crossing_the_Chasm"&gt;wikipedia&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt; &lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt; &lt;br /&gt;
&lt;/div&gt;Ans this will be the central theme of the rest of the book: what separates &lt;i&gt;early&lt;/i&gt; and &lt;i&gt;mainstream markets&lt;/i&gt;, the gap between &lt;i&gt;early adopters&lt;/i&gt; and &lt;i&gt;early majority&lt;/i&gt;, the &lt;b&gt;Chasm&lt;/b&gt;, and &lt;b&gt;how to cross it&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Moore makes a compelling argument around what he calls &lt;b&gt;Beachhead Strategy&lt;/b&gt; and the &lt;b&gt;Whole Product Model&lt;/b&gt;. He describes what it takes for a company to get a foothold in the mainstream market and expand from there.&lt;br /&gt;
&lt;br /&gt;
A great read. &lt;b&gt;Highly recommended.&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-1092694281831696865?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/xePtFyyizX0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/1092694281831696865/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2009/11/one-minute-book-review-crossing-chasm.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/1092694281831696865?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/1092694281831696865?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/xePtFyyizX0/one-minute-book-review-crossing-chasm.html" title="One Minute Book Review: Crossing the Chasm" /><author><name>Axel Fontaine</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/TRpSbvk7ZvI/AAAAAAAAAFQ/9iUViVJCNnw/S220/photo.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_-pOGRs8-Xu0/SwPCuM651YI/AAAAAAAAAEQ/pqOD18HRx6k/s72-c/Chossing-the-chasm-cover.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.axelfontaine.com/2009/11/one-minute-book-review-crossing-chasm.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEMQ3k8eyp7ImA9WxNbEE4.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-2384832686899678090</id><published>2009-11-12T13:44:00.001+01:00</published><updated>2009-11-12T13:58:02.773+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-12T13:58:02.773+01:00</app:edited><title>The perils of the missing javascript block scope</title><content type="html">Javascript variable scope is something of a strange thing. You have a &lt;i&gt;global&lt;/i&gt; and a &lt;i&gt;function&lt;/i&gt; scope. &lt;b&gt;But unlike most other languages, there is no &lt;i&gt;block&lt;/i&gt; scope!&lt;/b&gt; This is often a cause for hard to find bugs.&lt;br /&gt;
&lt;br /&gt;
Let me show you the consequences of this with a small puzzler:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: html"&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;a id="link1" href=""&amp;gt;Link 1&amp;lt;/a&amp;gt; &amp;lt;span id="part1"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;a id="link2" href=""&amp;gt;Link 2&amp;lt;/a&amp;gt; &amp;lt;span id="part2"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;a id="link3" href=""&amp;gt;Link 3&amp;lt;/a&amp;gt; &amp;lt;span id="part3"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;a id="link4" href=""&amp;gt;Link 4&amp;lt;/a&amp;gt; &amp;lt;span id="part4"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;a id="link5" href=""&amp;gt;Link 5&amp;lt;/a&amp;gt; &amp;lt;span id="part5"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
No Link 6 &amp;lt;span id="part6"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;

&amp;lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type="text/javascript"&amp;gt;
  $(document).ready(function() {
    for (i = 1; i &amp;lt;= 5; i++) {
      $("#link"+i).click(function() {
        $("#part"+i).html("Clicked !");
        return false;
      });
    }
  });
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Now what does this do?&lt;/b&gt; (you need a bit of &lt;a href="http://www.jquery.com/"&gt;jquery&lt;/a&gt; knowledge to guess it)&lt;br /&gt;
&lt;br /&gt;
At first glance, it walks over the 5 links present on this page, and registers a handler for mouse clicks that adds the text "Clicked !" to the span element with the same number as the link.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Or does it?&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Well, this is what the output looks like when you click on "Link 3":&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;a href="http://4.bp.blogspot.com/_-pOGRs8-Xu0/Svv8bS65GQI/AAAAAAAAAD4/3nV_kYVMjq4/s1600-h/test.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_-pOGRs8-Xu0/Svv8bS65GQI/AAAAAAAAAD4/3nV_kYVMjq4/s320/test.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;b style="color: red;"&gt;It is totally wrong !&lt;/b&gt; Now why is that? Well, as we have no block scope, by the time we are done with the for loop, the variable&lt;b&gt; i has been incremented up to 6&lt;/b&gt;. It is however &lt;b&gt;still in scope&lt;/b&gt;, and therefore this last value gets used &lt;b&gt;when the closure for the click event gets called&lt;/b&gt;. And so it is part 6 that receives the new text !&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;So how can we fix this?&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
We have to &lt;b&gt;separate the scopes&lt;/b&gt;, and to do that we need a &lt;b&gt;new function&lt;/b&gt;. This is what the correct code looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: html"&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;a id="link1" href=""&amp;gt;Link 1&amp;lt;/a&amp;gt; &amp;lt;span id="part1"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;a id="link2" href=""&amp;gt;Link 2&amp;lt;/a&amp;gt; &amp;lt;span id="part2"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;a id="link3" href=""&amp;gt;Link 3&amp;lt;/a&amp;gt; &amp;lt;span id="part3"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;a id="link4" href=""&amp;gt;Link 4&amp;lt;/a&amp;gt; &amp;lt;span id="part4"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;a id="link5" href=""&amp;gt;Link 5&amp;lt;/a&amp;gt; &amp;lt;span id="part5"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
No Link 6 &amp;lt;span id="part6"&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;

&amp;lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type="text/javascript"&amp;gt;
  $(document).ready(function() {
    for (i = 1; i &amp;lt;= 5; i++) {
      addClickEvent(i);
    }
  });
  
  function addClickEvent(i) {
    $("#link"+i).click(function() {
      $("#part"+i).html("Clicked !");
      return false;
    });
  }
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
With the registration of the click event taking place in a separate function (and therefore a separate scope for the variable i), this is what the output looks like:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;a href="http://4.bp.blogspot.com/_-pOGRs8-Xu0/Svv-D61PbAI/AAAAAAAAAEA/LuiopOTLkxE/s1600-h/testOk.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_-pOGRs8-Xu0/Svv-D61PbAI/AAAAAAAAAEA/LuiopOTLkxE/s320/testOk.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;Which is much more like what we were expecting !&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;So beware of the lack of &lt;i&gt;block&lt;/i&gt; scope in Javascript! It can come and bite more easily than you think if you're not extra careful about it!&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-2384832686899678090?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/1NLoAQ_va40" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/2384832686899678090/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2009/11/perils-of-missing-javascript-block.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/2384832686899678090?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/2384832686899678090?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/1NLoAQ_va40/perils-of-missing-javascript-block.html" title="The perils of the missing javascript block scope" /><author><name>Axel Fontaine</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/TRpSbvk7ZvI/AAAAAAAAAFQ/9iUViVJCNnw/S220/photo.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_-pOGRs8-Xu0/Svv8bS65GQI/AAAAAAAAAD4/3nV_kYVMjq4/s72-c/test.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.axelfontaine.com/2009/11/perils-of-missing-javascript-block.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQAR345fip7ImA9WxNUFEk.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-3741151993561830951</id><published>2009-11-04T18:22:00.010+01:00</published><updated>2009-11-05T18:49:06.026+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-05T18:49:06.026+01:00</app:edited><title>Taming the beasts: Getting Ubuntu Server 9.10 to run in Virtual PC on Windows 7</title><content type="html">As I &lt;a href="http://blog.axelfontaine.eu/2009/11/running-ie-6-7-and-8-simultaneously-on.html"&gt;wrote&lt;/a&gt;, I am a big fan of Windows 7 and virtualization. While my development environment for &lt;a href="http://www.veturanto.com/"&gt;Veturanto&lt;/a&gt; runs on Windows, the production server runs on &lt;a href="http://www.ubuntu.com/products/whatIsubuntu/serveredition"&gt;Ubuntu Server&lt;/a&gt;. Ubuntu Server is great and by far the best Linux distribution available at the moment. One piece of the Veturanto infrastructure puzzle I haven't talked about yet is the test server. As I want it to be as close as possible to the production environment, it also naturally runs the same OS. And being a virtualization fan, I want it to run in a window to boot.&lt;br /&gt;
&lt;br /&gt;
However &lt;b&gt;Virtual PC and Ubuntu Server&lt;/b&gt; have a history of making life difficult for each other and &lt;b&gt;not playing together nicely&lt;/b&gt;. There is however a way to get them to cooperate.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;So let's go and tame these beasts!&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;For this to work you will need:&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Windows 7 with Virtual PC installed (see my &lt;a href="http://blog.axelfontaine.eu/2009/11/running-ie-6-7-and-8-simultaneously-on.html"&gt;previous blog post&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;a href="http://www.ubuntu.com/getubuntu/download-server"&gt;Ubuntu Server 9.10 32-bit ISO&lt;/a&gt; (Virtual PC does not yet support 64-bit guests)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Ok, let's get started!&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
1. In the &lt;b&gt;Virtual Machines&lt;/b&gt; folder, create a new VM. Before launching it, edit the settings to&lt;b&gt; mount the Ubuntu ISO&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
2. Launch the VM and run the installation normally.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_-pOGRs8-Xu0/SvK9OMVpD8I/AAAAAAAAADY/YJG3BPakVD4/s1600-h/install.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/SvK9OMVpD8I/AAAAAAAAADY/YJG3BPakVD4/s400/install.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
3. In Grub, select the &lt;b&gt;Linux 2.6.31-14-generic-pae&lt;/b&gt; entry and press "&lt;b&gt;e&lt;/b&gt;" to edit it.&lt;br /&gt;
&lt;br /&gt;
4. Add "&lt;b&gt;noreplace-paravirt vga=771&lt;/b&gt;" (no quotes) before "&lt;b&gt;quiet splash&lt;/b&gt;" on the second last line and press &lt;b&gt;Ctrl+x&lt;/b&gt; to boot&lt;br /&gt;
&lt;br /&gt;
5. Log in and create a file called "&lt;b&gt;/etc/default/grub&lt;/b&gt;" as root with this content:&lt;br /&gt;
&lt;pre class="brush: text"&gt;GRUB_DEFAULT=0
GRUB_CMDLINE_LINUX_DEFAULT="noreplace-paravirt vga=771 quiet splash"
&lt;/pre&gt;&lt;br /&gt;
6. Execute this command:&lt;br /&gt;
&lt;pre class="brush: shell"&gt;sudo update-grub
&lt;/pre&gt;&lt;br /&gt;
7. Reboot&lt;br /&gt;
&lt;br /&gt;
8. &lt;b&gt;Welcome to Ubuntu Server 9.10 under Virtual PC on Windows 7 !&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_-pOGRs8-Xu0/SvK_eAIQMaI/AAAAAAAAADw/nnwuD-6kumU/s1600-h/welcome.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_-pOGRs8-Xu0/SvK_eAIQMaI/AAAAAAAAADw/nnwuD-6kumU/s400/welcome.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Note:&lt;/b&gt; Credits go to &lt;a href="http://www.myoddweb.com/2009/07/04/install-ubuntu-9-on-virtual-pc-2007-part-deux/"&gt;this post&lt;/a&gt; and &lt;a href="http://tombuntu.com/index.php/2007/09/05/making-ubuntu-server-work-in-virtualbox/"&gt;this post&lt;/a&gt; as they were essential inspiration to arrive at this solution!&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: red;"&gt;&lt;b&gt;Update:&lt;/b&gt;&lt;span style="color: black;"&gt; Removed the bit about changing the kernel. It wasn't necessary.&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-3741151993561830951?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/hrnZIGJg36c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/3741151993561830951/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2009/11/taming-beasts-getting-ubuntu-server-910.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/3741151993561830951?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/3741151993561830951?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/hrnZIGJg36c/taming-beasts-getting-ubuntu-server-910.html" title="Taming the beasts: Getting Ubuntu Server 9.10 to run in Virtual PC on Windows 7" /><author><name>Axel Fontaine</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/TRpSbvk7ZvI/AAAAAAAAAFQ/9iUViVJCNnw/S220/photo.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_-pOGRs8-Xu0/SvK9OMVpD8I/AAAAAAAAADY/YJG3BPakVD4/s72-c/install.png" height="72" width="72" /><thr:total>5</thr:total><feedburner:origLink>http://www.axelfontaine.com/2009/11/taming-beasts-getting-ubuntu-server-910.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUAGQX88fip7ImA9WxNUFE8.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-5915220059685944431</id><published>2009-11-04T17:17:00.006+01:00</published><updated>2009-11-05T13:22:00.176+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-05T13:22:00.176+01:00</app:edited><title>Browser testing on steroids: Running IE 6, 7 and 8 simultaneously on Windows 7</title><content type="html">I use Windows 7 on my development machine. It works great, and I've especially come to like the deep integration features provided by Windows Virtual PC, as I'll show you in this blog post. They have been a tremendous time-saver when it comes to testing &lt;a href="http://www.veturanto.com/"&gt;Veturanto&lt;/a&gt;, the website I am currently working on. I usually test the website using Firefox 3.5, Chrome 3, IE 6, IE7 and IE8.&lt;br /&gt;
&lt;br /&gt;
Firefox, Chrome and IE8 all run natively on Windows 7, no problem there. But what about IE6 and IE7? These guys only run on XP (IE 6 &amp;amp; 7) and Vista (IE 7). Are we out of luck? Not quite. First we have virtualization to the rescue and second we don't even need our own licenses as Microsoft freely provides &lt;a href="http://www.microsoft.com/DOWNLOADS/details.aspx?FamilyID=21eabb90-958f-4b64-b5f1-73d0a413c8ef&amp;amp;displaylang=en"&gt;VHDs of both these browsers both on XP SP3 and Vista&lt;/a&gt; to run tests on. (Note that they do expire every few months, but Microsoft always provides new ones in time.)&lt;br /&gt;
&lt;br /&gt;
This post shows how to use them most effectively to&lt;b&gt; deeply integrate IE 6 and IE 7 into Windows 7&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;So let's get to work!&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
For this to work we will &lt;b&gt;need&lt;/b&gt; the following things:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Windows 7 with &lt;a href="http://www.microsoft.com/windows/virtual-pc/download.aspx"&gt;Windows Virtual PC&lt;/a&gt; installed. It is a free optional component of Windows 7. (On the download page, select Ultimate to reveal the download buttons. If you have Windows 7 Home Premium&lt;a href="http://blogs.msdn.com/virtual_pc_guy/archive/2009/10/22/windows-virtual-pc-windows-xp-mode-rtm-now-available-for-general-download.aspx#9911442"&gt; you can still use Virtual PC, but not XP Mode&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;amp;FamilyID=21eabb90-958f-4b64-b5f1-73d0a413c8ef"&gt;XP SP3 IE6 and XP SP3 IE7 application compatibility VHDs&lt;/a&gt;, extracted in your Virtual Machines folder.&lt;/li&gt;
&lt;li&gt;A Windows XP Installation CD in your CD drive (this will be needed for the Integration Components installation)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have all that ready, let's get started. The following steps describe the IE 6 installation, simply repeat them with the other VHD to install IE 7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1. Select the &lt;b&gt;IE6 on XP SP3.vhd&lt;/b&gt; file and click &lt;b&gt;Create virtual machine&lt;/b&gt; to create a new VM&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_-pOGRs8-Xu0/SvF7askv-II/AAAAAAAAACg/R7cQpXTm7oo/s1600-h/CreateVirtualMachine.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_-pOGRs8-Xu0/SvF7askv-II/AAAAAAAAACg/R7cQpXTm7oo/s400/CreateVirtualMachine.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
2. For simplicity's sake, name it to match the VHD&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_-pOGRs8-Xu0/SvF80yjo-lI/AAAAAAAAACo/omnHKBQcePc/s1600-h/VMName.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_-pOGRs8-Xu0/SvF80yjo-lI/AAAAAAAAACo/omnHKBQcePc/s400/VMName.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;3. Leave the memory to its default setting of 512 MB&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_-pOGRs8-Xu0/SvF9OpKQmtI/AAAAAAAAACw/rp7KhT5dCxo/s1600-h/VMmemory.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/SvF9OpKQmtI/AAAAAAAAACw/rp7KhT5dCxo/s400/VMmemory.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
4. Associate the VHD with the VM and click &lt;b&gt;Create&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_-pOGRs8-Xu0/SvF93jdSmBI/AAAAAAAAAC4/X74w6l_ToOY/s1600-h/VMvhd.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_-pOGRs8-Xu0/SvF93jdSmBI/AAAAAAAAAC4/X74w6l_ToOY/s400/VMvhd.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;5. Select the VM (&lt;b&gt;IE 6 on XP SP3.vmcx&lt;/b&gt;) and click &lt;b&gt;Settings &lt;/b&gt;to mount the XP CD&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_iYDSZgG3iA0/SvGdGdGiAlI/AAAAAAAAAKs/eQ3plzPiX1w/s1600-h/xpcd.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_iYDSZgG3iA0/SvGdGdGiAlI/AAAAAAAAAKs/eQ3plzPiX1w/s400/xpcd.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;6. Launch the VM by clicking &lt;b&gt;Open &lt;/b&gt;and watch XP boot&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_-pOGRs8-Xu0/SvF_P4aXTLI/AAAAAAAAADA/h5OLxoXFfrg/s1600-h/OpenVirtualMachine.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/SvF_P4aXTLI/AAAAAAAAADA/h5OLxoXFfrg/s400/OpenVirtualMachine.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
7. By default a user &lt;b&gt;IETest&lt;/b&gt; with Administrator privileges gets created. &lt;b&gt;Assign it a password&lt;/b&gt; (Start -&amp;gt; Control Panel -&amp;gt; User Accounts -&amp;gt; IETest -&amp;gt; Create a password) Pick &lt;b&gt;IETest &lt;/b&gt;again to keep it simple.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_iYDSZgG3iA0/SvGho9OM5LI/AAAAAAAAAK0/9c-3klZdet4/s1600-h/createpassword.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_iYDSZgG3iA0/SvGho9OM5LI/AAAAAAAAAK0/9c-3klZdet4/s400/createpassword.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
8. &lt;b&gt;Update the integration components&lt;/b&gt;, and let the installer reboot the VM when it needs to.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_-pOGRs8-Xu0/SvGAGRTprkI/AAAAAAAAADI/R_5fyNoWtAQ/s1600-h/upgradeIntegration.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/SvGAGRTprkI/AAAAAAAAADI/R_5fyNoWtAQ/s400/upgradeIntegration.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
9. Make sure that at the end of the installation, the checkbox "&lt;b&gt;Download updates required for running virtual applications from your PC&lt;/b&gt;" is checked before clicking Finish.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_iYDSZgG3iA0/SvGjlORcJ2I/AAAAAAAAAK8/OFnSfam2lZk/s1600-h/downloadcheckbox.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_iYDSZgG3iA0/SvGjlORcJ2I/AAAAAAAAAK8/OFnSfam2lZk/s400/downloadcheckbox.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;10. Download and run the &lt;b&gt;RemoteApp &lt;/b&gt;installer. The VM will restart at the end after you click Finish.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_iYDSZgG3iA0/SvGkIQ0Q-eI/AAAAAAAAALE/_LbskjIVq3A/s1600-h/remoteapp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_iYDSZgG3iA0/SvGkIQ0Q-eI/AAAAAAAAALE/_LbskjIVq3A/s400/remoteapp.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&amp;nbsp;11. Log in and click &lt;b&gt;Enable Integration features&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_iYDSZgG3iA0/SvGlAH7ejpI/AAAAAAAAALM/NYa5o8nwTb0/s1600-h/enablefeatures.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_iYDSZgG3iA0/SvGlAH7ejpI/AAAAAAAAALM/NYa5o8nwTb0/s400/enablefeatures.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
12. When prompted for credentials, click "&lt;b&gt;Use another account&lt;/b&gt;" and enter &lt;b&gt;IETest/IETest&lt;/b&gt; and don't forget to &lt;b&gt;tick the checkbox&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_iYDSZgG3iA0/SvGlv4tsDaI/AAAAAAAAALU/jPSNShaFr0M/s1600-h/credentials.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_iYDSZgG3iA0/SvGlv4tsDaI/AAAAAAAAALU/jPSNShaFr0M/s400/credentials.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
13. Right click Start and select "&lt;b&gt;Open all users&lt;/b&gt;", go into &lt;b&gt;Programs &lt;/b&gt;and drag the IE icon from the desktop into this folder.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_iYDSZgG3iA0/SvGm5k3rWvI/AAAAAAAAALc/OZONKg8eLBs/s1600-h/ieinxp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_iYDSZgG3iA0/SvGm5k3rWvI/AAAAAAAAALc/OZONKg8eLBs/s400/ieinxp.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;14. If you now go back to the Windows 7 Start menu, you will magically find the IE icon again under&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;b&gt;All Programs -&amp;gt; Windows Virtual PC -&amp;gt; IE 6 on XP SP3 Applications&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_iYDSZgG3iA0/SvGnxY9Mo0I/AAAAAAAAALk/FA7OYly7IrQ/s1600-h/ieon7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_iYDSZgG3iA0/SvGnxY9Mo0I/AAAAAAAAALk/FA7OYly7IrQ/s400/ieon7.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
15. Repeat for IE 7 :-)&lt;br /&gt;
&lt;br /&gt;
16. (optional) Pin the icons to the taskbar next to the IE 8 icon, so that they are just only click away.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_iYDSZgG3iA0/SvGooXJXASI/AAAAAAAAALs/L--1qeW88eY/s1600-h/pin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_iYDSZgG3iA0/SvGooXJXASI/AAAAAAAAALs/L--1qeW88eY/s400/pin.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
And finally there you have it, &lt;b&gt;IE 6, IE 7 and IE 8 all running at the same time on Windows 7&lt;/b&gt;:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_iYDSZgG3iA0/SvGaeK5qRXI/AAAAAAAAAKk/lAkxUY-8IvM/s1600-h/ie678.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_iYDSZgG3iA0/SvGaeK5qRXI/AAAAAAAAAKk/lAkxUY-8IvM/s640/ie678.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
Hope you enjoyed it and that it improved your life as much as mine when it comes to testing in different browsers !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-5915220059685944431?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/WQOVO7p2FZg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/5915220059685944431/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2009/11/running-ie-6-7-and-8-simultaneously-on.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/5915220059685944431?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/5915220059685944431?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/WQOVO7p2FZg/running-ie-6-7-and-8-simultaneously-on.html" title="Browser testing on steroids: Running IE 6, 7 and 8 simultaneously on Windows 7" /><author><name>Axel Fontaine</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/TRpSbvk7ZvI/AAAAAAAAAFQ/9iUViVJCNnw/S220/photo.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_-pOGRs8-Xu0/SvF7askv-II/AAAAAAAAACg/R7cQpXTm7oo/s72-c/CreateVirtualMachine.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.axelfontaine.com/2009/11/running-ie-6-7-and-8-simultaneously-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8HSH8_fCp7ImA9WxNQEEk.&quot;"><id>tag:blogger.com,1999:blog-40756891089949856.post-6111223286884506900</id><published>2009-09-03T18:26:00.013+02:00</published><updated>2009-09-15T21:27:19.144+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-15T21:27:19.144+02:00</app:edited><title>Transparently supporting HTTP HEAD requests in Java and Spring MVC</title><content type="html">The http 1.1 specification (RFC 2616) defines a number of &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html"&gt;methods&lt;/a&gt;: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE and CONNECT.&lt;br /&gt;
&lt;br /&gt;
Of these, the most familiar are &lt;b&gt;GET&lt;/b&gt; and &lt;b&gt;POST&lt;/b&gt;.&lt;br /&gt;
Web browsers rely on these two methods to send and receive data from web servers. (In compliance with the &lt;a href="http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.1"&gt;W3C Html 4 recommendation&lt;/a&gt;) &lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3"&gt;&lt;b&gt;GET&lt;/b&gt;&lt;/a&gt; is meant for &lt;b&gt;retrieving content&lt;/b&gt; from a web server. The requests should be &lt;b&gt;idempotent&lt;/b&gt;. No critical state should change. Successive requests should return the same content. (This makes them ideal candidates for caching!)&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5"&gt;&lt;b&gt;POST&lt;/b&gt;&lt;/a&gt; on the other hand is typically used for operations that &lt;b&gt;manipulate content&lt;/b&gt; on the server, such as adding, editing or removing content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;&lt;i&gt;So, what about the other methods, you might ask?&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Well it turns out browsers are not the only clients talking to our web servers. The web of 2009 has two more essential infrastructure components that our servers frequently have to deal with: &lt;b&gt;proxy servers&lt;/b&gt; and &lt;b&gt;web crawlers&lt;/b&gt;.&lt;br /&gt;
And it turns out these two types of clients are very fond of a third http method: &lt;b&gt;HEAD&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4"&gt;&lt;b&gt;HEAD&lt;/b&gt;&lt;/a&gt; is identical to GET except that only the http headers are returned. The body is discarded. This is primarily used for checking the validity of URLs. The load on the server will most likely remain the same as the content-length header must be returned (and thus potentially calculated based on the generated response body). Only the bandwidth is saved.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;&lt;i&gt;How do Java servlets deal with this?&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Not too bad it turns out ! Deep inside the HttpServlet class (part of the Servlet API 2.5), we find the following code:&lt;br /&gt;
&lt;pre class="brush: java"&gt;protected void doHead(HttpServletRequest req, HttpServletResponse resp)
 throws ServletException, IOException {
    NoBodyResponse response = new NoBodyResponse(resp);
 
    doGet(req, response);
    response.setContentLength();
}
&lt;/pre&gt;&lt;br /&gt;
Here is what  the &lt;b&gt;NoBodyResponse&lt;/b&gt; wrapper does (from the source code documentation):&lt;br /&gt;
&lt;blockquote&gt;A response that includes no body, for use in (dumb) "HEAD" support.&lt;br /&gt;
This just swallows that body, counting the bytes in order to set the content length appropriately. All other methods delegate directly to the HttpServletResponse object used to construct this one.&lt;/blockquote&gt;&lt;br /&gt;
So this means the standard way of the servlet api to deal with with HEAD requests consists of:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Wrapping the response using the NoBodyResponse in order to suppress the body, but preserve the headers.&lt;/li&gt;
&lt;li&gt;Execute the GET functionnality of the application (with the wrapped response object)&lt;/li&gt;
&lt;li&gt;Set the content-length header of the response&lt;/li&gt;
&lt;li&gt;Return the response headers to the client (without the body)&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
Sounds exactly like what we need, so where is the problem?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Comes in Spring MVC...&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
A typical Spring MVC 2.5 controller looks like this (from the Spring 2.5.6 reference documentation):&lt;br /&gt;
&lt;pre class="brush: java"&gt;@Controller
@RequestMapping("/editPet.do")
@SessionAttributes("pet")
public class EditPetForm {
    private final Clinic clinic;

    @Autowired
    public EditPetForm(Clinic clinic) {
        this.clinic = clinic;
    }

    @ModelAttribute("types")
    public Collection&amp;lt;pettype&amp;gt; populatePetTypes() {
        return this.clinic.getPetTypes();
    }

    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String processSubmit(
            @ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {

        new PetValidator().validate(pet, result);
        if (result.hasErrors()) {
            return "petForm";
        }
        else {
            this.clinic.storePet(pet);
            status.setComplete();
            return "redirect:owner.do?ownerId=" + pet.getOwner().getId();
        }
    }
}&lt;/pre&gt;&lt;br /&gt;
The editPetForm controller will respond to the /editPet.do URL.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;GET /editPet.do&lt;/b&gt; executes the &lt;b&gt;setupForm&lt;/b&gt; method.&lt;br /&gt;
&lt;b&gt;POST /editPet.do&lt;/b&gt; executes the &lt;b&gt;processSubmit&lt;/b&gt; method.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;i&gt;But what about HEAD /editPet.do?&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="color: red;"&gt;It generates an error!&lt;/span&gt;&lt;/b&gt; Spring MVC cannot find a method annotated with&lt;br /&gt;
&lt;pre class="brush: java"&gt;@RequestMapping(method = RequestMethod.HEAD)&lt;/pre&gt;and throws an exception.&lt;br /&gt;
&lt;br /&gt;
There are two solutions to this problem.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;Solution #1&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;Add the missing RequestMapping annotation to all controllers handling GET requests.&lt;/b&gt; This solves the problem, but not without significant &lt;b&gt;drawbacks&lt;/b&gt;:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;It is verbose (this annotation must be added to all relevant controllers)&lt;/li&gt;
&lt;li&gt;It is tedious (every controller must be reviewed)&lt;/li&gt;
&lt;li&gt;It is error-prone (the burden lies on the developer not to forget this)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
But luckily there is an alternative...&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;Solution #2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;b&gt;Add a servlet filter (in web.xml) in front of the Spring MVC servlet to lie about the http method and present all HEAD requests as GET.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Here is the code:&lt;br /&gt;
&lt;pre class="brush: java"&gt;//Imports and documentation have been omitted...

public class HttpHeadFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;

        if (isHttpHead(httpServletRequest)) {
            chain.doFilter(new ForceGetRequestWrapper(httpServletRequest), response);
        } else {
            chain.doFilter(request, response);
        }
    }

    public void destroy() {
    }

    private boolean isHttpHead(HttpServletRequest request) {
        return "HEAD".equals(request.getMethod());
    }

    private class ForceGetRequestWrapper extends HttpServletRequestWrapper {
        public ForceGetRequestWrapper(HttpServletRequest request) {
            super(request);
        }

        public String getMethod() {
            return "GET";
        }
    }
}
&lt;/pre&gt;&lt;br /&gt;
With this filter, our previous example would work as follows:&lt;br /&gt;
&lt;br /&gt;
The HEAD request will be seen as a GET by Spring MVC and therefore&lt;b&gt; HEAD /editPet.do&lt;/b&gt; executes the &lt;b&gt;setupForm&lt;/b&gt; method without the need for the extra annotation!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;&lt;i&gt;But what about the response?&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The Spring MVC DispatcherServlet&lt;b&gt; overrides the doService method&lt;/b&gt; from HttpServlet. This means that the nice NoBodyResponse logic is overridden, and thus never called.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are once again two solutions to this problem:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;Solution #1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;b&gt;Rely on your web container &lt;/b&gt;to suppress the response body for HEAD requests. Some containers, like Apache Tomcat, provide this functionality out of the box. Relying on container-specific behavior will increase your dependency on this particular server. This may or may not be a &lt;b&gt;problem&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;Solution #2&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;Integrate the NoBodyResponse&lt;/b&gt; wrapper with the HttpHeadFilter.&lt;br /&gt;
&lt;br /&gt;
This is how the final solution looks like:&lt;br /&gt;
&lt;pre class="brush: java"&gt;//Imports and documentation have been omitted...

public class HttpHeadFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;

        if (isHttpHead(httpServletRequest)) {
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            NoBodyResponseWrapper noBodyResponseWrapper = new NoBodyResponseWrapper(httpServletResponse);

            chain.doFilter(new ForceGetRequestWrapper(httpServletRequest), noBodyResponseWrapper);
            noBodyResponseWrapper.setContentLength();
        } else {
            chain.doFilter(request, response);
        }
    }

    public void destroy() {
    }

    private boolean isHttpHead(HttpServletRequest request) {
        return "HEAD".equals(request.getMethod());
    }

    private class ForceGetRequestWrapper extends HttpServletRequestWrapper {
        public ForceGetRequestWrapper(HttpServletRequest request) {
            super(request);
        }

        public String getMethod() {
            return "GET";
        }
    }

    private class NoBodyResponseWrapper extends HttpServletResponseWrapper {
        private final NoBodyOutputStream noBodyOutputStream = new NoBodyOutputStream();
        private PrintWriter writer;

        public NoBodyResponseWrapper(HttpServletResponse response) {
            super(response);
        }

        public ServletOutputStream getOutputStream() throws IOException {
            return noBodyOutputStream;
        }

        public PrintWriter getWriter() throws UnsupportedEncodingException {
            if (writer == null) {
                writer = new PrintWriter(new OutputStreamWriter(noBodyOutputStream, getCharacterEncoding()));
            }

            return writer;
        }

        void setContentLength() {
            super.setContentLength(noBodyOutputStream.getContentLength());
        }
    }

    private class NoBodyOutputStream extends ServletOutputStream {
        private int contentLength = 0;

        int getContentLength() {
            return contentLength;
        }

        public void write(int b) {
            contentLength++;
        }

        public void write(byte buf[], int offset, int len) throws IOException {
            contentLength += len;
        }
    }
}
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;&lt;i&gt;Conclusion&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
We now have a &lt;b&gt;drop-in solution&lt;/b&gt;, compatible with any web framework and any container. It allows us to &lt;b&gt;transparently support http HEAD&lt;/b&gt; requests in our applications and finally treat web crawlers and proxy servers as first class citizens.&lt;br /&gt;
&lt;br /&gt;
The source code for &lt;b&gt;HttpHeadFilter&lt;/b&gt; is available &lt;a href="http://www.axelfontaine.eu/blog/files/HttpHeadFilter.java"&gt;here&lt;/a&gt;. Feel free to use it as you wish.&lt;br /&gt;
&lt;br /&gt;
Feedback is always welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/40756891089949856-6111223286884506900?l=www.axelfontaine.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/axelfontaine/~4/fdAX5tc3Ib8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.axelfontaine.com/feeds/6111223286884506900/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.axelfontaine.com/2009/09/transparently-supporting-http-head.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/6111223286884506900?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/40756891089949856/posts/default/6111223286884506900?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/axelfontaine/~3/fdAX5tc3Ib8/transparently-supporting-http-head.html" title="Transparently supporting HTTP HEAD requests in Java and Spring MVC" /><author><name>Axel Fontaine</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://2.bp.blogspot.com/_-pOGRs8-Xu0/TRpSbvk7ZvI/AAAAAAAAAFQ/9iUViVJCNnw/S220/photo.png" /></author><thr:total>2</thr:total><feedburner:origLink>http://www.axelfontaine.com/2009/09/transparently-supporting-http-head.html</feedburner:origLink></entry></feed>

