<?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>John of All Trades &#187; Code</title>
	<atom:link href="http://www.johnofalltrades.name/category/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.johnofalltrades.name</link>
	<description>Yeah. I&#039;d hack that.</description>
	<lastBuildDate>Tue, 26 Apr 2011 17:09:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Every Message has its Medium&#8230;</title>
		<link>http://www.johnofalltrades.name/2011/04/21/every-message-has-its-medium/</link>
		<comments>http://www.johnofalltrades.name/2011/04/21/every-message-has-its-medium/#comments</comments>
		<pubDate>Thu, 21 Apr 2011 21:28:53 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.johnofalltrades.name/?p=242</guid>
		<description><![CDATA[I&#8217;m presenting at JBossWorld this year, talking about best practices and trip hazards related to Apache Maven. I&#8217;ve spent the past several days working on the presentation, and one thing that strikes me is how much work goes into so very little content. The idea and general outline are the easy part! After this comes [...]]]></description>
			<content:encoded><![CDATA[<p><img style="border: 0pt none; width: 0pt; height: 0pt; display: none;" src="http://tokentracker.com/token.gif?id=acT2aar85" alt="" />I&#8217;m presenting at JBossWorld this year, talking about best practices and trip hazards related to Apache Maven.</p>
<p>I&#8217;ve spent the past several days working on the presentation, and one thing that strikes me is how much work goes into so very little content. The idea and general outline are the easy part! After this comes hours of concocting graphics that illustrate your point while de-cluttering the slides, then hours of dealing with the most ruthless of editors: the stopwatch. Long before you&#8217;ve satisfied this critic, you&#8217;re forced to give up on some of the ideas you previously regarded as absolute essentials. In the end, you come to realize that you&#8217;ve initially had enough content to fill three hours, not fifty minutes.</p>
<p>I&#8217;ve opted this year to do a LOT more slides, many of which are variations on the same message that each highlight a different aspect. I&#8217;m hoping this will have the effect of presenting the same amount of content in a much clearer way, but who knows? I&#8217;m going on the theory that a picture is worth a thousand words, so we&#8217;ll see if <em>that&#8217;s</em> true&#8230;I should have some results for you in a couple weeks. I&#8217;ve chosen to stay away from live demos, mainly because most presentations I&#8217;ve seen that include them don&#8217;t work well (especially when the presentation is only an hour long). Usually, there are enough things that go wrong to derail the point of the presentation. Besides, I&#8217;m still relatively new to this, and I&#8217;m not willing to play fast and loose with the time management just yet, thanks very much.</p>
<p>Beyond struggling with the work involved in getting the slides <em>just right</em>, I&#8217;m also struck by the fact that each message has its own optimum medium. People in the business world are fond of saying that some things just need to be solved face-to-face, or that sometimes there&#8217;s simply no substitute for a phone call. Mostly I tend to think of these people as just not trying hard enough, or giving in to the habits bred by long years spent in co-located offices and cubicle farms. But I think that giving a technical presentation makes this point in a completely backward way&#8230;if you&#8217;ve ever tried to explain a technical concept in mere words and hand gestures, you know what I mean. As you attempt to manipulate imaginary solid shapes in mid-air, all the while relating the concept using a bunch of very technical words that have extremely closely-related definitions in their everyday use, you begin to understand the absurdity of it all. This is probably where a good set of diagrams &#8211; or a live demo &#8211; can save the day. I&#8217;m hoping that&#8217;s true. Otherwise, people are going to be in for one hell of an imaginary puppet show!</p>
<p>Wish me luck! And, if you&#8217;re at JBossWorld this year, stop by Wednesday afternoon and say hi. I&#8217;ll be presenting <a href="http://www.redhat.com/summit/sessions/jboss.html#607">Maven Best Practices</a>.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.johnofalltrades.name%2F2011%2F04%2F21%2Fevery-message-has-its-medium%2F&amp;title=Every%20Message%20has%20its%20Medium%26%238230%3B" id="wpa2a_2"><img src="http://www.johnofalltrades.name/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2011/04/21/every-message-has-its-medium/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nexus Development Hint: Debug a Missing Plugin Resource</title>
		<link>http://www.johnofalltrades.name/2010/03/18/nexus-development-hint-debug-a-missing-plugin-resource/</link>
		<comments>http://www.johnofalltrades.name/2010/03/18/nexus-development-hint-debug-a-missing-plugin-resource/#comments</comments>
		<pubDate>Thu, 18 Mar 2010 23:34:22 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[Eclipse]]></category>
		<category><![CDATA[Nexus]]></category>

		<guid isPermaLink="false">http://www.johnofalltrades.name/?p=172</guid>
		<description><![CDATA[To counter-balance my rant the other day about plugin development (specifically in Nexus), I thought I&#8217;d offer a method I developed for coping with the hidden errors I ran into. NOTE: Before I start, I should mention that most of the pain I&#8217;m about to describe, along the method of finding and working around the [...]]]></description>
			<content:encoded><![CDATA[<p>To counter-balance my <a href="http://www.johnofalltrades.name/2010/03/16/the-pain-of-plugin-development/"><img style="border: 0pt none; width: 0pt; height: 0pt; display: none;" src="http://tokentracker.com/token.gif?id=abIe2dd40" alt="" />rant</a> the other day about plugin development (specifically in Nexus), I thought I&#8217;d offer a method I developed for coping with the hidden errors I ran into.</p>
<p><strong>NOTE:</strong> Before I start, I should mention that most of the pain I&#8217;m about to describe, along the method of finding and working around the problem, will soon be a thing of the past. I&#8217;ve spoken to some of the Nexus team members, and they assure me they&#8217;re preparing to move Nexus off of Plexus, and onto Guice for dependency injection. So, once Nexus 1.6.0 comes out <em>[I hope]</em> it&#8217;ll be time to scrap these instructions.</p>
<h2>First, a little background.</h2>
<p>I&#8217;ve developed two Nexus plugins now, both small, and in each case I&#8217;ve run into strange behavior where my custom REST resources would go missing with nary an error to the console or logs. After specifying a particular resource URI, I&#8217;d build and deploy the plugin to my local Nexus instance, then try to hit it using <code>curl</code> with something like the following:</p>
<blockquote><p><code>curl --include --basic -H 'Accept: application/json' http://admin:admin123@localhost:8081/nexus/service/local/echo</code></p></blockquote>
<p>If all was well, the resource should respond with some result, throw an error, or something. But all I received was a 404 Not Found for my trouble. I attempted to dial up the log-level in <code>sonatype-work/nexus/conf/log4j.properties</code>, and scanned both <code>nexus-webapp-1.5.0/logs/wrapper.log</code> <strong>and</strong> <code>sonatype-work/nexus/logs/nexus.log</code> (the location I told log4j to use via a FileAppender). Nada.</p>
<p>When I developed my first plugin, this was the point where I started to bang my head against the wall in earnest. I couldn&#8217;t see any problems, it appeared from the logs that my plugin <strong>was</strong> loaded (it was listed in the plugin-manager output for my plugin bundle), and yet <code>curl</code> doesn&#8217;t lie. After about ten hours of remote debugging, I found a breakpoint that let me see what was going on. Eventually, I found a way to code around the problem, commented the hack liberally in my own code, filed a JIRA (<a href="https://issues.sonatype.org/browse/NEXUS-3308">NEXUS-3308</a>), and moved on. Unfortunately, when it came time to test the second plugin, I&#8217;d already dumped all the old debug breakpoints from the first go-round. So, this time I&#8217;m going to document the setup I used to find and fix the problem before I forget it again.</p>
<h2>Prepare your Nexus instance.</h2>
<p>Before we even talk about remote debugging from Eclipse, we need to setup Nexus to listen on a JPDA (java debugger) port. To do this, I modified the stock Java Service Wrapper <code>wrapper.conf</code> file that comes with Nexus as follows:</p>
<p><a href="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-wrapper.png"><img src="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-wrapper.png" alt="" width="501" height="263" /></a></p>
<p>You&#8217;ll notice that I actually have two variants of this JPDA configuration: one with <code>suspend=y</code>, and one with <code>suspend=n</code>. In most of my previous experience with remote debugging, I&#8217;ve been starting the application with the debugger attached so I can catch boot errors, things like that. But in the case of Nexus, I almost never use the <code>suspend=y</code> approach, since this makes the whole startup process excruciatingly slow. It&#8217;s not Nexus&#8217; fault, it&#8217;s just what happens when your remote debugger is watching Every. Single. Line. If you&#8217;re even halfway paying attention, you should have no problem watching the logs and attaching your remote debugger in plenty of time to catch the breakpoint you&#8217;re interested in. Particularly if it&#8217;s the breakpoint I&#8217;ll discuss below.</p>
<p>Now that you have Nexus rigged for debugging, let&#8217;s talk about the remote debugger before we restart. Once we restart Nexus, we&#8217;ll need to be on the ball to attach the debugger and intercept our breakpoint of choice at boot.</p>
<h2>Setup your remote debugger.</h2>
<p>What follows is described in terms of Eclipse. It&#8217;s the IDE I use, for a number of reasons. I get endless shit about this from the IDEA fanatics I run into here and there. For those people: I understand you&#8217;re probably of above-average intelligence. You will probably have no problem at all translating my instructions into IDEA-ese.</p>
<p>To start, get the project setup so you can actually navigate something meaningful with your debugger. This means attaching the sources for the <code>plexus-container-default</code> dependency in your project. I&#8217;m using <a href="http://m2eclipse.sonatype.org/">m2eclipse</a>, which makes it pretty easy. The following is a view of my Package Explorer, poised to go download and attach the Plexus source code:</p>
<p><a href="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-src.png"><img src="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-src.png" alt="" width="371" height="413" /></a></p>
<p>Next, setup a new Debug Configuration for your remote Nexus instance. This is pretty straightforward; the main points to notice is that your plugin project is selected as the main entry point, the host is set to <code>localhost</code> (or, wherever your Nexus instance is running), and the port is set to <code>8000</code> (this must correspond with the <code>wrapper.conf</code> modifications above). Your configuration should look something like this:</p>
<p><a href="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-remote.png"><img src="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-remote.png" alt="" width="480" height="384" /></a></p>
<p>Now we&#8217;re ready to configure that critical breakpoint, and setup our debugging environment so we can see the output. To set the breakpoint, I navigated through the <code>plexus-container-default</code> artifact until I found <code>org.codehaus.plexus.component.collections.AbstractComponentCollection</code>, scrolled to <strong>line 159</strong>, and set the breakpoint, like so:</p>
<p><a href="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-debug-breakpoint.png"><img src="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-debug-breakpoint.png" alt="" width="683" height="352" /></a></p>
<p><em>(You can set this breakpoint easily by double-clicking in the left gutter on line 159.)</em> Also, notice that the breakpoint shows up in my Breakpoints View, in the upper-right corner. If you read <strong>NEXUS-3308</strong>, you&#8217;ll understand why this particular breakpoint is so critical&#8230;</p>
<p>Once you&#8217;ve set the breakpoint, also setup a watched expression to output the full exception stacktrace. To do this, right-click in the <strong>Watched Expressions View</strong>, and select <strong>Add Watched Expression</strong>. Then, enter the following:</p>
<p><a href="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-expr2.png"><img src="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-expr2.png" alt="" width="356" height="208" /></a></p>
<p>Finally, since the result of that watched expression will be quite verbose, it&#8217;s important to extend the maximum buffer for the output pane in the Watched Expression View. To avoid having to do this twice, I&#8217;ve set mine to <code>0</code> <em>(no maximum)</em>. Just select <strong>Max Length&#8230;</strong> from the following menu, and set it appropriately:</p>
<p><a href="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-expr.png"><img src="http://www.johnofalltrades.name/wp-content/uploads/2010/03/nexus-plugin-dev-expr.png" alt="" width="270" height="283" /></a></p>
<h2>Debug!</h2>
<p>Now, we&#8217;re ready to dig in and find that elusive bug that&#8217;s been making life hell. To do this, you&#8217;re going to be paying attention!</p>
<p>Ready? Okay, first stop Nexus and then re-run it in console mode. This allows you to stop it with CTL-C after you&#8217;re done debugging. The commands look something like this:</p>
<blockquote><p><code><br />
~/apps/nexus/current/bin/jsw/macosx-universal-32/nexus stop<br />
~/apps/nexus/current/bin/jsw/macosx-universal-32/nexus console<br />
</code></p></blockquote>
<p><strong>As soon as you see output like the following</strong>, attach your remote debugger:</p>
<pre>INFO   | jvm 1    | 2010/03/16 17:22:30 | Initializing Nexus (OSS), Version 1.5.0
</pre>
<p>Now, simply wait. If your Nexus component is failing when it initializes, the breakpoint will halt the system and the watched expression above will contain the full stacktrace. If you click on that watched expression, then click on the output pane, you can use CTL-A (CMD-A), CTL-C (CMD-C) to Select All of the stacktrace, then Copy it to your clipboard. From here, I&#8217;ve had a lot of luck opening Any Old Text Editor and pasting the stacktrace there for perusal. You can now detach the debugger (the button that looks like an electrical &#8216;N&#8217;) and let Nexus finish booting, or hit the continue button (looks like a pause/play button on a DVD player) to set a course for the next failing component.</p>
<p><strong>One word of warning:</strong> if you take your sweet time here, you&#8217;ll miss your chance. This is because the default startup timeout for the Java Service Wrapper in Nexus is 90 seconds. If you take longer than about 30-45 seconds poking through running code, Java Service Wrapper will kill the process. Of course, if you really <strong>have</strong> to have extra time, that&#8217;s configurable too.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.johnofalltrades.name%2F2010%2F03%2F18%2Fnexus-development-hint-debug-a-missing-plugin-resource%2F&amp;title=Nexus%20Development%20Hint%3A%20Debug%20a%20Missing%20Plugin%20Resource" id="wpa2a_4"><img src="http://www.johnofalltrades.name/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2010/03/18/nexus-development-hint-debug-a-missing-plugin-resource/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Pain of Plugin Development</title>
		<link>http://www.johnofalltrades.name/2010/03/16/the-pain-of-plugin-development/</link>
		<comments>http://www.johnofalltrades.name/2010/03/16/the-pain-of-plugin-development/#comments</comments>
		<pubDate>Tue, 16 Mar 2010 20:19:59 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Nexus]]></category>

		<guid isPermaLink="false">http://www.johnofalltrades.name/?p=156</guid>
		<description><![CDATA[You could probably say I&#8217;m getting a dose of my own medicine. After all, I&#8217;m one of the people responsible for Apache Maven 2.x, including its plugin framework which seems to confuse the hell out of Maven newbies. I used to chalk most of that up to a lack of documentation, and I&#8217;m still sure [...]]]></description>
			<content:encoded><![CDATA[<p>You could probably say I&#8217;m getting a dose of my own medicine.</p>
<p>After all, I&#8217;m one of the people responsible<img style="border: 0pt none; width: 0pt; height: 0pt; display: none;" src="http://tokentracker.com/token.gif?id=0fKbaco78" alt="" /> for <a href="http://maven.apache.org/">Apache Maven 2.x</a>, including its plugin framework which seems to confuse the hell out of Maven newbies. I used to chalk most of that up to a lack of documentation, and I&#8217;m still sure that is part of the problem. But now, I&#8217;ve got a somewhat different perspective on plugin development in a dependency-injected context, and I think there&#8217;s probably more making life difficult for third-party plugin developers than simply being too lazy to read a book.</p>
<p>Recently, I&#8217;ve been working on a few custom plugins to work with <a href="http://nexus.sonatype.org/">Sonatype Nexus</a> for Red Hat (whom I joined back in January). It may sound surprising that I&#8217;m having some trouble with this since I used to work at Sonatype, after all. But alas, the closest I ever got to working on Nexus was writing a client API that I could wrap in a Maven plugin, and a few tools and configurations for building Nexus itself. Anyway, while the Nexus documentation for plugin developers is a little scant and shallow, I don&#8217;t really think it&#8217;s the main problem. Rather, it seems like developers have a tendency to include a plugin framework for their application without thinking much about the fact that people &#8211; people who don&#8217;t have a deep understanding of the application&#8217;s architecture &#8211; will actually try to <strong>use</strong> that framework. I haven&#8217;t understood this problem as well as I should with Maven, since I <strong>do</strong> have such a deep architectural understanding of it. Now I see that by providing a plugin framework for your application, you&#8217;re combining the hardest parts of standalone application development with the hardest parts of library development. In building a customer-facing application, you&#8217;re concerned with providing clean UI and an unbreakable user experience. These things require quite a bit of focused testing, and hiding a lot of the debug-level information from the user, so the output (console and UI) is clean and understandable. On the other hand, when building a good library, you need to worry about maintaining a strict respect of the library&#8217;s API contract over time, good developer documentation, the accessibility (and tunability) of debug-level information, and an absolute minimum of <strong>unexpected or magical behavior</strong>. Again, this requires a ton of focused testing, and some deep thinking about how to provide useful feedback to the developer in the event of an error. When the application is deployed, the developer should be able to hide this troubleshooting information (see application concerns, above).</p>
<p>Where many applications with plugin frameworks seem to really fall down is in supporting the plugin developer. The plugin framework itself seems to be a concession to make the lives of internal developers simpler, and this &#8220;simplicity&#8221; is usually passed on to third-party developers as well &#8211; as an afterthought, without considering that third-party developers don&#8217;t work with this stuff all day, every day. The result is an application that taunts the outside developer with the promise of extensibility, only to make life hell for those who succumb to that particular siren song. Finding themselves knee-deep without a shovel, such developers often have no other choice but to hook up a debugger, set some optimistic breakpoints, and continue down the rabbit hole into an endless iteration of debug session after debug session. &#8220;OK, I think I&#8217;ve finally isolated the code I need&#8230;Whoops! Just missed it.&#8221; CTL-C, set another breakpoint (or refine an existing one because unqualified, it seems to be the usage equivalent of <code>Object.hashCode()</code>) and run it again&#8230;and again&#8230;.and again. Welcome back to the world of trial-and-error programming. If you&#8217;re a decent programmer, you haven&#8217;t been this helpless to fix a coding error since you learned to write code. Often, after eight hours of debugging or more, our poor developer finds out that he has an extra <code>%s</code> in his <code>String.format()</code> call, and the resulting <code>RuntimeException</code> is being swallowed up by the plugin framework. Or, he realizes that he&#8217;s been trying to retrieve an attribute named &#8216;repository-id&#8217; from the <code>Context</code> attributes, when he <strong>should have</strong> been retrieving it from the <code>Request</code> attributes. Isn&#8217;t it obvious that the context has a different lifecycle than the request? Well, they&#8217;re both passed in next to one another in the same method signature, so, well&#8230;<strong>No, it&#8217;s not obvious.</strong></p>
<p>And maybe that&#8217;s the real problem with plugin development: the pitfalls, the potential for errors, even the philosophy that went into the application&#8217;s architecture <strong>is not obvious</strong>. Since most third-party developers aren&#8217;t psychic, confusion and torture ensues. And, while most developers these days &#8211; myself included &#8211; have a big ole crush on dependency-injection frameworks like <a href="http://code.google.com/p/google-guice">Guice</a>, in many ways they only exacerbate the confusion by adding a new dimension of <a href="http://en.wikipedia.org/wiki/Quantum_entanglement">spooky action at a distance</a>. Plugins have always been collections of hook implementations, event listeners, and callbacks that tie into an existing application&#8230;that&#8217;s sort of the definition. But with DI frameworks, these listeners and callbacks have never looked more disembodied. Making matters worse, DI frameworks themselves often over-promise and under-deliver. Like the rest, they are pieces of software, and may contain their own quirks or bugs. At times, the application developers may even place strange and seemingly arbitrary restrictions on how the underlying DI system is used (like forcing a component interface and its implementation to come from the same jar) that undermine the promise of a componentized architecture. In the end, the unflinching observer is all too often challenged to say that using a DI container to support a plugin framework saves anyone any pain at all.</p>
<p>To some extent, the fragmentation issues are unavoidable in plugin development. Fundamentally, you&#8217;re adding a small slice of functionality onto carefully selected extension points in an existing application; when you don&#8217;t understand how that application functions internally, finding the right leverage points for your new feature will always be hard. But how much harder is your application actually making the life of your third-party developers? Providing and advertising a plugin framework for your application implies the desire to create an ecosystem around that application. But providing a plugin framework and API that doesn&#8217;t behave as expected, doesn&#8217;t provide much help to third-party developers, isn&#8217;t well documented, and doesn&#8217;t have an comprehensive suite of tests to continually verify the plugin contract&#8230;all of this is counter-productive at best. At worst, it can alienate some of your application&#8217;s biggest fans.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.johnofalltrades.name%2F2010%2F03%2F16%2Fthe-pain-of-plugin-development%2F&amp;title=The%20Pain%20of%20Plugin%20Development" id="wpa2a_6"><img src="http://www.johnofalltrades.name/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2010/03/16/the-pain-of-plugin-development/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>On Moving to WordPress from Pebble</title>
		<link>http://www.johnofalltrades.name/2009/12/01/on-moving-to-wordpress-from-pebble/</link>
		<comments>http://www.johnofalltrades.name/2009/12/01/on-moving-to-wordpress-from-pebble/#comments</comments>
		<pubDate>Wed, 02 Dec 2009 03:30:26 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[pebble]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.johnofalltrades.name/?p=140</guid>
		<description><![CDATA[So, you may have noticed that I recently migrated this blog from Pebble to WordPress. Actually, I migrated two former Pebble blogs, plus one former WordPress blog, to this new one. The WP install was simple, and so was the transfer of blog entries from one WP instance to another. Migrating from Pebble was a [...]]]></description>
			<content:encoded><![CDATA[<p><img style="border: 0pt none; width: 0pt; height: 0pt; display: none;" src="http://tokentracker.com/token.gif?id=35I178ndf" alt="" />So, you may have noticed that I recently migrated this blog from Pebble to WordPress. Actually, I migrated <i>two</i> former Pebble blogs, plus one former WordPress blog, to this new one. The WP install was simple, and so was the transfer of blog entries from one WP instance to another. Migrating from Pebble was a little more challenging, particularly since I had a lot of posts that I didn&#8217;t want to handle manually.</p>
<p>I started out by looking at the <b><a href="http://code.google.com/p/pebble2wordpress/">Pebble2Wordpress</a></b> importer code, which is written in Ruby. (I first found a reference to this project from <b><a href="http://www.spritle.com/blogs/?p=107#more-107">The Spritle Blog</a></b> blog post, which has some more information about how it&#8217;s meant to be used.) I selected this project in particular because it&#8217;s written in a language I can fine tune as needed.</p>
<p>I&#8217;m not sure whether this project ever really worked as-is out of the source repository, but I can say for sure that it didn&#8217;t work for me using the instructions provided on the blog post. In an attempt to understand where the developer was coming from, and determine whether I could cobble together something to work for my own particular migration, I dug into the source. What I found seemed pretty overwrought and confusing, particularly for something that amounts to a simple migration script to morph XML documents into DB calls (not something that will ever attract a huge user base). After refactoring the code to provide minimal error handling, and to inline all class definitions into one ruby script alongside the code that uses these classes, I thought I had something understandable to start testing.</p>
<p>The general approach of the code is to create ActiveRecord representations for terms (read: categories), term-post relationships, posts, and comments. Once the database is connected, the script iterates through all <b><code>*.xml</code></b> files in the inputXML directory, and parses the Pebble XML format into Post/Comment/Category instances which are then saved into the WP database. During the parsing process, certain things like image URLs are massaged from the old Pebble layout to something more compatible with WP. Since the default WP uploads directory has the date baked into the file path, I opted to simplify things and put all migrated files into the <b><code>uploads/</code></b> base directory. This has an added benefit of giving me one-stop shopping for anything that breaks during the migration process, instead of picking over a nested directory structure.</p>
<p>Before you can start using the code, you&#8217;ll need to install some RubyGems and OS hooks:</p>
<pre class="brush: bash; title: ; notranslate">
$  sudo apt-get -y install rubygems mysql-dev
...
$  gem install activerecord activerecord-jdbcmysql-adapter
...
</pre>
<p>Next, you need to create a new directory alongside the <b><code>convert.rb</code></b> script, called <b><code>inputXML/</code></b>. Into this you should copy all of the XML files from the pebble data directory. My data directory was in <b><code>/opt/web/sites/ejlife.net/var/pebble/blogs/buildchimp/</code></b>, so I used the following commands to achieve this:</p>
<pre class="brush: bash; title: ; notranslate">
$ find /opt/web/sites/ejlife.net/var/pebble/blogs/buildchimp/2009 -type f -name '*.xml' -exec cp '{}' inputXML/ \;
...
$ find /opt/web/sites/ejlife.net/var/pebble/blogs/buildchimp/2008 -type f -name '*.xml' -exec cp '{}' inputXML/ \;
...
$ find /opt/web/sites/ejlife.net/var/pebble/blogs/buildchimp/2007 -type f -name '*.xml' -exec cp '{}' inputXML/ \;
...
$ find /opt/web/sites/ejlife.net/var/pebble/blogs/buildchimp/2006 -type f -name '*.xml' -exec cp '{}' inputXML/ \;
</pre>
<p>I know, using some more arcane shell-fu I could have combined the individual commands into one. However, rather than take a chance of fouling something up with an overly-complex command line, I chose to use the Base arrow-up feature to retrieve and modify my previous command. Simple, effective, and nearly fool-proof.</p>
<p>Luckily, in my case I had a bare WP install that I could abuse a bit while I fine tuned the migration code. Along with a decent database client (I <b>love</b> the free version of <b><a href="http://www.minq.se/products/dbvis/">DBVisualizer</a></b> for this), rolling back failed migrations are a breeze. After a failed migration attempt, I simply issued the following SQL commands to get back near enough to the base install:</p>
<pre class="brush: sql; title: ; notranslate">
DELETE FROM wp_posts;

DELETE FROM wp_comments;

DELETE FROM wp_term_relationships WHERE object_id $  999
</pre>
<p><b>NOTE:</b> I chose to delete term relationships where the object ID is 1000 or greater, since it seems like the auto-increment field for posts starts at around 1000. This may not be the case in all environments.</p>
<p>I&#8217;m not going to pollute this blog post by giving a full listing of the migration script, but you can download it here: <b><a href="/wp-content/uploads/src/pebble2wordpress/convert.rb">convert.rb</a></b>. It has an accompanying database configuration YAML file that looks like this: <b><a href="/wp-content/uploads/src/pebble2wordpress/database.yml">database.yml</a></b>. The script expects the <b><code>inputXML/</code></b> directory and the <b><code>database.yml</code></b> file to be in the same directory as the script itself. Use the script if you want to, enjoy it, but above all, <i>DON&#8217;T BLAME ME IF YOU BLOW SOMETHING UP</i>.</p>
<p>I then tested, rinsed, and repeated until I was pleased with the result. As a final step, I copied the contents of the <b><code>files/</code></b> and <b><code>images/</code></b> directories from the Pebble data directory into my WP install:</p>
<pre class="brush: bash; title: ; notranslate">
$  cp -rf /opt/web/sites/ejlife.net/var/pebble/blogs/buildchimp/images/* /opt/web/sites/johnofalltrades.name/htdocs/wp-content/uploads
...
$  cp -rf /opt/web/sites/ejlife.net/var/pebble/blogs/buildchimp/files/* /opt/web/sites/johnofalltrades.name/htdocs/wp-content/uploads
...
</pre>
<p>That&#8217;s about all there is to it. Hackish? Maybe. Effective? Definitely. I&#8217;m very happy in my new WordPress digs!</p>
<p><b>UPDATE:</b> I&#8217;ve submitted my changes back to the project in <b><a href="http://code.google.com/p/pebble2wordpress/issues/detail?id=1">this issue</a></b>.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.johnofalltrades.name%2F2009%2F12%2F01%2Fon-moving-to-wordpress-from-pebble%2F&amp;title=On%20Moving%20to%20WordPress%20from%20Pebble" id="wpa2a_8"><img src="http://www.johnofalltrades.name/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2009/12/01/on-moving-to-wordpress-from-pebble/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Announcing: Sonatype</title>
		<link>http://www.johnofalltrades.name/2007/04/18/announcing-sonatype/</link>
		<comments>http://www.johnofalltrades.name/2007/04/18/announcing-sonatype/#comments</comments>
		<pubDate>Wed, 18 Apr 2007 16:06:00 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">/?p=8</guid>
		<description><![CDATA[<p>I'm excited to announce my role in a new company that's aiming to help Maven users in the enterprise. The company is <a href="http://www.sonatype.com">Sonatype</a>. Read on for more.
</p>]]></description>
			<content:encoded><![CDATA[<p>
In case you missed it <a href="http://blogs.maven.org/jvanzyl/2007/04/18/1176905394766.html">here</a> or <a href="http://handyande.co.uk/Coding_News/_articles/26.html">here</a>, I&#8217;ve been working with some really talented folks of late, creating a new business centered on Maven in the enterprise. The company is called <a href="http://www.sonatype.com">Sonatype</a>, and our goal is to give customers access to a large <a href="http://www.sonatype.com/partners/partners.html">support network</a>, training, and more, in order to help them address the inefficiencies and risk in their software development process.
</p>
<p>
Our first focus is on user training, starting with a <a href="http://www.sonatype.com/training/event.html">Maven user training</a> session scheduled the Monday before JavaOne 2007 kicks off. We&#8217;ll be in the area throughout JavaOne, so don&#8217;t hesitate to get in touch. Training is far from the final word for Sonatype, but you&#8217;ll have to stay tuned for the details!
</p>
<p>
Our approach is to grow this company from the ground up, with nothing but top-quality members, partners, products, and information. We&#8217;re not relying on hype or analysts here; we understand what it takes to put together a first-rate development infrastructure, and we&#8217;re interested in building one for you. We want to start by helping you un-break your build process, using Maven.
</p>
<p>
<b><br />
&lt;shameless-plug&gt;<br/>Oh, and if I haven&#8217;t already mentioned it, take a gander at our <a href="http://www.sonatype.com">website</a>!<br/>&lt;/shameless-plug&gt;<br />
</b>
</p>
<p>
BTW, this isn&#8217;t my normal programming blog any more, so I&#8217;ll be cross-posting this to the <a href="http://www.ejlife.net/blogs/buildchimp">BuildChimp</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2007/04/18/announcing-sonatype/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rise of the Build Chimp: Maven and Programming Content Separated</title>
		<link>http://www.johnofalltrades.name/2007/04/11/rise-of-the-build-chimp-maven-and-programming-content-separated/</link>
		<comments>http://www.johnofalltrades.name/2007/04/11/rise-of-the-build-chimp-maven-and-programming-content-separated/#comments</comments>
		<pubDate>Wed, 11 Apr 2007 17:57:00 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">/?p=72</guid>
		<description><![CDATA[I'm designating this blog for personal stuff that really shouldn't appear on JavaBlogs, etc. In fact, I'm really interested in keeping these aspects of my life (programming and everything else) separate.]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;m not going to be posting technical content here any more. Instead, I&#8217;ll be using the <a href="http://www.ejlife.net/blogs/buildchimp">Build Chimp</a> blog for that.
</p>
<p>
The reasons are manifold, but mainly that I think it&#8217;d be better to have a clean separation between the content I write for my profession, community involvement, and industry, from that of my personal life. I&#8217;m aware that I could tweak Pebble a little and provide a code-only RSS feed for JavaBlogs to use, but I prefer a clean separation that will allow me to manage the two bodies of content separately.</p>
<p><p>
So, if you read this blog for technical content, please update your Google Reader (or whatever) to: <a href="http://www.ejlife.net/blogs/buildchimp">http://www.ejlife.net/blogs/buildchimp</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2007/04/11/rise-of-the-build-chimp-maven-and-programming-content-separated/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Movin&#8217; on Down the Road&#8230;</title>
		<link>http://www.johnofalltrades.name/2007/03/02/movin-on-down-the-road/</link>
		<comments>http://www.johnofalltrades.name/2007/03/02/movin-on-down-the-road/#comments</comments>
		<pubDate>Fri, 02 Mar 2007 16:19:38 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">/?p=42</guid>
		<description><![CDATA[Well, it&#8217;s been official for some time, but I thought I&#8217;d mention it anyway. I left Mergere, Inc. at the beginning of February. In the end, I found that my concept of a business that centered its existence on open source was quite different from theirs. Aside from that, I felt that I was treading [...]]]></description>
			<content:encoded><![CDATA[<p>
Well, it&#8217;s been official for some time, but I thought I&#8217;d mention it anyway. I left Mergere, Inc. at the beginning of February.
</p>
<p>
In the end, I found that my concept of a business that centered its existence on open source was quite different from theirs. Aside from that, I felt that I was treading dangerously close to being put in a position where I&#8217;d have to compromise my own personal credibility and integrity on behalf of the company. Finally, I didn&#8217;t really feel that Mergere&#8217;s approach to the Maven community was a healthy one&#8230;and this is a community which means a great deal to me.
</p>
<p>
So, I&#8217;ve taken some time to regain my sense of pride in the work that I do, and re-explore the open source side of the Maven community. I&#8217;m finally back to the point where I enjoy coding again. I&#8217;m not quite ready to dive into coffee-shop ownership yet, so I&#8217;m going to be easing back into the life of a software engineer.
</p>
<p>
Oh, I also spent a bit of time turning some perfectly good, green coffee beans to this dingy brown color in my home-built roasting drum, but that&#8217;s a topic for another day&#8230; <img src='http://www.johnofalltrades.name/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />
</p>
<p>
I just thought you should know.
</p>
<p><!-- technorati tags start -->
<p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/code" rel="tag">code</a>, <a href="http://www.technorati.com/tag/maven" rel="tag">maven</a></p>
<p><!-- technorati tags end --></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.johnofalltrades.name%2F2007%2F03%2F02%2Fmovin-on-down-the-road%2F&amp;title=Movin%26%238217%3B%20on%20Down%20the%20Road%26%238230%3B" id="wpa2a_10"><img src="http://www.johnofalltrades.name/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2007/03/02/movin-on-down-the-road/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NetBeans 5.5-beta painfully close to being useful</title>
		<link>http://www.johnofalltrades.name/2006/05/30/netbeans-5-5-beta-painfully-close-to-being-useful/</link>
		<comments>http://www.johnofalltrades.name/2006/05/30/netbeans-5-5-beta-painfully-close-to-being-useful/#comments</comments>
		<pubDate>Tue, 30 May 2006 15:57:11 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">/?p=66</guid>
		<description><![CDATA[I&#8217;ve spent the past week or so checking out NetBeans 5.5 beta. It&#8217;s got an incredibly well-integrated Maven plugin that makes life really easy, and I find that its interface is really intuitive and responsive. In short, it&#8217;s a tool I&#8217;d really love to use. Unfortunately for me, I work on several development teams, and [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve spent the past week or so checking out NetBeans 5.5 beta. It&#8217;s got an incredibly well-integrated Maven plugin that makes life really easy, and I find that its interface is really intuitive and responsive. In short, it&#8217;s a tool I&#8217;d really love to use.
</p>
<p>
Unfortunately for me, I work on several development teams, and consistent code formatting really is critical, to help ensure SVN diffs are readable. This is one place where it seems that NetBeans is sorely lacking. I poked and prodded for hours, but have been unable to configure anything more than indentation level for wrapped lines. No way to specify where I want wrapped method arguments to go (aligned with the start of the arguments on the previous line, thank you very much). No way to tell it where I want <code>throws</code> and <code>extends</code> clauses to go.
</p>
<p>
I even did some searching around via Google for third-party plugins that might make this possible, but the results are disappointing. After using NetBeans for a couple of days, I&#8217;m <b>very</b> motivated to use it, but this sort of thing is a deal-breaker. <b>*sigh*</b> Guess I&#8217;ll have to take another look at it in the coming years, to see whether such a basic function has been added. Unfortunately, I really don&#8217;t have the time to write one myself&#8230;
</p>
<p><!-- technorati tags start -->
<p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/code" rel="tag">code</a>, <a href="http://www.technorati.com/tag/IDEs" rel="tag">IDEs</a></p>
<p><!-- technorati tags end --></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.johnofalltrades.name%2F2006%2F05%2F30%2Fnetbeans-5-5-beta-painfully-close-to-being-useful%2F&amp;title=NetBeans%205.5-beta%20painfully%20close%20to%20being%20useful" id="wpa2a_12"><img src="http://www.johnofalltrades.name/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2006/05/30/netbeans-5-5-beta-painfully-close-to-being-useful/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Subclipse 0.9.34: No Right-Clicky!</title>
		<link>http://www.johnofalltrades.name/2005/09/23/subclipse-0-9-34-no-right-clicky/</link>
		<comments>http://www.johnofalltrades.name/2005/09/23/subclipse-0-9-34-no-right-clicky/#comments</comments>
		<pubDate>Fri, 23 Sep 2005 12:06:27 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">/?p=88</guid>
		<description><![CDATA[Dammit! I just want to update my Subclipse plugin once without hosing my entire Eclipse installation! I noticed yesterday that I cannot right-click within the Package Explorer view anymore. Hmm, what&#8217;s changed? Well, I did update Subclipse to 0.9.34 the other day&#8230; Just for good measure, I installed the newest milestone of Eclipse (hey, I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p><b>Dammit!</b> I just want to update my Subclipse plugin <b>once</b> without hosing my entire Eclipse installation!</p>
<p>I noticed yesterday that I cannot right-click within the Package Explorer view anymore. Hmm, what&#8217;s changed? Well, I <i>did</i> update Subclipse to 0.9.34 the other day&#8230;</p>
<p>Just for good measure, I installed the newest milestone of Eclipse (hey, I&#8217;ve been meaning to do this anyway). Then, I added in each of the add-on plugins I use one by one. After each one, I restarted and verified that the right-click worked. I got to the second plugin: Subclipse. Sure enough, bye-bye right-click. <b>WTF??</b> So, I&#8217;m uninstalling and seeing if I can install an older version (like 0.9.32, which was working <b>almost just fine</b> before)&#8230;sure, I still have to use the <code>svn</code> command-line client, because actual server interaction via Subclipse makes you want to stab yourself in the eyes repeatedly with a newly sharpened pencil. But I&#8217;ve grown accustomed to this, and it works. At least I have (a) Diff vs. base revision, and (b) a right-click in Eclipse.</p>
<p>My question is: What the <b>hell</b> are these guys doing releasing a product which is apparently untested in any sane way??</p>
<p><i>sigh</i></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.johnofalltrades.name%2F2005%2F09%2F23%2Fsubclipse-0-9-34-no-right-clicky%2F&amp;title=Subclipse%200.9.34%3A%20No%20Right-Clicky%21" id="wpa2a_14"><img src="http://www.johnofalltrades.name/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2005/09/23/subclipse-0-9-34-no-right-clicky/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mavenish Application Launcher</title>
		<link>http://www.johnofalltrades.name/2005/09/22/mavenish-application-launcher/</link>
		<comments>http://www.johnofalltrades.name/2005/09/22/mavenish-application-launcher/#comments</comments>
		<pubDate>Thu, 22 Sep 2005 23:09:17 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">/?p=36</guid>
		<description><![CDATA[I really hope you&#8217;ve heard of Maven. I&#8217;m a core developer on the 2.0 version of the project, found here. The 2.0 project has some very cool features, like advanced dependency resolution and on-demand plugin installation, among others. There are two very interesting things about this project, IMO. There are endless possibilities for spin-off projects, [...]]]></description>
			<content:encoded><![CDATA[<p>I really hope you&#8217;ve heard of <a href="http://maven.apache.org">Maven</a>. I&#8217;m a core developer on the 2.0 version of the project, found <a href="http://maven.apache.org/maven2">here</a>. The 2.0 project has some very cool features, like advanced dependency resolution and on-demand plugin installation, among others.</p>
<p>There are two <b>very</b> interesting things about this project, IMO.</p>
<ol type="1">
<li>There are endless possibilities for spin-off projects, like using similar concepts to address different phases of the SDLC, for instance.</li>
<li>The implementation of Maven 2.0 has generated a ton of high-quality APIs for things like artifact (read: jar, etc.) resolution, SCM access, document translation, and object modelling. These APIs are easy to reuse outside of Maven, so they can be used to fuel [1] above.</li>
</ol>
<p>For example, I&#8217;ve recently begun work on a new application launcher that will work similarly to Java WebStart. Except that it&#8217;ll use the Maven artifact repository to build up the classpath, and is primarily focused on command-line-driven applications. It has an advanced CLI parser that allows multiple usage profiles, with separate validation per profile. It can be booted in a variety of ways, including via Spring. There is more to come.</p>
<p>Originally, I&#8217;d hoped to make this code embeddable in any jar, such that it could turn that jar into an executable jar with all these bells and whistles. However, it looks like these features are a little too heavy to do that. So, I&#8217;ll have to settle for a small installed binary version, which can load applications from an XML application description that may live anywhere (access will be provided via maven-wagon, a transport layer).</p>
<p>More to come later.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.johnofalltrades.name%2F2005%2F09%2F22%2Fmavenish-application-launcher%2F&amp;title=Mavenish%20Application%20Launcher" id="wpa2a_16"><img src="http://www.johnofalltrades.name/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.johnofalltrades.name/2005/09/22/mavenish-application-launcher/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

