<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Redfin Developers\' Blog &#187; Dan Fabulich</title>
	<atom:link href="http://blog.redfin.com/devblog/author/danfabulich/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.redfin.com/devblog</link>
	<description>Redfin Developers\' Blog</description>
	<lastBuildDate>Mon, 16 Nov 2009 20:22:30 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>How to Set Up Hot Code Replacement with Tomcat and Eclipse</title>
		<link>http://blog.redfin.com/devblog/2009/09/how_to_set_up_hot_code_replacement_with_tomcat_and_eclipse.html</link>
		<comments>http://blog.redfin.com/devblog/2009/09/how_to_set_up_hot_code_replacement_with_tomcat_and_eclipse.html#comments</comments>
		<pubDate>Wed, 30 Sep 2009 19:28:32 +0000</pubDate>
		<dc:creator>Dan Fabulich</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/?p=170</guid>
		<description><![CDATA[This blog post will guide you through setting up Tomcat hot code replacement (also called hotswap debugging) in Eclipse.

What Is &#8220;Hot Code Replace&#8221;?
What&#8217;s the Catch?
What About JavaRebel?
Configuring Your Web Application in Eclipse

Download Eclipse &#8220;JEE&#8221; Edition
Switch to the &#8220;Java EE&#8221; Perspective
Configure Your WAR Project
Create a New Server
Magic Setting: Disable &#8220;Auto Reloading&#8221; on Each Project in the [...]]]></description>
			<content:encoded><![CDATA[<p>This blog post will guide you through setting up Tomcat hot code replacement (also called hotswap debugging) in Eclipse.</p>
<ul>
<li>What Is &#8220;Hot Code Replace&#8221;?</li>
<li>What&#8217;s the Catch?</li>
<li>What About JavaRebel?</li>
<li>Configuring Your Web Application in Eclipse
<ol>
<li>Download Eclipse &#8220;JEE&#8221; Edition</li>
<li>Switch to the &#8220;Java EE&#8221; Perspective</li>
<li>Configure Your WAR Project</li>
<li>Create a New Server</li>
<li>Magic Setting: Disable &#8220;Auto Reloading&#8221; on Each Project in the Server</li>
<li>Performance Tip: Adjust Memory Settings</li>
<li>Start Your Tomcat Server in Debug Mode</li>
</ol>
</li>
<li>Why Disable Auto Reloading?</li>
<li>Disable Auto Reloading but <em>Enable</em> Auto Publishing</li>
<li>Finding the <kbd>tmp0</kbd> Fake Tomcat Directory</li>
<li>Exorcising the <kbd>tmp0</kbd> Directory</li>
<li>Troubleshooting: What Do I Do If I Still Can&#8217;t Get It to Work?</li>
</ul>
<h2>What Is &#8220;Hot Code Replace&#8221;?</h2>
<p>&#8220;<a href="http://wiki.eclipse.org/FAQ_What_is_hot_code_replace%3F">Hot Code Replace</a>&#8221; (HCR) lets you make modifications to a Java class and see the effect immediately in a running JVM, without restarting your application.  HCR is part of the Java Platform Debugger Architecture (JPDA) and is available on all modern JVMs.</p>
<p>Consider this ordinary application:</p>
<p><code>
<pre>public class Sample {
  public static void main(String[] args) {
    String foo = "unchangeable";
    foo += blah();
    System.out.println(foo);
  }

  public static String blah() {
    String bar = "bar";
    bar += "blah";
    return bar;
  }

}</pre>
<p></code></p>
<p>If you debug this class in Eclipse, you can make changes to it, on the fly, without restarting the JVM.  For example, try setting a breakpoint on the second line of <code>blah()</code>. Next, change the literal <code>blah</code> to <code>quz</code>.  Save the file and the program will continue running with the new code.</p>
<p>You can do this with Tomcat web applications in Eclipse, but it&#8217;s a lot trickier.</p>
<h2><a name="catch"></a>What&#8217;s the Catch?</h2>
<p>There are a few limitations when using hot code replace.  You can&#8217;t use JPDA HCR to change the signature of a class (add/remove methods or fields) or to add new classes on the fly.  Additionally, some method calls (&#8221;stack frames&#8221;) can&#8217;t be modified, including the <code>main</code> method or any method invoked via reflection, that is, by using <kbd>java.lang.reflect.Method.invoke()</kbd>.</p>
<p>Here&#8217;s what happens if you try to replace the <code>unchangeable</code> variable in the main method of <kbd>Sample.java</kbd> above.</p>
<p><img src="http://blog.redfin.com/devblog/files/2009/09/unchangeable-300x115.png" alt="unchangeable 300x115 How to Set Up Hot Code Replacement with Tomcat and Eclipse" width="300" height="115" class="alignnone size-medium wp-image-180" title="How to Set Up Hot Code Replacement with Tomcat and Eclipse" /></p>
<h2>What About JavaRebel?</h2>
<p><a href="http://www.zeroturnaround.com/javarebel/">JavaRebel</a> is a hot code replacement system that&#8217;s a little better than JPDA HCR.  (<a href="http://www.zeroturnaround.com/jrebel/comparison/">Maybe a lot better</a>.)</p>
<p>With JavaRebel you can add/remove methods and classes without restarting Tomcat.  However, JavaRebel costs $149 per developer per year, so it may or may not be worthwhile for you.</p>
<h2>Configuring Your Web Application in Eclipse</h2>
<ol>
<li>Download Eclipse &#8220;JEE&#8221; edition</p>
<p>Most developers already use this, since it&#8217;s the first option available on the <a href="http://www.eclipse.org/downloads/">Eclipse download page</a>, but if you&#8217;re using &#8220;Eclipse IDE for Java Developers&#8221; (92MB), you&#8217;ll need to go back and download &#8220;Eclipse IDE for Jave EE Developers&#8221; (189MB).  It&#8217;s worth it, I promise!</p>
<p><img src="http://blog.redfin.com/devblog/files/2009/09/download-screenshot-300x188.png" alt="download screenshot 300x188 How to Set Up Hot Code Replacement with Tomcat and Eclipse" width="300" height="188" class="alignnone size-medium wp-image-175" title="How to Set Up Hot Code Replacement with Tomcat and Eclipse" /></p>
<p>Note: The difference between the regular Java IDE and the Java EE IDE is that the JEE edition comes with the Eclipse &#8220;Web Tools Project&#8221; (WTP), which includes &#8220;Web Server Tools&#8221; (WST).  The terms are sometimes used interchangeably; keep an eye out for this if you need to search for them.</p>
</li>
<li>Switch to the &#8220;Java EE&#8221; Perspective
<p>Make sure you&#8217;re in the &#8220;Java EE&#8221; perspective, not the &#8220;Java&#8221; perspective.  If it&#8217;s not in the upper-right corner of your Eclipse window, you might need to enable it manually (Window menu -&gt; Open Perspective -&gt; Other&#8230;).  If &#8220;Java EE&#8221; doesn&#8217;t appear on this list, you&#8217;ve probably downloaded the wrong package of Eclipse; go back and download the Java EE version.</p>
<p><img src="http://blog.redfin.com/devblog/files/2009/09/jee-screenshot.png" alt="jee screenshot How to Set Up Hot Code Replacement with Tomcat and Eclipse" width="253" height="141" class="alignnone size-full wp-image-176" title="How to Set Up Hot Code Replacement with Tomcat and Eclipse" /></p>
</li>
<li>Configure Your WAR Project
<p>From scratch: From the New menu, select &#8220;Dynamic Web Project&#8221;.  Configure your source and output folders, as well as your &#8220;Content directory&#8221;, which will contain your JSPs, your WEB-INF directory, etc.</p>
<p>Via Maven: Use <a href="http://maven.apache.org/">Maven</a> to create a WAR project.  For example:</p>
<p><kbd>mvn archetype:create -DarchetypeArtifactId=maven-archetype-webapp -DartifactId=YOURNAMEHERE -DgroupId=YOURNAMEHERE</kbd></p>
<p>Modify your <kbd>pom.xml</kbd> to include an explicit reference to <code>maven-eclipse-plugin</code>, like this:</p>
<p><code>
<pre>
&lt;!-- ... --&gt;
&lt;build&gt;
    &lt;!-- ... --&gt;
    &lt;plugins&gt;
        &lt;!-- ... --&gt;
        &lt;plugin&gt;
            &lt;artifactId&gt;maven-eclipse-plugin&lt;/artifactId&gt;
            &lt;configuration&gt;
                &lt;wtpversion&gt;2.0&lt;/wtpversion&gt;
            &lt;/configuration&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;
&lt;!-- ... --&gt;
</pre>
<p></code></p>
<p>Now generate an Eclipse project from the command line, like this:</p>
<p><kbd>mvn eclipse:eclipse</kbd></p>
<p>Here&#8217;s an <a href="http://blog.redfin.com/devblog/files/2009/09/hotswaptest.zip">example Maven project</a> you can use.  Just download it, extract it, and run <code>mvn eclipse:eclipse</code> to generate your Eclipse project.  (If this is your first time using Maven with Eclipse, you&#8217;ll also need to add an <kbd>M2_REPO</kbd> classpath variable in your Eclipse workspace preferences that points to your Maven repository, typically <kbd>$HOME/.m2/repository</kbd> or <kbd>%USERPROFILE%\.m2\repository</kbd>.)</p>
</li>
<li>Create a New Server
<p>From the New menu, select Other&#8230; -&gt; Server -&gt; Server.  For your server type, expand the &#8220;Apache&#8221; folder and select the version of Tomcat you intend to use.  Choose &#8220;Next&#8221; and then specify the path to your Tomcat installation directory, e.g. <kbd>c:\tools\tomcat-6.0</kbd>.  Add your web project as a &#8220;resource&#8221; to this server.</p>
</li>
<li><a name="magic-setting"></a>Magic Setting: Disable &#8220;Auto Reloading&#8221; on Each Project in the Server
<p>You now have a weird pseudo-project called &#8220;Servers&#8221; in your Project Explorer.  In the explorer, your server looks like a folder called something like &#8220;Tomcat v6.0 Server at localhost-config&#8221; &#8230;but that&#8217;s not what you want.  You need to interact with your server using the &#8220;Servers&#8221; tab.  (Eclipse calls these tabs &#8220;Views,&#8221; but everybody else just calls them &#8220;tabs.&#8221;)</p>
<p>The &#8220;Servers&#8221; tab should be exposed by default, but in case it isn&#8217;t, you can expose it via Window -&gt; Show View -&gt; Servers.  From there you can double-click on your server to configure it.</p>
<p>Note that the configuration panel for your server has two tabs, &#8220;Overview&#8221; and &#8220;Modules&#8221;, down at the bottom of the window.  Click on the &#8220;Modules&#8221; tab to bring up the list of projects associated with the server.</p>
<p>Select your project in the list and click on &#8220;Edit&#8221;. You&#8217;ll see the magic secret checkbox: &#8220;Auto reloading enabled&#8221;.  It&#8217;s checked by default.  For the love of Pete, uncheck it!</p>
<p>(It&#8217;s interesting to note that <a href="http://www.zeroturnaround.com/news/javarebel-and-wtp-configuration/">JavaRebel also requires disabling auto reloading</a> to work properly in Eclipse.)</p>
<p><img src="http://blog.redfin.com/devblog/files/2009/09/magic-checkbox-screenshot-300x216.png" alt="magic checkbox screenshot 300x216 How to Set Up Hot Code Replacement with Tomcat and Eclipse" width="300" height="216" class="alignnone size-medium wp-image-177" title="How to Set Up Hot Code Replacement with Tomcat and Eclipse" /></p>
</li>
<li><a name="memory"></a>Performance Tip: Adjust Memory Settings
<p>Before you start up your server, I strongly recommend adjusting your server&#8217;s <kbd>-Xmx</kbd> memory settings; otherwise, it will constrain itself to the default value, 64 MB, which is just not enough!</p>
<p>Double-click on your server in the &#8220;Servers&#8221; tab and switch to the &#8220;Overview&#8221; tab.  Click on the &#8220;Open launch configuration&#8221; link.  Switch to the Arguments tab; there you can add relevant memory settings to the &#8220;VM Arguments&#8221; section.  For example, you might add <kbd>-Xmx512m</kbd> to the end of the existing arguments.</p>
<p><img src="http://blog.redfin.com/devblog/files/2009/09/memory-screenshot-300x273.png" alt="memory screenshot 300x273 How to Set Up Hot Code Replacement with Tomcat and Eclipse" width="300" height="273" class="alignnone size-medium wp-image-178" title="How to Set Up Hot Code Replacement with Tomcat and Eclipse" /></p>
<li>Start Your Tomcat Server in Debug Mode
<p>Now you can right-click on the Server in your Servers tab and choose &#8220;Debug&#8221;.  Changes you make to your JSPs or Java classes will be instantly hotswapped into your running WAR.</p>
</li>
</ol>
<h2>Why Disable Auto Reloading?</h2>
<p>Auto reloading is a feature of Tomcat that allows you to replace Java classes at runtime without using JPDA.  In this mode, Tomcat uses Java classloaders to try to unload classes and reload them; whenever it reloads, it also tries to reinitialize your application, re-launching any servlets that are marked <code>load-on-startup</code> in your <kbd>web.xml</kbd> file.</p>
<p>As a result, Tomcat auto reloading may not save you any time at all if your webapp has a lot of startup code.  For example, if your load-on-startup code needs to warm up Hibernate database caches, Spring/Guice dependency injection configuration, etc., it may take almost as long to restart your webapp as it does to restart Tomcat.</p>
<p>Worse, an app that has been auto reloaded can behave strangely, and can quickly run out of PermGen memory due to frequent unloading/reloading of classes.  When this happens, restarting Tomcat typically fixes the problem.  If you spend even five minutes investigating a weird auto reloading problem, you&#8217;ve just wasted all the time you were hoping to save by avoiding a restart.  (Not to mention your stress and frustration!)</p>
<p>By disabling auto reloading and using JPDA hot code replace instead, you get a more reliable code replacement system.</p>
<h2><a name="auto-publish">Disable Auto Reloading but <em>Enable</em> Auto Publishing</a></h2>
<p>In the screenshot above you can see how to disable auto reloading on the &#8220;Modules&#8221; tab of the Tomcat server; auto reloading is bad for JPDA debugging.  But there&#8217;s another setting called &#8220;Automatically publish when resources change&#8221; on the &#8220;Overview&#8221; tab of the Tomcat server.  It&#8217;s hidden by default, collapsed under the &#8220;Publishing&#8221; section.  You can see it if you expand that section; you want to make sure auto publishing is enabled while auto reloading is disabled.</p>
<p><img src="http://blog.redfin.com/devblog/files/2009/09/autopublish-screenshot-300x205.png" alt="autopublish screenshot 300x205 How to Set Up Hot Code Replacement with Tomcat and Eclipse" width="300" height="205" class="alignnone size-medium wp-image-173" title="How to Set Up Hot Code Replacement with Tomcat and Eclipse" /></p>
<p>To understand the difference between auto publishing and auto reloading, we&#8217;ll have to go into how exactly Eclipse WTP works.  When you create a &#8220;Server&#8221; in Eclipse, the IDE creates a fake Tomcat directory, complete with the <kbd>conf</kbd>, <kbd>logs</kbd>, <kbd>temp</kbd>, <kbd>webapps</kbd> and <kbd>work</kbd> directories.  When you configured the server, you told Eclipse where to find Tomcat, but it doesn&#8217;t use any of your settings files or any data from your <kbd>webapps</kbd> directory.  Instead, Eclipse launches Tomcat with special command-line arguments, indicating where to find the fake Tomcat directory.</p>
<p>&#8220;Publishing&#8221; means to populate the fake Tomcat directory with all of your code.  It copies your JSPs, JARs up your Java, regenerates settings files, etc.</p>
<p>If you turn off auto publishing, then you have to right-click on your Server and &#8220;Publish&#8221; your changes manually every time you save your Java code.  Additionally, auto publishing allows Tomcat to reload JSPs automatically, regardless of whether you use JPDA or not.</p>
<p><img src="http://blog.redfin.com/devblog/files/2009/09/server-menu-screenshot-300x279.png" alt="server menu screenshot 300x279 How to Set Up Hot Code Replacement with Tomcat and Eclipse" width="300" height="279" class="alignnone size-medium wp-image-179" title="How to Set Up Hot Code Replacement with Tomcat and Eclipse" /></p>
<h2>Finding the <kbd>tmp0</kbd> Fake Tomcat Directory</h2>
<p>Sometimes it can be helpful to look inside the fake Tomcat directory and see what&#8217;s going on in there.  Eclipse tells you where it put the Tomcat directory in the &#8220;Server Locations&#8221; section of your &#8220;Tomcat&#8221; server configuration panel.  (Double-click on your Server in the &#8220;Servers&#8221; tab to open the configuration panel.)  Typically, Eclipse says that your server is in <kbd>.metadata/.plugins/org.eclipse.wst.server.core/tmp0</kbd>; for this reason I typically call it the <kbd>tmp0</kbd> directory (pronounced &#8220;tempo&#8221;).</p>
<p>The <kbd>.metadata</kbd> folder is inside your Eclipse workspace directory.  (You can find your Eclipse workspace directory by going to File -&gt; Switch Workspace; the default value is your current workspace directory.)  In the worst case, you can always just search your hard drive for <kbd>tmp0</kbd>.  It&#8217;s there somewhere!</p>
<p>Inside, you can see all the folders Eclipse has created.  Check out the generated <kbd>server.xml</kbd> file in <kbd>tmp0/conf</kbd>.  Examine generated <kbd>.java</kbd> files in <kbd>tmp0/work</kbd>.  Your <kbd>tmp0/webapps</kbd> directory is probably empty; Eclipse has probably generated your webapp in <kbd>wtpwebapps</kbd>.</p>
<h2><a name="exorcism">Exorcising the <kbd>tmp0</kbd> Directory</a></h2>
<p>Unfortunately, sometimes Eclipse gets a little confused about what to put in your WAR file, and you need to perform various stages of exorcism depending on how badly your <kbd>tmp0</kbd> directory is messed up.</p>
<ul>
<li>Try republishing your <kbd>tmp0</kbd> directory.  Open the &#8220;Servers&#8221; tab, right-click on your server and select &#8220;Clean&#8230;&#8221; (<em>not</em> &#8220;Clean Tomcat Work Directory&#8230;&#8221;).  Then select &#8220;Publish.&#8221;  That should completely rebuild your <kbd>tmp0</kbd> directory.</li>
<li>Try restarting Eclipse.  This works more often than I&#8217;d like to admit.</li>
<li>Try completely deleting and recreating your server.  Follow this ritual:
<ol>
<li>Open the &#8220;Servers&#8221; tab, right-click on the server and select &#8220;Delete&#8221;.</li>
<li>Make sure &#8220;Delete unused server configuration(s)&#8221; is checked, then click OK.</li>
<li>Look at your &#8220;Servers&#8221; pseudo-project; make sure the folder for your server is gone.  If it isn&#8217;t, right-click on it and Delete it.</li>
<li>Quit Eclipse.</li>
<li>Go find your <kbd>tmp0</kbd> directory (if it&#8217;s still present) and delete it from your file system.</li>
<li>Launch Eclipse and recreate your server from scratch.</li>
</ol>
</li>
<li>Try creating a new workspace.  File -&gt; Switch Workspaces: specify an empty directory.  Create your server from scratch.</li>
</ul>
<h2>Troubleshooting: What Do I Do If I Still Can&#8217;t Get It to Work?</h2>
<ul>
<li><a name="regular"></a>My project works in regular Tomcat, but doesn&#8217;t work in Tomcat under Eclipse
<p>Try using Eclipse to generate a WAR file for Tomcat.  Right-click on your web project and select Export -&gt; WAR file, and install it in Tomcat by dropping the exported WAR into your Tomcat <kbd>webapps</kbd> directory.</p>
<p>If the exported WAR file doesn&#8217;t work, then you now have two WARs: one working WAR generated by your build script, and one non-working WAR generated by Eclipse.  WAR files are just zips; extract them both, find the difference, and fix it!  Right-click on your web project and select &#8220;Properties&#8221;.  The problem is somewhere in here.</p>
<p>On the other hand, if the exported WAR file <em>does</em> work, then you know that the problem has to do with the way Eclipse is launching Tomcat.  Find your <kbd>tmp0</kbd> directory (described above) and poke around.  Does everything look OK in there?  Be sure to check your <kbd>server.xml</kbd> file, as well as your webapp itself in <kbd>wtpwebapps</kbd>.  Make sure to note your <kbd>WEB-INF/lib</kbd> directory, typically in <kbd>tmp0/wtpwebapps/YOURAPP/WEB-INF/lib</kbd>.</p>
</li>
<li>Tomcat is throwing <kbd>NoClassDefFoundError</kbd> or <kbd>ClassNotFoundException</kbd>
<p>First, double-check whether this problem happens in regular Tomcat.  See <a href="#regular">My project works in regular Tomcat, but doesn&#8217;t work in Tomcat under Eclipse</a> above.</p>
<p>If this problem occurs in the exported WAR file under regular Tomcat, then your webapp is probably missing JARs.  See <a href="#missing-jars">My exported WAR is missing JARs</a> below.</p>
<p>If the exported WAR works but your webapp is still broken under Tomcat, you may need to perform an exorcism.  (See <a href="#exorcism">Exorcising the <kbd>tmp0</kbd> Directory</a> above.) If this happens to you often, double-check that you haven&#8217;t accidentally disabled auto publishing.  (See <a href="#auto-publish">Disable Auto Reloading but <em>Enable</em> Auto Publishing</a> above.)</p>
</li>
<li><a name="missing-jars"></a>My exported WAR is missing JARs
<p>Right-click on your web project and select &#8220;Properties.&#8221;  The problem is somewhere in here.  Make sure you see your JAR listed under &#8220;Java Build Path&#8221; in the Properties dialog.</p>
<p>Beware: not every JAR in &#8220;Java Build Path&#8221; gets exported to the WAR.  The list of JARs for the WAR is under &#8220;Java EE Module Dependencies.&#8221;  If a JAR/project is unchecked on that list, it won&#8217;t appear in your WAR file.</p>
</li>
<li>My <kbd>tmp0</kbd> directory is missing an important configuration file
<p>Eclipse will publish files that it finds in the &#8220;Tomcat&#8221; folder of the &#8220;Servers&#8221; pseudo-project to your <kbd>tmp0/conf</kbd> directory; if you&#8217;re missing files, you can add them here.</p>
</li>
<li>My <kbd>server.xml</kbd> file is messed up
<p>That file is copied from the &#8220;Tomcat&#8221; folder in your &#8220;Servers&#8221; pseudo-project to your <kbd>tmp0/conf</kbd> directory.  But note that the <kbd>server.xml</kbd> file is at least partially autogenerated by Eclipse.  If you make direct changes to the file, Eclipse will do its best to try to incorporate your changes, but it often gets confused and does the wrong thing.  When possible, it&#8217;s better to find the appropriate Eclipse settings and change them there instead of modifying the <kbd>server.xml</kbd> file directly.</p>
<p>Note that one of the most common problems with <kbd>server.xml</kbd> is an incorrect <code>path</code> attribute on your webapp&#8217;s <code>&lt;Context&gt;</code> element, causing your webapp to appear on a non-standard URL.  See the following question about 404 errors for more details about this problem.</p>
</li>
<li>Tomcat is giving me strange 404 errors
<p>First, double-check whether this problem happens in regular Tomcat.  (See <a href="#regular">My project works in regular Tomcat, but doesn&#8217;t work in Tomcat under Eclipse</a>)  If it happens in regular Tomcat too, then it&#8217;s probably a bug in your code.</p>
<p>If the problem only happens in Eclipse, then it&#8217;s probably a <kbd>server.xml</kbd> configuration problem.  Check your <kbd>tmp0/conf/server.xml</kbd> file&#8217;s <code>&lt;Context&gt;</code> element; check the <code>path</code> attribute.  The <code>path</code> attribute indicates the virtual directory of your webapp.  For example, if your <kbd>Context/path</kbd> is &#8220;examplePath&#8221;, then your webapp will appear at <kbd>http://localhost:8080/examplePath</kbd>.  If it&#8217;s misconfigured, your webapp may not be available at the URL you expect.</p>
<p>The <kbd>path</kbd> attribute is auto-generated based on settings in the properties of your WAR project.  Right-click on your web project, select &#8220;Properties&#8221; and go to the &#8220;Web Project Settings&#8221; section.  There&#8217;s only one setting here; it&#8217;s called &#8220;Context root&#8221;.  Specify the context you intend to use here.  If you want your project to appear in the root directory, you&#8217;ll need to put <kbd>/</kbd> as your context root (since you aren&#8217;t allowed to leave it blank).</p>
<p><img src="http://blog.redfin.com/devblog/files/2009/09/context-root-screenshot-300x272.png" alt="context root screenshot 300x272 How to Set Up Hot Code Replacement with Tomcat and Eclipse" width="300" height="272" class="alignnone size-medium wp-image-174" title="How to Set Up Hot Code Replacement with Tomcat and Eclipse" /></p>
</li>
<li>Tomcat times out when starting under Eclipse (&#8221;Server [...] was unable to start within 45 seconds&#8221;)
<p>The Eclipse developers, in their infinite wisdom, have added a timeout to Tomcat startup.  If Tomcat doesn&#8217;t declare a successful startup in 45 seconds, it kills Tomcat automatically.  (Gee, thanks, guys!)</p>
<p>You can increase that timeout.  Open the &#8220;Servers&#8221; tab and double-clicking on your server to open the server configuration panel.  Make sure the panel&#8217;s &#8220;Overview&#8221; tab is selected.  Expand the &#8220;Timeouts&#8221; section and increase the Start timeout to something reasonable for your server.</p>
</li>
<li>I had Tomcat working under Eclipse, but now it&#8217;s broken and I can&#8217;t figure out why
<p>You may need to perform an exorcism.  (See <a href="#exorcism">Exorcising the <kbd>tmp0</kbd> Directory</a> above.)</p>
</li>
<li>My web project starts up fine, but when I save <kbd>.java</kbd> files in Eclipse, it doesn&#8217;t take effect until I restart
<ul>
<li>Did you make sure to launch the server in Debug mode, as opposed to Run mode?  JPDA only works when you Debug the server.</li>
<li>Is your server configured to auto publish?  (See <a href="#auto-publish">Disable auto reloading but <em>Enable</em> auto publishing</a> above.)</li>
<li>Did you change something that broke JPDA?  (See <a href="#catch">What&#8217;s the catch?</a> above.)  If you make large changes to your classes, JPDA may be unable to replace the code; if you choose to &#8220;Continue&#8221; past that point, further changes will have no effect.</li>
</li>
</ul>
<li>My web project starts up fine, but when I save <kbd>.jsp</kbd> files in Eclipse, it doesn&#8217;t take effect until I restart
<p>This is typically due to disabled auto publishing.  Double-check that your server is configured to auto publish.  (See <a href="#auto-publish">Disable auto reloading but <em>Enable</em> auto publishing</a> above.)</p>
<p>If that doesn&#8217;t work, examine your <kbd>tmp0</kbd> directory to make sure Tomcat is using the correct JSP.  It should automatically begin consuming new JSPs as they are installed in the <kbd>tmp0/wtpwebapps</kbd> directory.</p>
</li>
<li>Whenever I save a <kbd>.java</kbd> file in Eclipse, Tomcat restarts
<p>This is typically due to Tomcat auto reloading.  Double-check that you correctly disabled auto reloading.  (See <a href="#magic-setting">Magic Setting</a> above.)</p>
</li>
<li>Tomcat in Eclipse is <i>much</i> slower than regular Tomcat
<p>Try increasing your <a href="#memory">memory settings</a> as described above, if you haven&#8217;t already.</p>
<p>Try running Tomcat in &#8220;Run&#8221; mode (as opposed to &#8220;Debug&#8221;) mode.  If that fixes the problem, then there may be nothing you can do about it.  JPDA does have some overhead; you can turn it off, but while you&#8217;ve turned it off you won&#8217;t have access to hot code replacement.</p>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2009/09/how_to_set_up_hot_code_replacement_with_tomcat_and_eclipse.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Installing Beta Builds on iPhone</title>
		<link>http://blog.redfin.com/devblog/2009/09/installing_beta_builds_on_iphone.html</link>
		<comments>http://blog.redfin.com/devblog/2009/09/installing_beta_builds_on_iphone.html#comments</comments>
		<pubDate>Wed, 30 Sep 2009 01:16:02 +0000</pubDate>
		<dc:creator>Dan Fabulich</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/?p=146</guid>
		<description><![CDATA[Probably the hardest part of learning to code an iPhone app is figuring out how to get your app installed on a phone.  Even after you&#8217;ve installed your app on your personal development phone, installing it on other people&#8217;s phones for beta testing is especially tricky.
Here&#8217;s the rough outline:

Create an &#8220;Ad Hoc&#8221; Provisioning Profile [...]]]></description>
			<content:encoded><![CDATA[<p>Probably the hardest part of learning to code an iPhone app is figuring out how to get your app installed on a phone.  Even after you&#8217;ve installed your app on your personal development phone, installing it on other people&#8217;s phones for beta testing is especially tricky.</p>
<p>Here&#8217;s the rough outline:</p>
<ol>
<li>Create an &#8220;Ad Hoc&#8221; Provisioning Profile (a <kbd>.mobileprovision</kbd> file) for beta testing.
<li>Find yourself a friendly beta tester.</li>
<li>Each beta tester needs to give you the Universal Device Identifier (UDID) of his/her device.  (This number is not easily visible to users.)</li>
<li>Submit the UDID as a named &#8220;Device&#8221; to Apple.</li>
<li>Attach the device to your Provisioning Profile.  Apple will generate (or regenerate) a <kbd>.mobileprovision</kbd> file for you to download.  Always use the latest <kbd>.mobileprovision</kbd> file.</li>
<li>Build (or rebuild) your software in Xcode using the latest Provisioning Profile.</li>
<li>Zip up your application.</li>
<li>Deliver your finished <kbd>.app</kbd> together with the <kbd>.mobileprovision</kbd> to your beta tester.</li>
<li>The beta tester installs your provisioning profile, either by dragging it into iTunes or by using the iPhone Configuration Utility (iPCU).</li>
<li>Finally, the beta tester installs your app, using either iTunes or iPCU.</li>
</ol>
<p>That&#8217;s a lot of steps; there&#8217;s a lot of room for things to go wrong.  Here&#8217;s a few gotchas we encountered on our way to releasing the Redfin iPhone app.</p>
<h2>Some Zip Tools Don&#8217;t Work; Use <kbd>ditto</kbd></h2>
<p>Zipping your <kbd>.app</kbd> file is surprisingly tricky business.  For example, if you use Apache Ant&#8217;s <code>&lt;zip&gt;</code> task to create your zipfile, it will ignore the UNIX permissions of the files it zips.  When unsuspecting beta testers try to extract the app, they&#8217;ll find that it installs successfully under Windows (which doesn&#8217;t honor UNIX permissions) but if they install from OS X, the app will immediately crash on startup, with no crash log.</p>
<p>FYI, if you observe this permissions crash via the device console logs, it looks a little like this:
<pre>Tue Sep 29 17:47:04 unknown com.apple.launchd[1] : (UIKitApplication:com.redfin.redfin[0x43d3]) posix_spawn("/var/mobile/Applications/2B5E0CE3-362F-4FF0-80A2-C45DE3923C86/Redfin.app/Redfin", ...): Permission denied
Tue Sep 29 17:47:04 unknown com.apple.launchd[1] : (UIKitApplication:com.redfin.redfin[0x43d3]) Exited with exit code: 1
Tue Sep 29 17:47:04 unknown SpringBoard[24] : Failed to spawn Redfin. Unable to obtain a task name port right for pid 13432: (os/kern) failure
Tue Sep 29 17:47:04 unknown com.apple.launchd[1] : (UIKitApplication:com.redfin.redfin[0x43d3]) Throttling respawn: Will start in 2147483647 seconds
Tue Sep 29 17:47:04 unknown SpringBoard[24] : Application 'Redfin' exited abnormally with exit status 1
</code></pre>
<p>(Please excuse the scrolling; WordPress automatically screws up this log file entry.)</p>
<p>Even the standard command-line <kbd>zip</kbd> tool from Info-ZIP that comes with OS X doesn&#8217;t quite do the job.  Insidiously, zip archives created with <kbd>zip</kbd> work fine for beta testing, but the App Store will reject them, claiming that the app signature is invalid.</p>
<p>You can check the validity of your app signature with <kbd>codesign -vvvv YourAppName.app</kbd>.  (Yes, all four &#8220;v&#8221;s are necessary.)  Valid apps should look like this:</p>
<p><kbd>
<pre>$ codesign -vvvv Redfin.app
Redfin.app: valid on disk
Redfin.app: satisfies its Designated Requirement</pre>
<p></kbd></p>
<p>It is very easy to disturb this signature.  For example, if you copy the app with <kbd>cp -r Redfin.app /tmp</kbd> and then check the signature, you&#8217;ll get a message like this:</p>
<p><kbd>
<pre>$ codesign -vvvv Redfin.app
Redfin.app: a sealed resource is missing or invalid
/private/tmp/Redfin.app/CodeResources: resource added</pre>
<p></kbd></p>
<p>Unfortunately, <kbd>cp</kbd> isn&#8217;t the only command-line tool that can invalidate the signature.  If you create your zip archive using <kbd>zip -r yourappname YourAppName.app</kbd> and then unzip it (either with Finder or with <kbd>unzip</kbd>), you&#8217;ll invalidate the signature.</p>
<p>You don&#8217;t get this problem if you use Finder to create the zip archive, by putting <kbd>YourAppName.app</kbd> in a folder called <kbd>YourAppName</kbd>, and right-clicking on the <kbd>YourAppName</kbd> folder and selecting the &#8220;Compress&#8221; option.  To duplicate this functionality automatically, you&#8217;ll have to use <kbd><a href="http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man1/ditto.1.html">ditto</a></kbd>, which comes with OS X.  <kbd>ditto -c -k YourAppName YourAppName.zip</kbd> should do the trick.</p>
<h2>Don&#8217;t Use iTunes; Use the iPhone Configuration Utility</h2>
<p>Some people are able to successfully install apps and provisioning profiles using iTunes; if iTunes works for you, great.  But a lot of our beta testers weren&#8217;t so lucky.  iTunes would often fail mysteriously, sometimes with no useful error messages.</p>
<p>The iPhone Configuration Utility (iPCU) allows users to generate log files with error messages; these error messages are critical for diagnosing problems with application installation.  More generally, iPCU includes better error messages than iTunes all around; in many cases, switching to iPCU gave our beta testers enough information to solve the problem without the aid of developers.</p>
<p>There&#8217;s another good reason to use iPCU instead of iTunes for app installation: you can sync an iPhone with only one iTunes machine.  If you want to install beta apps using any other machine, you have to use the iPhone Configuration Utility.  In most cases, you can workaround even the trickiest app installation problems just by using iPCU to install from another machine.</p>
<p>To install an app using iPCU:</p>
<ol>
<li>Download and install the <a href="http://www.apple.com/support/iphone/enterprise/">iPhone Configuration Utility</a> from Apple.</li>
<li>Connect your iPhone/iPod to your computer via USB cable.</li>
<li>Close iTunes, if it is open, before launching iPCU</li>
<li>Launch iPCU.  You should see your device appear in the &#8220;Devices&#8221; section on the left side of the window.</li>
<li>Add the provisioning profile (mobile provision) to the iPCU Library: Click on &#8220;Provisioning Profiles&#8221;, then drag the <kbd>.mobileprovision</kbd> file into the Provisioning Profiles pane. </li>
<li>Add the application to the iPCU Library: Click on &#8220;Applications&#8221;, then drag the app into the Applications Pane. On Windows, the app will be a folder, named something like <kbd>YourAppName.app</kbd>. On Mac OS X, the app  will be a single application file.</li>
<li>Access your device: Click on your device in the list of devices on the left. You should see five tabs appear in the main window: &#8220;Summary&#8221;, &#8220;Configuration Profiles&#8221;, &#8220;Provisioning Profiles&#8221;, &#8220;Applications&#8221;, and &#8220;Console&#8221;.</li>
<li>Install the Provisioning Profile: Click on the &#8220;Provisioning Profiles&#8221; tab of your device. You should see your Ad Hoc Provisioning Profile in the list of profiles. In the &#8220;Install&#8221; column you should see either a button that says &#8220;Install&#8221; or a button that says &#8220;Remove&#8221; (if you&#8217;ve installed this profile previously). </li>
<li>Install the app: Click on your device&#8217;s &#8220;Applications&#8221; tab. You should see your app in the list of applications. In the &#8220;Install&#8221; column you should see either a button that says &#8220;Install&#8221; or a button that says &#8220;Uninstall&#8221; (if you&#8217;ve already installed the app). </li>
</ol>
<p>That&#8217;s all there is to it, assuming that nothing goes wrong.</p>
<h2>Error Messages: What Could Go Wrong?</h2>
<ul>
<li>iPhone Config Utility: &#8220;Could not start session with device. Error: <b>kAMDSessionActiveError</b>&#8221;
<p>Your device has turned off / fallen asleep. Push the power button, slide to unlock, and try it again. </p>
</li>
<li>iPhone Config Utility: I tried to install, and I got an error like &#8220;Could not install application on device. Error: <b>-402620395</b>.&#8221;.
<p>This is almost certainly because the <kbd>.mobileprovision</kbd> didn&#8217;t install correctly. Clear out all provisioning profiles from your phone and from the iPCU Library (following directions above), drag your <kbd>.mobileprovision</kbd> file into the Library / Provisioning Profiles section, then click on Devices / Your Device / Provisioning Profiles. Make sure you see only one profile on the list, and make sure it&#8217;s installed.</p>
</li>
<li>iPhone Config Utility: I tried to install, and I got an error like &#8220;Could not install application on device. Error: <b>-402620393</b>.&#8221;.
<p>We saw this error several times but never figured out the root cause.  <b>Installing from another machine worked around the problem.</b></p>
</li>
<li>iPhone Config Utility: I tried to install, and I got an error like &#8220;Could not transfer application to device. Error: <b>kAMDUndefinedError</b>.&#8221;.
<p>A number of our beta users had this error, but we never deduced the root cause.  In at least one case, re-installing the latest version of iPCU resolved the problem.  In all known cases, installing from another machine worked around the problem.</p>
</li>
<li>iTunes: I tried to sync, and I got an error like &#8220;The application &#8216;YourAppName&#8217; was not installed on the iPhone because an unknown error occurred (<b>0xE8008017</b>).&#8221;
<p>This is the same as error -402620393 above. (Note that E8008017 is hexadecimal for the signed integer -402620393.)  We saw this error several times but never figured out the root cause.  Installing from another machine without iTunes (using iPCU) worked around the problem.</p>
</li>
<li>iTunes: I tried to sync, and I got an error like &#8220;The application &#8216;YourAppName&#8217; was not installed on the iPhone because an unknown error occurred (<b>0xE8008015</b>).&#8221;
<p>This is the same as error -402620395 above. (Note that E8008015 is hexadecimal for the signed integer -402620395.)This is almost certainly because the <kbd>.mobileprovision</kbd> didn&#8217;t install correctly. Try dragging the <kbd>.mobileprovision</kbd> again to Applications pane in iTunes and syncing. It might also help to delete all of your existing mobile provisions (see <a href="#clear">Clear Out the Phone Using the Phone</a> below). </p>
</li>
</ul>
<h2>Troubleshooting</h2>
<p>Still not working?  Try this.</p>
<ol>
<li><b>Using iTunes? Try the iPhone Configuration Utility.</b></li>
<li><b>Try installing from another machine.</b> It&#8217;s often especially helpful to try installing from a Mac if you&#8217;re failing on Windows, or to try installing from a Windows box if you&#8217;re failing on a Mac.  (If you&#8217;re on Windows and you don&#8217;t have access to a Mac, try switching to a Windows machine that does not have iTunes installed.)</li>
<li><b>Close iTunes.</b> The iPhone Configuration Utility doesn&#8217;t work so well if iTunes is open. Note that iTunes auto-launches by default when you plug in an iPhone/iPod. </li>
<li><b>Try restarting your phone.</b> Press and hold the power button at the top of the phone, slide to power off. Wait until the screen turns off, then press and hold the power button again to start it up again. <b>No, seriously. This actually works, more often than you&#8217;d think.</b></li>
<li><b>Clear out the app and provisioning profiles correctly</b>, as described below. </li>
<li><b>Delete your entire iPCU Library</b>, as described below. </li>
<li>Using iPhone Configuration Utility? <b>Try iTunes.</b></li>
<li><i>Still</i> not working? <b>Examine the iPCU Log.</b> Directions below.</li>
</ol>
<h2><a name="clear">Clear Out the Phone Using the Phone</a></h2>
<p>Both iTunes and iPCU provide the ability to remove apps and provisioning profiles from the phone, but they don&#8217;t work very reliably, especially when you have multiple versions of the same app/profile bouncing around.</p>
<p>The most reliable way to remove an app from the iPhone is to do it the normal way: on the Home screen, press and hold your finger on the app; an X will appear.  Tap on the X to delete the app.</p>
<p>You can remove provisioning profiles using the iPhone &#8220;Settings&#8221; app.  In the &#8220;General&#8221; section, scroll down to the &#8220;Profiles&#8221; section, select it, tap on the old provisioning profile, and tap &#8220;Remove&#8221;.  (Ordinarily you shouldn&#8217;t need to delete provisioning profiles, but the best way to be sure that you&#8217;ve installed a <kbd>.mobileprovision</kbd> file is to remove all profiles and then install just the provision you need.)</p>
<p><img src="http://blog.redfin.com/devblog/files/2009/09/profiles-200x300.png" alt="profiles 200x300 Installing Beta Builds on iPhone" width="200" height="300" class="alignnone size-medium wp-image-149" title="Installing Beta Builds on iPhone" /></p>
<h2>Deleting the iPhone Configuration Utility Library</h2>
<p>Removing the app and provisioning profile from your iPCU library should just be a simple matter of deleting them in iPCU.  But if something goes really wrong, you may have to purge the iPCU library.  (In at least one recorded case, purging the iPCU library not only fixed iPCU, but also fixed installing the app via iTunes.)</p>
<p>On OSX, the iPCU library is stored in your Home directory, in ./Library/MobileDevice. You can delete the entire folder.</p>
<p>On Windows, the library is stored in your local application data folder.  To find your local app data folder:</p>
<ul>
<li>On Vista, press the Windows key, type <kbd>%localappdata%</kbd> in the search box, and press Enter.</p>
<li>On XP, press the Windows key, select &#8220;Run&#8221; and type <kbd>%userprofile%\Local Settings\Application Data</kbd>
</ul>
<p>Go to the &#8220;Apple Computer&#8221; folder. (There may also be an &#8220;Apple&#8221; folder and an &#8220;Apple_Inc&#8221; folder; ignore those.) You should see an &#8220;iPhone Configuration Utility&#8221; folder here and a &#8220;MobileDevice&#8221; folder here; delete both of them. </p>
<h2>Extracting the iPCU Log</h2>
<p>To access your device console, click on your device in the &#8220;Devices&#8221; section on the left pane of iPCU. There is a &#8220;Console&#8221; tab on the far right side. Click on that and you should start seeing console messages. (It sometimes takes a few seconds for the messages to appear.) You can click &#8220;Save Log As&#8230;&#8221; to generate a text file that you can send out as an attachment.</p>
<ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2009/09/installing_beta_builds_on_iphone.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Maven Reactor Tricks</title>
		<link>http://blog.redfin.com/devblog/2009/09/maven_reactor_tricks.html</link>
		<comments>http://blog.redfin.com/devblog/2009/09/maven_reactor_tricks.html#comments</comments>
		<pubDate>Mon, 28 Sep 2009 17:56:01 +0000</pubDate>
		<dc:creator>Dan Fabulich</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/?p=153</guid>
		<description><![CDATA[Not many people know this, but you can use Maven to resume a failed build from the middle, or to build just a subset of projects in a multi-module (a.k.a. &#8220;reactor&#8221;) build.
Example Reactor Project
Consider this complex multi-module reactor build:
my-root-project
&#124;-- pom.xml
&#124;-- barBusinessLogic
&#124;   `-- pom.xml
&#124;-- bazDataAccess
&#124;   `-- pom.xml
&#124;-- quz
&#124;   &#124;-- pom.xml
&#124; [...]]]></description>
			<content:encoded><![CDATA[<p>Not many people know this, but you can use Maven to resume a failed build from the middle, or to build just a subset of projects in a multi-module (a.k.a. &#8220;reactor&#8221;) build.</p>
<h2>Example Reactor Project</h2>
<p>Consider this complex multi-module reactor build:</p>
<pre>my-root-project
|-- pom.xml
|-- <b>barBusinessLogic</b>
|   `-- pom.xml
|-- <b>bazDataAccess</b>
|   `-- pom.xml
|-- quz
|   |-- pom.xml
|   |-- <b>quzAdditionalLogic</b>
|   |   `-- pom.xml
|   `-- <b>quzUI</b>
|       `-- pom.xml
`-- <b>fooUI</b>
    `-- pom.xml
</pre>
<p>Suppose project <kbd>fooUI</kbd> depends on project <kbd>barBusinessLogic</kbd>, which depends on project <kbd>bazDataAccess</kbd>.</p>
<pre>fooUI --&gt; barBusinessLogic --&gt; bazDataAccess
</pre>
<p>Furthermore, <kbd>quzUI</kbd> depends on <kbd>quzAdditionalLogic</kbd>, which depends on <kbd>barBusinessLogic</kbd>.</p>
<pre>quzUI --&gt; quzAdditionalLogic --&gt; barBusinessLogic --&gt; bazDataAccess
</pre>
<p>Ordinarily, when you run <kbd>mvn install</kbd> from <kbd>my-root-project</kbd>, you&#8217;ll build the projects in this order:</p>
<ol>
<li><kbd>my-root-project</kbd> (parent project)</li>
<li><kbd>bazDataAccess</kbd></li>
<li><kbd>barBusinessLogic</kbd></li>
<li><kbd>fooUI</kbd></li>
<li><kbd>quz</kbd> (parent project)</li>
<li><kbd>quzAdditionalLogic</kbd></li>
<li><kbd>quzUI</kbd></li>
</ol>
<h2>Resuming the Build with <kbd>--resume-from</kbd></h2>
<p>Suppose you&#8217;re working on your code and you attempt to run <kbd>mvn install</kbd> from <kbd>my-root-project</kbd>, but you encounter a test failure in <kbd>fooUI</kbd>.  You make additional changes to <kbd>barBusinessLogic</kbd> without changing <kbd>bazDataAccess</kbd>; you know that <kbd>bazDataAccess</kbd> is fine, so there&#8217;s no need to rebuild/test it. You can then use the <kbd>--resume-from</kbd> argument, like this:</p>
<p><kbd>mvn install --resume-from=fooUI<br />
</kbd></p>
<p>That will skip over <kbd>bazDataAccess</kbd> and <kbd>barBusinessLogic</kbd> and pick up the build where you left off in <kbd>fooUI</kbd>. If <kbd>fooUI</kbd> succeeds, it will go on to build <kbd>quzAdditionalLogic</kbd> and <kbd>quzUI</kbd>.</p>
<h2>Specify a Subset of Projects with &#8211;projects</h2>
<p>Suppose you&#8217;ve made some changes to <kbd>fooUI</kbd> and <kbd>bazDataAccess</kbd> and would like to rebuild just those two projects.  You can use the <kbd>--projects</kbd> argument, like this:</p>
<p><kbd>mvn install --projects fooUI,bazDataAccess<br />
</kbd></p>
<p>That will automatically build just those two projects, saving you the trouble of running Maven in each directory separately.</p>
<h2>Making <kbd>fooUI</kbd> Without Building <kbd>quz</kbd> Using <kbd>--also-make</kbd></h2>
<p>Suppose you&#8217;re a developer working on <kbd>fooUI</kbd>; you don&#8217;t want to work on <kbd>quz</kbd> right now, but just want to get a working build of <kbd>fooUI</kbd>. You can use <kbd>--also-make</kbd>, like this:</p>
<p><kbd>mvn install --projects fooUI --also-make<br />
</kbd></p>
<p><kbd>--also-make</kbd> will examine <kbd>fooUI</kbd> and walk down its dependency tree, finding all of the projects that it needs to build. In this case, it will automatically build <kbd>bazDataAccess</kbd>, <kbd>barBusinessLogic</kbd> and <kbd>fooUI</kbd> without building <kbd>quz</kbd>.</p>
<h2>Changing <kbd>barBusinessLogic</kbd> and Verifying You Didn&#8217;t Break Anything Using <kbd>--also-make-dependents</kbd></h2>
<p>Suppose you&#8217;ve made a change to <kbd>barBusinessLogic</kbd>; you want to make sure you didn&#8217;t break any of the projects that depend on you. You also want to avoid rebuilding/testing projects that you know you haven&#8217;t changed. In this case, you want to avoid building <kbd>bazDataAccess</kbd>. You can use <kbd>--also-make-dependents</kbd>, like this:</p>
<p><kbd>mvn install --projects barBusinessLogic --also-make-dependents<br />
</kbd></p>
<p><kbd>--also-make-dependents</kbd> will examine all of the projects in your reactor to find projects that depend on <kbd>barBusinessLogic</kbd>; it will automatically build those and anything that depends on them.</p>
<h2>Resuming a <kbd>make</kbd> Build</h2>
<p>When you use <kbd>--also-make</kbd> or <kbd>--also-make-dependents</kbd>, you run a subset of projects, but that doesn&#8217;t mean stuff won&#8217;t fail halfway through the build. You can resume an <kbd>--also-make</kbd> build from the project that stopped the build by using <kbd>--resume-from</kbd> together with <kbd>--also-make</kbd>, like this:</p>
<p><kbd>mvn install --projects quz/quzUI --also-make --resume-from barBusinessLogic<br />
</kbd></p>
<p>At Redfin, our Maven reactor has 86 projects; avoiding unnecessary rebuilds is essential to our productivity!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2009/09/maven_reactor_tricks.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Announcing SitemapGen4j 1.0</title>
		<link>http://blog.redfin.com/devblog/2009/02/announcing_sitemapgen4j_10.html</link>
		<comments>http://blog.redfin.com/devblog/2009/02/announcing_sitemapgen4j_10.html#comments</comments>
		<pubDate>Tue, 03 Feb 2009 21:15:39 +0000</pubDate>
		<dc:creator>Dan Fabulich</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/2009/02/announcing_sitemapgen4j_10.html</guid>
		<description><![CDATA[Redfin is happy to announce SitemapGen4j 1.0.  SitemapGen4j is a library to generate XML sitemaps in Java.
Download SitemapGen4j 1.0
What&#8217;s an XML sitemap?
Quoting from sitemaps.org:
Sitemaps are an easy way for webmasters to inform search engines about pages on their sites that are available for crawling. In its simplest form, a Sitemap is an XML file [...]]]></description>
			<content:encoded><![CDATA[<p>Redfin is happy to announce <a href="http://code.google.com/p/sitemapgen4j/">SitemapGen4j 1.0</a>.  SitemapGen4j is a library to generate XML sitemaps in Java.</p>
<p><a href="http://code.google.com/p/sitemapgen4j/">Download SitemapGen4j 1.0</a></p>
<h2>What&#8217;s an XML sitemap?</h2>
<p>Quoting from <a href="http://sitemaps.org/index.php">sitemaps.org</a>:</p>
<blockquote><p>Sitemaps are an easy way for webmasters to inform search engines about pages on their sites that are available for crawling. In its simplest form, a Sitemap is an XML file that lists URLs for a site along with additional metadata about each URL (when it was last updated, how often it usually changes, and how important it is, relative to other URLs in the site) so that search engines can more intelligently crawl the site.</p>
<p>Web crawlers usually discover pages from links within the site and from other sites. Sitemaps supplement this data to allow crawlers that support Sitemaps to pick up all URLs in the Sitemap and learn about those URLs using the associated metadata. Using the Sitemap protocol does not guarantee that web pages are included in search engines, but provides hints for web crawlers to do a better job of crawling your site.</p>
<p>Sitemap 0.90 is offered under the terms of the Attribution-ShareAlike Creative Commons License and has wide adoption, including support from Google, Yahoo!, and Microsoft.</p>
</blockquote>
<h2>Getting started</h2>
<p>The easiest way to get started is to just use the WebSitemapGenerator class, like this:</p>
<pre name="code" class="java">WebSitemapGenerator wsg = new WebSitemapGenerator("http://www.example.com", myDir);
wsg.addUrl("http://www.example.com/index.html"); // repeat multiple times
wsg.write();</pre>
<h2>Configuring options</h2>
<p>But there are a lot of nifty options available for URLs and for the generator as a whole.  To configure the generator, use a builder:</p>
<pre name="code" class="java">WebSitemapGenerator wsg = WebSitemapGenerator.builder("http://www.example.com", myDir)
    .gzip(true).build(); // enable gzipped output
wsg.addUrl("http://www.example.com/index.html");
wsg.write();</pre>
<p>To configure the URLs, construct a WebSitemapUrl with WebSitemapUrl.Options.</p>
<pre name="code" class="java">WebSitemapGenerator wsg = new WebSitemapGenerator("http://www.example.com", myDir);
WebSitemapUrl url = new WebSitemapUrl.Options("http://www.example.com/index.html")
    .lastMod(new Date()).priority(1.0).changeFreq(ChangeFreq.HOURLY).build();
// this will configure the URL with lastmod=now, priority=1.0, changefreq=hourly
wsg.addUrl(url);
wsg.write();</pre>
<h2>Configuring the date format</h2>
<p>One important configuration option for the sitemap generator is the date format.  The <a href="http://www.w3.org/TR/NOTE-datetime">W3C datetime standard</a> allows you to choose the precision of your datetime (anything from just specifying the year like &#8220;1997&#8243; to specifying the fraction of the second like &#8220;1997-07-16T19:20:30.45+01:00&#8243;); if you don&#8217;t specify one, we&#8217;ll try to guess which one you want, and we&#8217;ll use the default timezone of the local machine, which might not be what you prefer.</p>
<pre name="code" class="java">
// Use DAY pattern (2009-02-07), Greenwich Mean Time timezone
W3CDateFormat dateFormat = new W3CDateFormat(Pattern.DAY);
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
WebSitemapGenerator wsg = WebSitemapGenerator.builder("http://www.example.com", myDir)
    .dateFormat(dateFormat).build(); // actually use the configured dateFormat
wsg.addUrl("http://www.example.com/index.html");
wsg.write();</pre>
<h2>Lots of URLs: a sitemap index file</h2>
<p>One sitemap can contain a maximum of 50,000 URLs.  (Some sitemaps, like Google News sitemaps, can contain only 1,000 URLs.) If you need to put more URLs than that in a sitemap, you&#8217;ll have to use a sitemap index file.  Fortunately,  WebSitemapGenerator can manage the whole thing for you. </p>
<pre name="code" class="java">WebSitemapGenerator wsg = new WebSitemapGenerator("http://www.example.com", myDir);
for (int i = 0; i &lt; 60000; i++) wsg.addUrl("http://www.example.com/doc"+i+".html");
wsg.write();
wsg.writeSitemapsWithIndex(); // generate the sitemap_index.xml
</pre>
<p>That will generate two sitemaps for 60K URLs: sitemap1.xml (with 50K urls) and sitemap2.xml (with the remaining 10K), and then generate a sitemap_index.xml file describing the two.</p>
<p>It&#8217;s also possible to carefully organize your sub-sitemaps.  For example, it&#8217;s recommended to group URLs with the same changeFreq together (have one sitemap for changeFreq &#8220;daily&#8221; and another for changeFreq &#8220;yearly&#8221;), so you can modify the lastMod of the daily sitemap without modifying the lastMod of the yearly sitemap.  To do that, just construct your sitemaps one at a time using  the WebSitemapGenerator, then use the SitemapIndexGenerator to create a single index for all of them.</p>
<pre name="code" class="java">WebSitemapGenerator wsg;
// generate foo sitemap
wsg = WebSitemapGenerator.builder("http://www.example.com", myDir)
    .fileNamePrefix("foo").build();
for (int i = 0; i &lt; 5; i++) wsg.addUrl("http://www.example.com/foo"+i+".html");
wsg.write();
// generate bar sitemap
wsg = WebSitemapGenerator.builder("http://www.example.com", myDir)
    .fileNamePrefix("bar").build();
for (int i = 0; i &lt; 5; i++) wsg.addUrl("http://www.example.com/bar"+i+".html");
wsg.write();
// generate sitemap index for foo + bar
SitemapIndexGenerator sig = new SitemapIndexGenerator("http://www.example.com", myFile);
sig.addUrl("http://www.example.com/foo.xml");
sig.addUrl("http://www.example.com/bar.xml");
sig.write();</pre>
<p>You could also use the SitemapIndexGenerator to incorporate sitemaps generated by other tools.  For example, you might use Google&#8217;s official Python sitemap generator to generate some sitemaps, and use WebSitemapGenerator to generate some sitemaps, and use SitemapIndexGenerator to make an index of all of them.</p>
<h2>Validate your sitemaps</h2>
<p>SitemapGen4j can also validate your sitemaps using the official XML Schema Definition (XSD).  If you used SitemapGen4j to make the sitemaps, you shouldn&#8217;t need to do this unless there&#8217;s a bug in our code.  But you can use it to validate sitemaps generated by other tools, and it provides an extra level of safety.</p>
<p>It&#8217;s easy to configure the WebSitemapGenerator to automatically validate your sitemaps right after you write them (but this does slow things down, naturally).</p>
<pre name="code" class="java">WebSitemapGenerator wsg = WebSitemapGenerator.builder("http://www.example.com", myDir)
    .autoValidate(true).build(); // validate the sitemap after writing
wsg.addUrl("http://www.example.com/index.html");
wsg.write();</pre>
<p>You can also use the SitemapValidator directly to manage sitemaps.  It has two methods: validateWebSitemap(File f) and validateSitemapIndex(File f).</p>
<h2>Google-specific sitemaps</h2>
<p>Google can understand a wide variety of custom sitemap formats that they made up, including a Mobile sitemaps, Geo sitemaps, Code sitemaps (for Google Code search), Google News sitemaps, and Video sitemaps.  SitemapGen4j can generate any/all of these different types of sitemaps.</p>
<p>To generate a special type of sitemap, just use GoogleMobileSitemapGenerator, GoogleGeoSitemapGenerator, GoogleCodeSitemapGenerator, GoogleCodeSitemapGenerator, GoogleNewsSitemapGenerator, or GoogleVideoSitemapGenerator instead of WebSitemapGenerator.</p>
<p>You can&#8217;t mix-and-match regular URLs with Google-specific sitemaps, so you&#8217;ll also have to use a GoogleMobileSitemapUrl, GoogleGeoSitemapUrl, GoogleCodeSitemapUrl, GoogleNewsSitemapUrl, or GoogleVideoSitemapUrl instead of a WebSitemapUrl.  Each of them has unique configurable options not available to regular web URLs.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2009/02/announcing_sitemapgen4j_10.html/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>URL Query Parameters and HTML Entities: The Case of the Missing Semicolon</title>
		<link>http://blog.redfin.com/devblog/2008/10/url_query_parameters_and_html_entities_the_case_of_the_missing_semicolon.html</link>
		<comments>http://blog.redfin.com/devblog/2008/10/url_query_parameters_and_html_entities_the_case_of_the_missing_semicolon.html#comments</comments>
		<pubDate>Wed, 15 Oct 2008 02:50:23 +0000</pubDate>
		<dc:creator>Dan Fabulich</dc:creator>
				<category><![CDATA[Browsers]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/2008/10/url_query_parameters_and_html_entities_the_case_of_the_missing_semicolon.html</guid>
		<description><![CDATA[What&#8217;s the difference between this HTML snippet:
    &#60;a href="http://www.google.com/search?q=html&#38;foo=0"&#62;foo=0&#60;/a&#62;
and this?
    &#60;a href="http://www.google.com/search?q=html&#38;copy=0"&#62;copy=0&#60;/a&#62;
Both of them look like simple Google searches (though they could have been anything; Google is just an example).  One of them appends an extra &#8220;&#38;foo=0&#8243; to the end of the URL; the other appends &#8220;&#38;copy=0&#8243; instead.
Only [...]]]></description>
			<content:encoded><![CDATA[<p>What&#8217;s the difference between this HTML snippet:</p>
<pre><code>    &lt;a href="http://www.google.com/search?q=html&amp;<strong>foo=0</strong>"&gt;foo=0&lt;/a&gt;</code></pre>
<p>and this?</p>
<pre><code>    &lt;a href="http://www.google.com/search?q=html&amp;<strong>copy=0</strong>"&gt;copy=0&lt;/a&gt;</code></pre>
<p>Both of them look like simple Google searches (though they could have been anything; Google is just an example).  One of them appends an extra &#8220;&amp;foo=0&#8243; to the end of the URL; the other appends &#8220;&amp;copy=0&#8243; instead.</p>
<p>Only the second snippet is <a href="http://validator.w3.org/check?fragment=%3C%21DOCTYPE+html+PUBLIC+%22-%2F%2FW3C%2F%2FDTD+HTML+4.01%2F%2FEN%22+%22http%3A%2F%2Fwww.w3.org%2FTR%2Fhtml4%2Fstrict.dtd%22%3E%0D%0A%3Chtml%3E%3Chead%3E%3Ctitle%3E%3C%2Ftitle%3E%3C%2Fhead%3E%3Cbody%3E%3Cp%3E%3Ca+href%3D%22http%3A%2F%2Fwww.google.com%2Fsearch%3Fq%3Dhtml%26copy%3D0%22%3Ecopy%3D0%3C%2Fa%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E%0D%0A" rel="nofollow">valid in HTML 4.01 Strict</a>, but that snippet doesn&#8217;t work the way you might expect.  Neither snippet is valid in XHTML.</p>
<p>Give up?  Click on these:</p>
<p><iframe src="http://blog.redfin.com/wp-content/uploads/html/poor-html-iframe.html" frameborder="0" height="50" scrolling="no"></iframe></p>
<p>The first URL searches for &#8220;html,&#8221; but the other URL searches for &#8220;html&copy;=0.&#8221;</p>
<p>Two weird things are happening here.</p>
<ul>
<li>Note that &#8220;&amp;copy;&#8221; is an HTML entity for the copyright symbol &#8220;&copy;.&#8221;  It would have been more obvious if the URL had used a semicolon, like this:
<pre><code>    &lt;a href="http://www.google.com/search?q=html<strong>&amp;copy;</strong>=0"&gt;copy;=0&lt;/a&gt;</code></pre>
<p>or if we&#8217;d used a more traditional HTML entity like this:</p>
<pre><code>    &lt;a href="http://www.google.com/search?q=html<strong>&amp;quot;</strong>=0"&gt;quot;=0&lt;/a&gt;</code></pre>
</li>
<li>The second weird thing is a <a href="http://www.w3.org/TR/REC-html40/charset.html#entities">quirk in the HTML specification on character references</a>:<br />
<blockquote><p><em><strong>Note.</strong> In SGML, it is possible to eliminate the final &#8220;;&#8221; after a character reference in some cases (e.g., at a line break or immediately before a tag). In other circumstances it may not be eliminated (e.g., in the middle of a word). We strongly suggest using the &#8220;;&#8221; in all cases to avoid problems with user agents that require this character to be present.</em></p></blockquote>
<p>As a result, all modern browsers (FF3, IE7, Opera 9, Safari 3.1) will helpfully notice possible entities like &#8220;&amp;copy&#8221; and &#8220;&amp;lt&#8221; and replace them with &#8220;&copy;&#8221; and &#8220;&lt;&#8221; &#8230; they assume you forgot the semicolon.  This applies to <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">all of the HTML entities</a>, even the obscure ones like &amp;empty &#8220;&empty;&#8221;, &amp;not &#8220;&not;&#8221;, &amp;reg &#8220;&reg;&#8221;, &amp;sub &#8220;&sub;&#8221;, and &amp;lang &#8220;&lang;&#8221;.  (Bizarrely, &amp;Copy is left alone as &#8220;&amp;Copy&#8221; but &amp;COPY is replaced with &#8220;&COPY;&#8221;.)</li>
</ul>
<p>We think there are two valuable lessons to learn from this story.  The first lesson you may already know:</p>
<ol>
<li>The correct way to write an URL with a query parameter is to HTML escape the URL, replacing all &amp;s with &amp;amp; like this:
<pre><code>    &lt;a href="http://www.google.com/search?q=html<strong>&amp;amp;copy=0</strong>"&gt;copy=0&lt;/a&gt;</code></pre>
<p>That&#8217;s also the only way to make the snippet XHTML compliant.</li>
<li>Don&#8217;t use URL query parameters whose names are <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">HTML entities</a>.  Never create a web service that accepts a query parameter like &#8220;&amp;lang=en&#8221;.  After all, there&#8217;s no way to know when your users might want to copy &amp; paste your URLs into a blog, forum, or HTML email.  Even if developers are clever enough to HTML escape href links, not everyone will be, and you can save everybody some trouble by avoiding the dangerous entities altogether.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2008/10/url_query_parameters_and_html_entities_the_case_of_the_missing_semicolon.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Lightweight Headless Test for Trailing Commas in JavaScript</title>
		<link>http://blog.redfin.com/devblog/2008/09/lightweight_headless_test_for_trailing_commas_in_javascript.html</link>
		<comments>http://blog.redfin.com/devblog/2008/09/lightweight_headless_test_for_trailing_commas_in_javascript.html#comments</comments>
		<pubDate>Tue, 16 Sep 2008 20:26:56 +0000</pubDate>
		<dc:creator>Dan Fabulich</dc:creator>
				<category><![CDATA[Browsers]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/2008/09/lightweight_headless_test_for_trailing_commas_in_javascript.html</guid>
		<description><![CDATA[Yesterday one of my co-workers spent hours reproducing and tracking down a bug that turned out to be a stray comma.
Unfortunately, Microsoft Internet Explorer doesn&#8217;t support trailing commas in JavaScript arrays and object literals.  Code like this won&#8217;t parse:
    var chord = ["do", "mi", "so",];
    var json = { [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday one of my co-workers spent hours reproducing and tracking down a bug that turned out to be a stray comma.</p>
<p>Unfortunately, Microsoft Internet Explorer doesn&#8217;t support trailing commas in JavaScript arrays and object literals.  Code like this won&#8217;t parse:</p>
<pre name="code" class="js">    var chord = ["do", "mi", "so",];
    var json = { truth:"beauty", beauty:true, };</pre>
<p>Those final commas will cause syntax errors in IE.</p>
<p>&#8220;How many thousands of developer hours have been lost to random IE bugs like this?&#8221; I asked myself.  I decided that there had to be a good way to detect this problem in an automated way, without firing up a copy of IE and running a full test suite. </p>
<p>It turns out that these and other syntax errors can be detected automatically from the Windows command line, using the Windows Scripting Host (WSH).  On Windows XP and higher, the command-line tool &#8220;cscript.exe&#8221; can be used to run JavaScript (ahem, <em>JScript</em>) headlessly (outside of any browser).</p>
<p>Just create a file called &#8220;wsh-parser.js&#8221; like this:</p>
<pre name="code" class="js">var fso = new ActiveXObject( "Scripting.FileSystemObject" );

function parse(fname) {
    var file = fso.OpenTextFile( fname, 1 );
    ret = file.ReadAll();
    file.Close();
    try {
        eval("(function(){\\n"+ret+"\\n});");
    } catch (e) {
        WScript.Echo("Syntax error parsing " + fname);
        WScript.Echo("  " + e.message);
    }
}

function findJavaScript(folder) {
    for (var fc = new Enumerator(folder.files); !fc.atEnd(); fc.moveNext()) {
        var file=fc.item();
        if (/.js$/.test(file.Name)) {
            parse(file);
        }
    }
    for (var fc = new Enumerator(folder.subfolders); !fc.atEnd(); fc.moveNext()) {
        var subfolder = fc.item();
        if (subfolder.Name == ".svn") continue; // ignore .svn folders
        findJavaScript(subfolder);
    }
}

var rootPath = "src/main/javascript";
var rootFolder = fso.GetFolder(rootPath);

findJavaScript(rootFolder);</pre>
<p>Then run it like this:</p>
<pre name="code">    cscript //E:javascript //nologo wsh-parser.js</pre>
<p>The script will automatically examine every JavaScript file in the specified rootPath, reporting errors in any file that won&#8217;t parse correctly.</p>
<p>There&#8217;s a bit of magic going on here in the &#8220;parse&#8221; function to guarantee that we&#8217;re only verifying the syntax of our JavaScript, without actually running it.  The magic line is:</p>
<pre name="code" class="js">    eval("(function(){\\n"+ret+"\\n});");</pre>
<p>The &#8220;eval&#8221; command would normally execute the provided string, but here we wrap the code in an anonymous function declaration.  We improve the performance and the maintainability of our test by declaring the function without actually using it.</p>
<p>Note that you can also use <a href="http://www.jslint.com/">JsLint</a> to detect trailing commas, but it will probably report a bunch of other problems with your code that you may or may not care about.</p>
<p>Automated validators like these should be used together with headless unit tests as well as live browser tests.  (I would recommend <a href="http://selenium.openqa.org">Selenium</a> for automated browser tests.  There are a ton of excellent headless JavaScript unit test tools, including <a href="http://jsunit.berlios.de/">Schaible&#8217;s JsUnit</a>, <a href="http://code.google.com/p/rhinounit/">RhinoUnit</a>, and <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/d-o-h-unit-testing">DOH</a>.  Note that <a href="http://www.jsunit.net/">Hieatt&#8217;s JsUnit</a> is not headless.)</p>
<p>But I recommend running automated validators first, because they&#8217;re fast and the errors they report are easy to debug/fix.  Once the automated validators are happy, run your unit tests.  When your unit tests pass, run your live browser tests.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2008/09/lightweight_headless_test_for_trailing_commas_in_javascript.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
