<?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>Mike Desjardins&#039; Series of Tubes &#187; programming</title>
	<atom:link href="http://www.mikedesjardins.net/content/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mikedesjardins.net/content</link>
	<description>freelance software developer consultant in portland, maine</description>
	<lastBuildDate>Mon, 28 Jun 2010 13:43:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Test your EJBs with JMeter</title>
		<link>http://www.mikedesjardins.net/content/2008/12/test-your-ejbs-with-jmeter/</link>
		<comments>http://www.mikedesjardins.net/content/2008/12/test-your-ejbs-with-jmeter/#comments</comments>
		<pubDate>Tue, 23 Dec 2008 02:14:21 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[ejb]]></category>
		<category><![CDATA[ejb3]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jmeter]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/?p=196</guid>
		<description><![CDATA[Note: This is my first blog post on my newly upgraded Wordpress blog (prior to this, I used Blogger).  Hopefully everything goes OK!
Sometimes it&#8217;s helpful to do some performance benchmarks on your EJBs.  There are a few different ways to do this, but I&#8217;ve found that Apache&#8217;s JMeter is an excellent tool for [...]]]></description>
			<content:encoded><![CDATA[<p><em>Note: This is my first blog post on my newly upgraded Wordpress blog (prior to thi</em><em><img class="alignright size-thumbnail wp-image-198" title="jaguar-tachometer.jpg" src="http://mikedesjardins.us/wordpress/wp-content/uploads/2008/12/jaguar-tachometer-150x150.jpg" alt="jaguar-tachometer.jpg" width="150" height="150" /></em><em>s, I used </em><em>Blogger).  Hopefully everything goes OK!</em></p>
<p>Sometimes it&#8217;s helpful to do some performance benchmarks on your EJBs.  There are a few different ways to do this, but I&#8217;ve found that Apache&#8217;s <a href="http://jakarta.apache.org/jmeter">JMeter</a> is an excellent tool for benchmarking.  Unfortunately, JMeter doesn&#8217;t come with a general-purpose sampler for testing arbitrary EJBs.  Luckily, it isn&#8217;t very difficult to create one.</p>
<p>For this article, I&#8217;m using the JBoss application server to host my EJBs.  The process for using other containers should be quite similar.</p>
<h3>1.) Create a factory to lookup your EJBs.</h3>
<p>The first thing that you&#8217;ll probably want to do is create a simple singleton factory class to create instances of your EJB client for your test.  I use something like the following:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MyServiceFactory <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> Log log <span style="color: #339933;">=</span> LogFactory.<span style="color: #006633;">getLog</span><span style="color: #009900;">&#40;</span>MyServiceFactory.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> MyService service<span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> MyServiceFactory me<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> MyServiceFactory<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #009900;">&#123;</span>
    MyServiceFactory.<span style="color: #006633;">me</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MyServiceFactory<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> MyServiceFactory getInstance<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> MyServiceFactory.<span style="color: #006633;">me</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> MyService getService<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>MyService.<span style="color: #006633;">service</span> <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #666666; font-style: italic;">// Get the remote interface of the music search service</span>
      <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
        log.<span style="color: #006633;">info</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Loading the service...&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// JNDI the old-fashioned way:</span>
        <span style="color: #003399;">Context</span> ctx <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">InitialContext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        service <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>MyService<span style="color: #009900;">&#41;</span>ctx.<span style="color: #006633;">lookup</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;MyAction/remote&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>service <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          log.<span style="color: #006633;">error</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Didn't get the service!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">NamingException</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        log.<span style="color: #006633;">error</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Error looking up the remote service&quot;</span>, e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">return</span> service<span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>2.) Write the test</h3>
<p>Next, we&#8217;ll need to write the test itself.  To do this, we&#8217;ll extend the AbstractJavaSamplerClient class in JMeter&#8217;s org.apache.jmeter.protocol.java.sampler package.  This abstract class has a runTest method that we will override, and this method implements the actual test.   We will also override the getDefaultParameters method to provide some reasonable defaults values which will be displayed in JMeter&#8217;s GUI application.</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">us.mikedesjardins.demo.jmeter</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jmeter.config.Arguments</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jmeter.protocol.java.sampler.JavaSamplerContext</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.jmeter.samplers.SampleResult</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> DigitalContentServiceEJBTestSampler <span style="color: #000000; font-weight: bold;">extends</span> AbstractJavaSamplerClient <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> SampleResult runTest<span style="color: #009900;">&#40;</span>JavaSamplerContext context<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    SampleResult results <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SampleResult<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    MyService service <span style="color: #339933;">=</span> MyServiceFactory.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getService</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    results.<span style="color: #006633;">sampleStart</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #003399;">Long</span> param1 <span style="color: #339933;">=</span> context.<span style="color: #006633;">getLongParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;PARAM_1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #003399;">String</span> param2 <span style="color: #339933;">=</span> context.<span style="color: #006633;">getStringParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;PARAM_2&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    MyResult result <span style="color: #339933;">=</span> service.<span style="color: #006633;">myMethod</span><span style="color: #009900;">&#40;</span>param1, param2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>result <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       results.<span style="color: #006633;">setSuccessful</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
       results.<span style="color: #006633;">setResponseCodeOK</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
       results.<span style="color: #006633;">setResponseMessage</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;'myResult:&quot;</span> <span style="color: #339933;">+</span> myResult<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
       results.<span style="color: #006633;">setSuccessful</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    results.<span style="color: #006633;">sampleEnd</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">return</span> results<span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> Arguments getDefaultParameters<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    Arguments args <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Arguments<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    args.<span style="color: #006633;">addArgument</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;PARAM_1&quot;</span>, <span style="color: #0000ff;">&quot;4815162342&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    args.<span style="color: #006633;">addArgument</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;PARAM_2&quot;</span>, <span style="color: #0000ff;">&quot;Iculus&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">return</span> args<span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>3.) Setup JMeter</h3>
<p>JMeter&#8217;s extra libs directory is ${JMETER_INSTALL_LIB}/lib/ext.  Into that directory you will need to copy any jars that your EJB client will need.  In you&#8217;re using JBoss, you will want to copy the jbossall-client.jar into that directory as well (for the JNDI client and other remoting goodies) &#8211; presumably other application servers have similar client jar files available.</p>
<p>When you fire up JMeter, your new sampler should appear in the Samplers menu.  Enjoy!</p>
<p><em>Photo Credit: <a href="http://flickr.com/people/billjacobus1/">Bill Jacobus</a></em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/12/test-your-ejbs-with-jmeter/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Eight Rules of Conference Call Etiquette</title>
		<link>http://www.mikedesjardins.net/content/2008/09/eight-rules-of-conference-call/</link>
		<comments>http://www.mikedesjardins.net/content/2008/09/eight-rules-of-conference-call/#comments</comments>
		<pubDate>Mon, 29 Sep 2008 20:29:00 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[career]]></category>
		<category><![CDATA[industry]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/2008/09/eight-rules-of-conference-call-etiquette/</guid>
		<description><![CDATA[At my past few jobs, I&#8217;ve had to spend a lot of time on conference calls with developers and project managers.  While I don&#8217;t profess to be a &#8220;conference call expert&#8221; (or, for that matter, an etiquette expert), I think there are some general ground rules for conference calls, and I&#8217;m going to deviate [...]]]></description>
			<content:encoded><![CDATA[<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/conference-call-746961.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/conference-call-746944.jpg" alt="" border="0" /></a>At my past few jobs, I&#8217;ve had to spend a lot of time on conference calls with developers and project managers.  While I don&#8217;t profess to be a &#8220;conference call expert&#8221; (or, for that matter, an etiquette expert), I think there are some general ground rules for conference calls, and I&#8217;m going to deviate a bit from my usual Hibernate/JEE topics to itemize the ones that I think are important.</p>
<p>At my current job, I&#8217;m actually pretty lucky.  Almost all of us work remotely, so we&#8217;re pretty accustomed to how to behave in the ubiquitous con-call.  At a previous engagement, I wasn&#8217;t so lucky &#8211; I&#8217;ll omit their names to protect the guilty.</p>
<p>So here&#8217;s an arbitrary list from me, a random guy on the internet of questionable credentials, of what you should and shouldn&#8217;t do on a conference call.  Some of these probably seem really obvious, but I&#8217;m listing even the obvious ones because some people still break them:</p>
<p><span style="font-weight: bold;">1.) Use the Mute Button, especially on a speakerphone.</span> The most important reason for using Mute is to prevent echo-y feedback, particularly on speaker phones.  If you aren&#8217;t talking, please put your speaker phone on mute for the sake of everyone else listening.  Note that following this rule will invariably lead to the embarrassing situation where you start talking and don&#8217;t realize that you&#8217;ve left your phone on mute.  Don&#8217;t worry, we&#8217;ve all done it and we&#8217;ll all forgive you!<br /><span style="font-weight: bold;">2.) Introduce yourself when you enter the conference.</span>  Some conference systems will force you to state your name when you log in, and then the robo-operator will announce you when you join.  I actually find this to be quite jarring, especially when robo-operator interrupts what everyone is saying.  Better systems will play a quiet tone when people enter or leave the call.  Some, like one that a client had at my previous job, will do nothing at all.  This would allow people to lurk on the line unbeknownst to the participants, which is <span style="font-style: italic;">terribly</span> rude.  Likewise, if you enter a conference room while a conference call is already underway, announce yourself at the next free moment.  Ideally, the moderator of the conference will also take a moment to introduce everybody at the beginning of the call if there is a chance that everyone doesn&#8217;t know each other.  This is a <span style="font-style: italic;">great idea</span>.<br /><span style="font-weight: bold;">3.) Close the Door.</span>  It&#8217;s best to go to a closed room to join a conference call to eliminate background noise.  If you can go to such a place, do it.  Don&#8217;t join a conference call from, e.g., a street cafe or airport gate.  In doing so you risk a passing ambulance, street parade, or TSA threats to destroy unattended luggage interrupting the call.<br /><span style="font-weight: bold;">4.) Don&#8217;t use a mobile phone if you can help it.</span>  Occasionally you can get away with using a mobile for a con-call in a pinch.  But if it&#8217;s a super-important meeting where you are trying to make an impression or do something complicated, nothing will be more frustrating than a garbled, broken up, or dropped call.  Try to use a land-line if you can.<br /><span style="font-weight: bold;">5.) Don&#8217;t eat on the phone.</span>  I guess this is just a personal pet peeve of mine.  I can&#8217;t even listen to NPR if the announcer&#8217;s voice is all moist and saliva-sounding.  This is more important if you&#8217;re wearing a headset.<br /><span style="font-weight: bold;">6.) Have an agenda that everyone receives beforehand.</span>  This goes for all meetings, but it&#8217;s just as critical for a conference call. This helps you set expectations and stay on-topic during the call.<br /><span style="font-weight: bold;">7.) Get some screen-sharing software.</span>  Better yet, get some screen sharing software and test it out before the meeting.  With it, you can use something as simple as Notepad or TextMate as a virtual whiteboard.  For some reason, we never did this at my previous jobs.  We&#8217;ve done it at my current job and it works great.<br /><span style="font-weight: bold;">8.) Pick a good time for all participants. </span> This is particularly important if you&#8217;re working in different time zones.  Generally you can depend on developers being available between 10am and 4pm in their respective time zones &#8211; you can argue that programmers need to grow up and work regular business hours like everyone else.  But until the voodoo of deadline creation becomes a perfected science, software people will need to occasionally work late into the night or early in the morning to meet schedules.  Or (like anyone else) we may have daycare responsibilities and have to leave a little early.  So we stay flexible.  This means that if you&#8217;re working on, e.g., both coasts of the United States, your best bet is between 1pm and 3pm, eastern time.  If you&#8217;re working in the U.S. and the far east, you&#8217;re usually stuck with getting the U.S. participants to work early, and the others late in their workday.  Similarly between Europe and the U.S., the U.S. participants will probably need to be available late in the day, and the Europeans earlier.</p>
<p>What do you think?  Have I missed any conference call ground rules?</p>
<p><span style="font-style: italic;">Photo Credit: </span><a style="font-style: italic;" href="http://flickr.com/people/spcummings/">Stephen Cummings</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/09/eight-rules-of-conference-call/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Hibernate Tools: Tips for Reverse Engineering at the Command Line</title>
		<link>http://www.mikedesjardins.net/content/2008/08/hibernate-tools-tips-for-reverse/</link>
		<comments>http://www.mikedesjardins.net/content/2008/08/hibernate-tools-tips-for-reverse/#comments</comments>
		<pubDate>Tue, 05 Aug 2008 17:24:00 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[hibernate]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jpa]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/?p=32</guid>
		<description><![CDATA[One of the ancillary projects of the Hibernate framework is the Hibernate Tools toolset.  Using Hibernate Tools, you can automatically generate your mapping files (or, if you prefer, JPA annotations), POJOs, and DDL from your database schema.
I&#8217;ve been enamored with the &#8220;Convention over Configuration&#8221; web frameworks lately (e.g., Grails, Django), and wondered how hard [...]]]></description>
			<content:encoded><![CDATA[<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/tools-geishaboy500-716138.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/tools-geishaboy500-716103.jpg" alt="" border="0"></a>One of the ancillary projects of the Hibernate framework is the <a href="http://www.hibernate.org/255.html">Hibernate Tools</a> toolset.  Using Hibernate Tools, you can automatically generate your mapping files (or, if you prefer, JPA annotations), POJOs, and DDL from your database schema.</p>
<p>I&#8217;ve been enamored with the &#8220;Convention over Configuration&#8221; web frameworks lately (e.g., Grails, Django), and wondered how hard it&#8217;d be to reproduce some of their magic ORM functionality using Hibernate Tools.  I&#8217;ve concluded that I&#8217;ve still got a <font style="font-weight: bold;">long</font> ways to go, but that I might have some worthwhile tips to share in the meantime.</p>
<p>My progress has been impeded a bit because the documentation for Hibernate Tools is pretty weak.  Hibernate Tools was really generated with Eclipse users in mind.  A large portion of the documentation is devoted to explaining how to use the IDE.  I&#8217;m not using Eclipse, and I intend to use the tools at the command-line, and command-line use really isn&#8217;t targeted.</p>
<p><font style="font-weight: bold;">0.) Get the tools and dependencies.</font><br />I&#8217;m still in the dark ages &#8211; I use ant instead of maven for builds, and need to track down jar dependencies the old fashioned way.  In addition to the usual Hibernate jars, you&#8217;ll also need <a href="http://www.hibernate.org/30.html">hibernate-tools</a>, <a href="http://freemarker.sourceforge.net/">freemarker</a>, and <a href="http://jtidy.sourceforge.net/download.html">jtidy</a>.</p>
<p><font style="font-weight: bold;"><br />
1.) Setup an Ant task</font><br />This is pretty straightforward, and it is explained fairly well in the documentation.  First, define yourself a Hibernate Tools task.  Mine looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;taskdef</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;hibernatetool&quot;</span> <span style="color: #000066;">classname</span>=<span style="color: #ff0000;">&quot;org.hibernate.tool.ant.HibernateToolTask&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;classpath<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fileset</span> <span style="color: #000066;">refid</span>=<span style="color: #ff0000;">&quot;hibernate.libs&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fileset</span> <span style="color: #000066;">refid</span>=<span style="color: #ff0000;">&quot;hibernatetools.libs&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fileset</span> <span style="color: #000066;">refid</span>=<span style="color: #ff0000;">&quot;app.libs&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fileset</span> <span style="color: #000066;">refid</span>=<span style="color: #ff0000;">&quot;compile.libs&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;pathelement</span> <span style="color: #000066;">path</span>=<span style="color: #ff0000;">&quot;${build}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;pathelement</span> <span style="color: #000066;">path</span>=<span style="color: #ff0000;">&quot;${basedir}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span> 
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/classpath<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/taskdef<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Next, create a task that uses our new definition.  We&#8217;re going to be creating the mapping files and POJOs in this example.  It will look something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;gen_hibernate&quot;</span> <span style="color: #000066;">depends</span>=<span style="color: #ff0000;">&quot;compile&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span> 
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;delete</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;mkdir</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hibernatetool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jdbcconfiguration</span> </span>
<span style="color: #009900;">        <span style="color: #000066;">configurationfile</span>=<span style="color: #ff0000;">&quot;${src}/hibernate-connection.cfg.xml&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">revengfile</span>=<span style="color: #ff0000;">&quot;hibernate.reveng.xml&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">packagename</span>=<span style="color: #ff0000;">&quot;us.mikedesjardins.data&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">detectmanytomany</span>=<span style="color: #ff0000;">&quot;true&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">detectoptimisticlock</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hbm2hbmxml</span> <span style="color: #000066;">destdir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>  
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hbm2java</span> <span style="color: #000066;">destdir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;jdk5&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;ejb3&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/hbm2java<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/hibernatetool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/target<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>You&#8217;ll note that I&#8217;ve created a hibernate configuration file above which only contains connection information.  This is because I ran into problems when I tried to use a hibernate configuration with cache configuration elements in it.  You&#8217;ll also note a reference to a file called hibernate.reveng.xml.  This file controls various aspects of the reverse engineering process.  Mine is very simple &#8211; I&#8217;m working with MS SQL Server, and I don&#8217;t want it to include any of the system tables which begin with the prefix sys:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hibernate-reverse-engineering<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #808080; font-style: italic;">&lt;!-- Eliminate system tables  --&gt;</span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;table-filter</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;sys.*&quot;</span> <span style="color: #000066;">exclude</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/hibernate-reverse-engineering<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>That should be all that you need to do to get started.  When you run this ant target, your domain object POJOs and Mappings should end up in the ${genhbm} directory.</p>
<p><font style="font-weight: bold;">2.) First Problem &#8211; Table Names</font><br />Let&#8217;s say you&#8217;re in a company that prefixes most of it&#8217;s tables with something silly, like &#8220;tb_&#8221;.  In that case, Hibernate tools will happily create all kinds of POJOs for you named TbAccount, TbAddress, etc.  This is probably not what you want.  Fortunately, Hibernate tools let you provide your own &#8220;Reverse Engineering Strategy&#8221; class to deal with situations just like this.</p>
<p>First, update your build target in Ant to include a reference to your strategy class as an attribute of the jdbcconfiguration element:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;gen_hibernate&quot;</span> <span style="color: #000066;">depends</span>=<span style="color: #ff0000;">&quot;compile&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span> 
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;delete</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;mkdir</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hibernatetool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jdbcconfiguration</span> </span>
<span style="color: #009900;">        <span style="color: #000066;">configurationfile</span>=<span style="color: #ff0000;">&quot;${src}/hibernate-connection.cfg.xml&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">revengfile</span>=<span style="color: #ff0000;">&quot;hibernate.reveng.xml&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">packagename</span>=<span style="color: #ff0000;">&quot;us.mikedesjardins.data&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">detectmanytomany</span>=<span style="color: #ff0000;">&quot;true&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">detectoptimisticlock</span>=<span style="color: #ff0000;">&quot;true&quot;</span> </span>
<span style="color: #009900;">        <span style="color: #000066;">reversestrategy</span>=<span style="color: #ff0000;">&quot;us.mikedesjardins.hibernate.CustomReverseEngineeringStrategy&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hbm2hbmxml</span> <span style="color: #000066;">destdir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>  
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hbm2java</span> <span style="color: #000066;">destdir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;jdk5&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;ejb3&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/hbm2java<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/hibernatetool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/target<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Next, we&#8217;ll need to create the strategy class.  The documentation recommends that you extend the <font style="font-weight: bold;">DelegatingReverseEngineeringStrategy</font> class to do this, like this:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">us.mikedesjardins.hibernate</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.hibernate.cfg.reveng.DelegatingReverseEngineeringStrategy</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.hibernate.cfg.reveng.ReverseEngineeringStrategy</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> CustomReverseEngineeringStrategy <span style="color: #000000; font-weight: bold;">extends</span> DelegatingReverseEngineeringStrategy <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> CustomReverseEngineeringStrategy<span style="color: #009900;">&#40;</span>ReverseEngineeringStrategy delegate <span style="color: #009900;">&#123;</span> 
    <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>delegate<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Unfortunately, I was unable to find any JavaDoc documentation for the Hibernate Tools classes, so I had to do a bit of trial-and-error.  It turns out there is a method called tableToClassName that can be overridden.  This class accepts a TableIdentifier as its input parameter, and returns the class name in a String.  Thus, to remove the tb_ from the class, we could do something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> tableToClassName<span style="color: #009900;">&#40;</span>TableIdentifier tableIdentifier<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #003399;">String</span> packageName <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;us.mikedesjardins.data&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #003399;">String</span> className <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">super</span>.<span style="color: #006633;">tableToClassName</span><span style="color: #009900;">&#40;</span>tableIdentifier<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>className.<span style="color: #006633;">startsWith</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Tb&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    className <span style="color: #339933;">=</span> className.<span style="color: #006633;">substring</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000000; font-weight: bold;">return</span> className<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Compile your CustomReverseEngineeringStrategy class, make sure it&#8217;s on the hibernatetools task definition&#8217;s classpath, and re-run the task.  Voila!  The Tb&#8217;s are gone!</p>
<p>There&#8217;s a similar method for column names named <font style="font-weight: bold;">columnToPropertyName</font> that handles naming your persisted class&#8217;s member variables.  In my current project, the primary key columns are named the same as the table name, with &#8220;_id&#8221; appended to the end.  However, in the object model, we like to just name the primary key property &#8220;id&#8221; to simplify the creation of generic DAOs.  I use the columnToPropertyName method for this.</p>
<p><font style="font-weight: bold;">2.) Next Problem &#8211; The Generated POJOs need tweaking.</font><br />Perhaps the code that Hibernate generates is not to your liking.  Maybe you work with standards-compliance-nazis who want a copyright header at the top of each class file.  Or maybe all of your persisted objects implement the same interface for use with generic DAOs.</p>
<p>Under the covers, Hibernate uses <a href="http://freemarker.sourceforge.net/">freemarker</a> to generate POJOs and mapping files.  The templates that it uses can be edited to your liking, but doing it is not very straightforward.</p>
<p>First, unzip the hibernate tools jar into a temporary directory.  Once unzipped, you&#8217;ll find a directory named pojo.  This directory contains all of the templates used for POJO generation.  Copy that directory into your build area and name it something like hib_templates.</p>
<p>The hbm2java task is actually just an alias for another hibernate tools target called hbmtemplate.  With hbmtemplate, you can configure the location of the source templates.  So we&#8217;ll remove the hbm2java task from the gen_hibernate target, and replace it with an equivalent hbmtemplate task:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;gen_hibernate&quot;</span> <span style="color: #000066;">depends</span>=<span style="color: #ff0000;">&quot;compile&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span> 
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;delete</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;mkdir</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hibernatetool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jdbcconfiguration</span> </span>
<span style="color: #009900;">        <span style="color: #000066;">configurationfile</span>=<span style="color: #ff0000;">&quot;${src}/hibernate-connection.cfg.xml&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">revengfile</span>=<span style="color: #ff0000;">&quot;hibernate.reveng.xml&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">packagename</span>=<span style="color: #ff0000;">&quot;us.mikedesjardins.data&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">detectmanytomany</span>=<span style="color: #ff0000;">&quot;true&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">detectoptimisticlock</span>=<span style="color: #ff0000;">&quot;true&quot;</span> </span>
<span style="color: #009900;">        <span style="color: #000066;">reversestrategy</span>=<span style="color: #ff0000;">&quot;us.mikedesjardins.hibernate.CustomReverseEngineeringStrategy&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
     <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hbm2hbmxml</span> <span style="color: #000066;">destdir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>  
     <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hbmtemplate</span> <span style="color: #000066;">templateprefix</span>=<span style="color: #ff0000;">&quot;pojo/&quot;</span></span>
<span style="color: #009900;">              <span style="color: #000066;">destdir</span>=<span style="color: #ff0000;">&quot;${genhbm}&quot;</span></span>
<span style="color: #009900;">              <span style="color: #000066;">template</span>=<span style="color: #ff0000;">&quot;hib_templates/Pojo.ftl&quot;</span></span>
<span style="color: #009900;">              <span style="color: #000066;">filepattern</span>=<span style="color: #ff0000;">&quot;{package-name}/{class-name}.java&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
       <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;jdk5&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
       <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;ejb3&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/hbmtemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/hibernatetool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/target<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Now that we&#8217;ve told hibernate tools where our template lives, we can edit it to our liking.  For example, if we want to add a copyright notice to the top of each generated POJO, we could do so thusly:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//</span>
<span style="color: #666666; font-style: italic;">// Copyright 2008 Big Amalgamated Mega Global Software Corp.  All Rights Reserved.</span>
<span style="color: #666666; font-style: italic;">//</span>
$<span style="color: #009900;">&#123;</span>pojo.<span style="color: #006633;">getPackageDeclaration</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span>
<span style="color: #666666; font-style: italic;">// Generated ${date} by Hibernate Tools ${version}</span>
&nbsp;
<span style="color: #339933;">&lt;</span>#assign classbody<span style="color: #339933;">&gt;</span>
<span style="color: #339933;">&lt;</span>#include <span style="color: #0000ff;">&quot;PojoTypeDeclaration.ftl&quot;</span><span style="color: #339933;">/&gt;;</span> <span style="color: #009900;">&#123;</span>
.
.
.
<span style="color: #009900;">&#40;</span>etc<span style="color: #009900;">&#41;</span></pre></div></div>

<p>Now that we&#8217;ve done this, we can create more templates that, e.g., generate empty DAO classes, automatically create derived classes, etc.</p>
<p>Hope that helps!</p>
<p><font style="font-style: italic;">Photo Credit: </font><a style="font-style: italic;" href="http://flickr.com/people/geishaboy500/">geishaboy500</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/08/hibernate-tools-tips-for-reverse/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Twenty minutes with Hibernate Search; A Cheesy Example</title>
		<link>http://www.mikedesjardins.net/content/2008/07/twenty-minutes-with-hibernate-search-a-cheesy-example/</link>
		<comments>http://www.mikedesjardins.net/content/2008/07/twenty-minutes-with-hibernate-search-a-cheesy-example/#comments</comments>
		<pubDate>Sat, 12 Jul 2008 15:48:00 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[hibernate]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jpa]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/?p=31</guid>
		<description><![CDATA[In a recent post, I showed a trick for determining which users in a system are running a long-running query.  One commenter suggested that using a full-text search system made a lot of sense in those situations, and I wholeheartedly agree. So I decided to devote a new post to Hibernate Search!
In this example, [...]]]></description>
			<content:encoded><![CDATA[<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/cheese-blog-719088.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/cheese-blog-719057.jpg" alt="" border="0" /></a>In a <a href="http://mikedesjardins.us/blog/2008/06/who-is-running-that-horrible-hibernate.html">recent post</a>, I showed a trick for determining which users in a system are running a long-running query.  One commenter suggested that using a full-text search system made a lot of sense in those situations, and I wholeheartedly agree. So I decided to devote a new post to <a href="http://www.hibernate.org/410.html">Hibernate Search</a>!</p>
<p>In this example, I provide a live, <a href="http://mikedesjardins.us/cheese/search">online interactive search</a> of an online cheese database, and you can download the example (more on that at the end of the post).</p>
<p><span style="font-weight: bold;">Step One &#8211; The Test Data</span><br />I spent the most time on this project was creating test data for the example program.  I headed over to <a href="http://freebase.com/">Freebase</a> to see what was available for data sets.  Among lots of other things, they have a free database of <a href="http://www.freebase.com/view/food/cheese">cheese</a>.  First, I downloaded the data in TSV format, dumped it into a raw table, and massaged it into a relational, normalized schema.  I ended up with this when I was done:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/cheese-search-erd-785039.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/cheese-search-erd-785035.jpg" alt="" border="0" /></a>So, a CHEESE can have only one ORIGIN (a country or region where the cheese is made), is made from one-to-many types of MILK, and may have zero-to-many TEXTURES associated with it.</p>
<p><span style="font-weight: bold;">Step Two &#8211; Build the Domain Model</span><br />The domain model for this system is very simple.  Each Cheese class has an Origin, and a set of Milk and Textures:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@<span style="color: #003399;">Entity</span> @Table<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;MILK&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Milk <span style="color: #009900;">&#123;</span>
  @Id @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;milk_id&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
  @Basic @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> name<span style="color: #339933;">;</span>
&nbsp;
  @Version @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;version&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> version<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Accessors omitted</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@<span style="color: #003399;">Entity</span> @Table<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;ORIGIN&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Origin <span style="color: #009900;">&#123;</span>
  @Id @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;origin_id&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
  @Basic @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> name<span style="color: #339933;">;</span>
&nbsp;
  @Version @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;version&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> version<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Accessors omitted</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@<span style="color: #003399;">Entity</span> @Table<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;TEXTURE&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Texture <span style="color: #009900;">&#123;</span>
  @Id @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;texture_id&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
  @Basic @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> description<span style="color: #339933;">;</span>
&nbsp;
  @Version @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;version&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> version<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Accessors omitted</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@<span style="color: #003399;">Entity</span> @Table<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;CHEESE&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Cheese <span style="color: #009900;">&#123;</span>
  @Id @GeneratedValue<span style="color: #009900;">&#40;</span>strategy<span style="color: #339933;">=</span>GenerationType.<span style="color: #006633;">IDENTITY</span><span style="color: #009900;">&#41;</span>
  @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;cheese_id&quot;</span>,nullable<span style="color: #339933;">=</span><span style="color: #000066; font-weight: bold;">false</span>,unique<span style="color: #339933;">=</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
  @Basic @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> name<span style="color: #339933;">;</span>
&nbsp;
  @ManyToOne<span style="color: #009900;">&#40;</span>cascade<span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span>CascadeType.<span style="color: #006633;">ALL</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
  @JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;origin_id&quot;</span>,nullable<span style="color: #339933;">=</span><span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> Origin origin<span style="color: #339933;">;</span>
&nbsp;
  @ManyToMany<span style="color: #009900;">&#40;</span>cascade<span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span>CascadeType.<span style="color: #006633;">PERSIST</span>,CascadeType.<span style="color: #006633;">MERGE</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
  @JoinTable<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;CHEESE_MILK_MAP&quot;</span>,
             joinColumns<span style="color: #339933;">=</span>@JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;cheese_id&quot;</span><span style="color: #009900;">&#41;</span>,
             inverseJoinColumns<span style="color: #339933;">=</span>@JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;milk_id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> Set<span style="color: #339933;">&lt;</span>Milk<span style="color: #339933;">&gt;</span> milks <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashSet<span style="color: #339933;">&lt;</span>Milk<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  @ManyToMany<span style="color: #009900;">&#40;</span>cascade<span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span>CascadeType.<span style="color: #006633;">PERSIST</span>,CascadeType.<span style="color: #006633;">MERGE</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
  @JoinTable<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;CHEESE_TEXTURE_MAP&quot;</span>,
             joinColumns<span style="color: #339933;">=</span>@JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;cheese_id&quot;</span><span style="color: #009900;">&#41;</span>,
             inverseJoinColumns<span style="color: #339933;">=</span>@JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;texture_id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> Set<span style="color: #339933;">&lt;</span>Texture<span style="color: #339933;">&gt;</span> textures <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashSet<span style="color: #339933;">&lt;</span>Texture<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  @Version @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;version&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> version<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Accessors omitted</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><span style="font-weight: bold;">Step Three &#8211; Add Search Annotations and Configure Lucene</span><br />Behind the scenes, Hibernate Search uses the <a href="http://lucene.apache.org/">Apache Lucene</a> search engine to do its indexing. In short, it maintains a mapping of object IDs to search terms in an external file, and updates the file when objects are added, updated, or deleted.  To start using Hibernate Search, you&#8217;ll need to configure the location of these index files, as well as a search directory provider (we&#8217;ll just use the default).  This is done in your Hibernate properties file, or (if you use JPA, like me), in persistence.xml:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;hibernate.search.default.directory_provider&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;org.hibernate.search.store.FSDirectoryProvider&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;hibernate.search.default.indexBase&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;/var/lucene/cheese-indexes&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>Next, you need to indicate to Lucene which classes need to be indexed.  You also need to indicate which data fields 1.) contain the document ID, and 2.) contain relevant search text.  In our example, we only need to index the Cheese objects.  We want to allow users to search on cheese name, milk name, origin, and texture.</p>
<p>First, we indicate that we want to index the Cheese objects by applying the <span style="font-weight: bold;">@Indexed</span> annotation to the class, and we elect to use the Id field to identify the Cheese objects to Lucene by applying a <span style="font-weight: bold;">@DocumentId</span> annotation to it.  Next, we indicate that the cheese name contains searchable text by adding the <span style="font-weight: bold;">@Field(index=Index.TOKENIZED, store=Store.NO)</span> annotation to it.  The annotation parameters are informing Hibernate Search to use Lucene&#8217;s default tokenizer to summarize the text, and not to store a copy of the document content.</p>
<p>We also want to allow users to search on Origin, Milk Name, and Texture.  This text is not contained within the Cheese object, instead they&#8217;re in related object.  So we need to add the <span style="font-weight: bold;">@IndexEmbedded</span> annotation to the member variables in the Cheese class that refer to the objects which contain the searchable text, and we also need to add the <span style="font-weight: bold;">@Field(index=Index.TOKENIZED, store=Store.NO)</span> annotation to the Milk, Origin, and Texture classes to indicate which fields are searchable.</p>
<p>When you&#8217;re done, the modified domain classes will look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@<span style="color: #003399;">Entity</span> @Table<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;MILK&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Milk <span style="color: #009900;">&#123;</span>
  @Id @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;milk_id&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
  @<span style="color: #003399;">Field</span><span style="color: #009900;">&#40;</span>index<span style="color: #339933;">=</span>Index.<span style="color: #006633;">TOKENIZED</span><span style="color: #009900;">&#41;</span>
  @Basic @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> name<span style="color: #339933;">;</span>
&nbsp;
  @Version @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;version&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> version<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Accessors omitted</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@<span style="color: #003399;">Entity</span> @Table<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;ORIGIN&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Origin <span style="color: #009900;">&#123;</span>
  @Id @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;origin_id&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
  @<span style="color: #003399;">Field</span><span style="color: #009900;">&#40;</span>index<span style="color: #339933;">=</span>Index.<span style="color: #006633;">TOKENIZED</span><span style="color: #009900;">&#41;</span>
  @Basic @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> name<span style="color: #339933;">;</span>
&nbsp;
  @Version @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;version&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> version<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Accessors omitted</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@<span style="color: #003399;">Entity</span> @Table<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;TEXTURE&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Texture <span style="color: #009900;">&#123;</span>
  @Id @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;texture_id&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
  @<span style="color: #003399;">Field</span><span style="color: #009900;">&#40;</span>index<span style="color: #339933;">=</span>Index.<span style="color: #006633;">TOKENIZED</span><span style="color: #009900;">&#41;</span>
  @Basic @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> description<span style="color: #339933;">;</span>
&nbsp;
  @Version @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;version&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> version<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Accessors omitted</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@Indexed
@<span style="color: #003399;">Entity</span> @Table<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;CHEESE&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Cheese <span style="color: #009900;">&#123;</span>
  @DocumentId
  @Id @GeneratedValue<span style="color: #009900;">&#40;</span>strategy<span style="color: #339933;">=</span>GenerationType.<span style="color: #006633;">IDENTITY</span><span style="color: #009900;">&#41;</span>
  @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;cheese_id&quot;</span>,nullable<span style="color: #339933;">=</span><span style="color: #000066; font-weight: bold;">false</span>,unique<span style="color: #339933;">=</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
&nbsp;
  @Basic @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#41;</span>
  @<span style="color: #003399;">Field</span><span style="color: #009900;">&#40;</span>index<span style="color: #339933;">=</span>Index.<span style="color: #006633;">TOKENIZED</span>, store<span style="color: #339933;">=</span>Store.<span style="color: #006633;">NO</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> name<span style="color: #339933;">;</span>
&nbsp;
  @IndexedEmbedded
  @ManyToOne<span style="color: #009900;">&#40;</span>cascade<span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span>CascadeType.<span style="color: #006633;">ALL</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
  @JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;origin_id&quot;</span>,nullable<span style="color: #339933;">=</span><span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> Origin origin<span style="color: #339933;">;</span>
&nbsp;
  @IndexedEmbedded
  @ManyToMany<span style="color: #009900;">&#40;</span>cascade<span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span>CascadeType.<span style="color: #006633;">PERSIST</span>,CascadeType.<span style="color: #006633;">MERGE</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
  @JoinTable<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;CHEESE_MILK_MAP&quot;</span>,
             joinColumns<span style="color: #339933;">=</span>@JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;cheese_id&quot;</span><span style="color: #009900;">&#41;</span>,
             inverseJoinColumns<span style="color: #339933;">=</span>@JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;milk_id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> Set<span style="color: #339933;">&lt;</span>Milk<span style="color: #339933;">&gt;</span> milks <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashSet<span style="color: #339933;">&lt;</span>Milk<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  @IndexedEmbedded
  @ManyToMany<span style="color: #009900;">&#40;</span>cascade<span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span>CascadeType.<span style="color: #006633;">PERSIST</span>,CascadeType.<span style="color: #006633;">MERGE</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
  @JoinTable<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;CHEESE_TEXTURE_MAP&quot;</span>,
             joinColumns<span style="color: #339933;">=</span>@JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;cheese_id&quot;</span><span style="color: #009900;">&#41;</span>,
             inverseJoinColumns<span style="color: #339933;">=</span>@JoinColumn<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;texture_id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> Set<span style="color: #339933;">&lt;</span>Texture<span style="color: #339933;">&gt;</span> textures <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashSet<span style="color: #339933;">&lt;</span>Texture<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  @Version @Column<span style="color: #009900;">&#40;</span>name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;version&quot;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> version<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Accessors omitted</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><span style="font-weight: bold;">Step Four &#8211; The Servlets</span><br />In this example, I didn&#8217;t want to rely on any web frameworks or even on JSPs, so I wrote a good old-fashioned servlet to exercise the search function.  No sane person would ever do it this way.   There are actually two servlets in the example &#8211; one for application initialization and one for the page itself.</p>
<p>The initialization servlet does the work of indexing all of the database data the first time through.  For our small data set, this takes less than a minute.  For larger data sets, it wouldn&#8217;t make sense to re-index everything every time you start the application.  The initialization code iterates over all of the Cheese objects ant tells the FullTextEntityManger to index it:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  Dao<span style="color: #339933;">&lt;</span>Cheese<span style="color: #339933;">&gt;</span> dao <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CheeseDao<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  EntityManager em <span style="color: #339933;">=</span> dao.<span style="color: #006633;">getEntityManager</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  FullTextEntityManager fullTextEntityManager <span style="color: #339933;">=</span> Search.<span style="color: #006633;">createFullTextEntityManager</span><span style="color: #009900;">&#40;</span>em<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  List<span style="color: #339933;">&lt;</span>Cheese<span style="color: #339933;">&gt;</span> cheeses <span style="color: #339933;">=</span> em.<span style="color: #006633;">createQuery</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;select c from Cheese as c&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getResultList</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>Cheese cheese <span style="color: #339933;">:</span> cheeses<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    fullTextEntityManager.<span style="color: #006633;">index</span><span style="color: #009900;">&#40;</span>cheese<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>The main page servlet has some code in the doPost method to perform the search based on the contents of the text form field.  That code looks like this (I&#8217;ve shortened it up a bit here by removing some error checking and HTML output):</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doPost<span style="color: #009900;">&#40;</span>HttpServletRequest request,
                   HttpServletResponse response<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> ServletException, <span style="color: #003399;">IOException</span> <span style="color: #009900;">&#123;</span>
  response.<span style="color: #006633;">setContentType</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;text/html&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #003399;">PrintWriter</span> out <span style="color: #339933;">=</span> response.<span style="color: #006633;">getWriter</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  emitHeader<span style="color: #009900;">&#40;</span>out<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #003399;">String</span> searchTerm <span style="color: #339933;">=</span> request.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;searchterm&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  EntityManager em <span style="color: #339933;">=</span> dao.<span style="color: #006633;">getEntityManager</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  FullTextEntityManager fullTextEntityManager <span style="color: #339933;">=</span>
    org.<span style="color: #006633;">hibernate</span>.<span style="color: #006633;">search</span>.<span style="color: #006633;">jpa</span>.<span style="color: #006633;">Search</span>.<span style="color: #006633;">createFullTextEntityManager</span><span style="color: #009900;">&#40;</span>em<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  MultiFieldQueryParser parser <span style="color: #339933;">=</span>
    <span style="color: #000000; font-weight: bold;">new</span> MultiFieldQueryParser<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#123;</span><span style="color: #0000ff;">&quot;name&quot;</span>,
                                            <span style="color: #0000ff;">&quot;origin.name&quot;</span>,
                                            <span style="color: #0000ff;">&quot;milks.name&quot;</span>,
                                            <span style="color: #0000ff;">&quot;textures.description&quot;</span><span style="color: #009900;">&#125;</span>,
                               <span style="color: #000000; font-weight: bold;">new</span> StandardAnalyzer<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
    org.<span style="color: #006633;">apache</span>.<span style="color: #006633;">lucene</span>.<span style="color: #006633;">search</span>.<span style="color: #006633;">Query</span> query <span style="color: #339933;">=</span> parser.<span style="color: #006633;">parse</span><span style="color: #009900;">&#40;</span>searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    javax.<span style="color: #006633;">persistence</span>.<span style="color: #006633;">Query</span> hibQuery <span style="color: #339933;">=</span>
      fullTextEntityManager.<span style="color: #006633;">createFullTextQuery</span><span style="color: #009900;">&#40;</span>query,Cheese.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    List<span style="color: #339933;">&lt;</span>Cheese<span style="color: #339933;">&gt;</span> result <span style="color: #339933;">=</span> hibQuery.<span style="color: #006633;">getResultList</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    emitTable<span style="color: #009900;">&#40;</span>out,result<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">ParseException</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    log.<span style="color: #006633;">error</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Got a parse exception&quot;</span>, e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> ServletException<span style="color: #009900;">&#40;</span>e.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  emitFooter<span style="color: #009900;">&#40;</span>out<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  out.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>That&#8217;s all there is to it!  As you can see, setting up Hibernate Search is very simple.  Most of the effort for this project was spent creating the data and making the servlets work.</p>
<p><span style="font-weight: bold;">Enjoy the Finished Product</span><br />To see this less-than-world-changing application in action, visit it <a href="http://mikedesjardins.us/cheese/search">here</a>.  You can also <a href="http://mikedesjardins.us/cheese-search-1.0.tar.gz">download the whole eclipse project</a> and try it out for yourself.  It comes with SQL dumps suitable for MySQL and PostgreSQL, and it has been tested with both environments under Tomcat 5.5.</p>
<p><span style="font-style: italic;">Photo Credit: </span><a href="http://www.flickr.com/people/cuse/"><span style="font-style: italic;font-size:100%;" ><span class="RealName"><span class="fn n"><span class="given-name">Chris</span> <span class="family-name">Buecheler</span></span></span></span></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/07/twenty-minutes-with-hibernate-search-a-cheesy-example/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Use Hibernate&#8217;s Custom Loaders to fake an aggregation view</title>
		<link>http://www.mikedesjardins.net/content/2008/06/use-hibernates-custom-loaders-to-fake/</link>
		<comments>http://www.mikedesjardins.net/content/2008/06/use-hibernates-custom-loaders-to-fake/#comments</comments>
		<pubDate>Mon, 23 Jun 2008 18:37:00 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[hibernate]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jpa]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/2008/06/use-hibernates-custom-loaders-to-fake-an-aggregation-view/</guid>
		<description><![CDATA[Your ProblemYou have a data model with table that contains data you want to aggregate.  For instance (returning to my venerable Pizza Shop example), let&#8217;s say you have a PRODUCT table that enumerates the items your pizza shops sells, and a LOCATION table that contains all of your retail locations:
We also have a table [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-weight: bold;">Your Problem</span><br />You have a data model with table that contains data you want to aggregate.  For instance (returning to my venerable Pizza Shop example), let&#8217;s say you have a PRODUCT table that enumerates the items your pizza shops sells, and a LOCATION table that contains all of your retail locations:</p>
<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/blog-location-product-791817.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/blog-location-product-791813.png" alt="" border="0" /></a><br />We also have a table that contains the sum of all of the previous days&#8217; sales, broken down by PRODUCT and LOCATION:</p>
<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/blog-yesterday-sales-786534.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/blog-yesterday-sales-786525.png" alt="" border="0" /></a>This is all well and good, but we&#8217;ve been asked to create an Executive Dashboard for the President of the pizza chain, and she would like to see daily sales by product.  She is not interested in a breakdown by location.</p>
<p><span style="font-weight: bold;">We could tally it up client side&#8230;</span><br />What if we just loaded the entire table into the client, and iterated over the per-product results, and present that?  Unfortunately, ORM libraries are pretty stupid in situations like these, and will generate all kinds of expensive reads to the database when you try to solve the problem this way.  If you want to learn more about lazy loading, and why you shouldn&#8217;t iterate over a collection, check out my earlier post <a href="http://mikedesjardins.us/blog/2008/03/pizza-shop-2-totaling-jpa-order-use.html">here</a>.</p>
<p><span style="font-weight: bold;">We could just create a view in the Database&#8230;</span><br />We <span>could</span><span style="font-weight: bold;"> </span>just create a view, and aggregate the data there.  Then we can easily create a Hibernate mapping to that view.  The query for the view is simple:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">VIEW</span> sales_by_product_view <span style="color: #993333; font-weight: bold;">AS</span>
<span style="color: #993333; font-weight: bold;">SELECT</span> product_id<span style="color: #66cc66;">,</span> sum<span style="color: #66cc66;">&#40;</span>total_sales<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> total_sales
  <span style="color: #993333; font-weight: bold;">FROM</span> YESTERDAY_SALES
 <span style="color: #993333; font-weight: bold;">GROUP</span> <span style="color: #993333; font-weight: bold;">BY</span> product_id</pre></div></div>

<p>However, we are working with a tyrannical DBA.  She is not keen on proliferating views throughout our otherwise pristine schema every time the President has decided that the company needs a new widget for the executive dashboard application.</p>
<p><span style="font-weight: bold;">&#8230;or we could fake it with a custom loader</span><br />Instead, let&#8217;s create a Hibernate mapping that generates the same results as the view.  First, let&#8217;s create a simple POJO to contain the results:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">us.mikedesjardins</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> SalesByProduct <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Integer</span> productId<span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">BigDecimal</span> sales<span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// accessors omitted</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>The corresponding mapping file would look like this.  I re-used the product_id for the ID in this  example.  Note the loader element:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;hibernate-mapping</span> <span style="color: #000066;">package</span>=<span style="color: #ff0000;">&quot;us.mikedesjardins&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;class</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;SalesByProduct&quot;</span></span>
<span style="color: #009900;">          <span style="color: #000066;">dynamic-insert</span>=<span style="color: #ff0000;">&quot;false&quot;</span></span>
<span style="color: #009900;">          <span style="color: #000066;">dynamic-update</span>=<span style="color: #ff0000;">&quot;false&quot;</span></span>
<span style="color: #009900;">          <span style="color: #000066;">mutable</span>=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;id&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;int&quot;</span> <span style="color: #000066;">unsaved-value</span>=<span style="color: #ff0000;">&quot;null&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;column</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;__id&quot;</span> <span style="color: #000066;">sql-type</span>=<span style="color: #ff0000;">&quot;int identity&quot;</span> <span style="color: #000066;">not-null</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">unique</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>    
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;productId&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;int&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;column</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;__product_id&quot;</span> <span style="color: #000066;">not-null</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/property<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;sales&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;java.math.BigDecimal&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;column</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;__total_sales&quot;</span> <span style="color: #000066;">not-null</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/property<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;loader</span> <span style="color: #000066;">query-ref</span>=<span style="color: #ff0000;">&quot;salesByProductQuery&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;sql-query</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;salesByProductQuery&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;return</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;SalesByProduct&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #339933;">&lt;![CDATA[</span>
<span style="color: #339933;">    select product_id as __id</span>
<span style="color: #339933;">         , product_id as __product_id</span>
<span style="color: #339933;">         , sum(total_sales) as __total_sales</span>
<span style="color: #339933;">      from YESTERDAY_SALES</span>
<span style="color: #339933;">     where product_id = :product_id</span>
<span style="color: #339933;">    group by product_id</span>
<span style="color: #339933;">   ]]&gt;</span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/sql-query<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/hibernate-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Note that you need to put a positional argument in the query, or Hibernate will get nasty about parsing it.  Hope that helps!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/06/use-hibernates-custom-loaders-to-fake/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Why you should not not use ORM</title>
		<link>http://www.mikedesjardins.net/content/2008/06/why-you-should-not-not-use-orm/</link>
		<comments>http://www.mikedesjardins.net/content/2008/06/why-you-should-not-not-use-orm/#comments</comments>
		<pubDate>Tue, 17 Jun 2008 00:32:00 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[hibernate]]></category>
		<category><![CDATA[jpa]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/2008/06/why-you-should-not-not-use-orm/</guid>
		<description><![CDATA[Yesterday I read a blog post by Kenneth Downs entitled &#8220;Why I Do Not Use ORM&#8221; on his The Database Programmer blog.  It wasn&#8217;t the first blog post with gripes about Object Relational Mapping, and it certainly won&#8217;t be the last.  For me, this particular article highlighted a few misconceptions about why and [...]]]></description>
			<content:encoded><![CDATA[<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/2522766037_44d8e2e709-731771.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/2522766037_44d8e2e709-731749.jpg" alt="" border="0" /></a>Yesterday I read a blog post by Kenneth Downs entitled &#8220;<a href="http://database-programmer.blogspot.com/2008/06/why-i-do-not-use-orm.html">Why I Do Not Use ORM</a>&#8221; on his <a href="http://database-programmer.blogspot.com/">The Database Programmer</a> blog.  It wasn&#8217;t the first blog post with gripes about Object Relational Mapping, and it certainly won&#8217;t be the last.  For me, this particular article highlighted a few misconceptions about why and how ORM should be used, and I thought I might chime in with my own perspective.</p>
<p><span style="font-weight: bold;">ORM is not a way to avoid SQL</span><br />The first thing that stood out for me was this quote:<br />
<blockquote>&#8220;The language SQL is the most widely supported, implemented, and    used way to connect to databases.  But since most of us have long    lists of complaints about the language, we end up writing abstraction    layers that make it easier for us to avoid coding SQL directly.&#8221;</p></blockquote>
<p>To his credit, the author wasn&#8217;t actually addressing ORM in this paragraph.  However, anyone writing business logic which interacts with a database, who is unable to write some basic SQL, is like a bull in a china shop; nothing good will come of it regardless of the tools and abstraction layers employed.</p>
<p><span style="font-weight: bold;">The Simple Example</span><br />The next example in the post shows how one would write a row to a database in only four lines of PHP code &#8211; it looks something like this (I removed the comments):</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$row</span> <span style="color: #339933;">=</span> getPostStartingWith<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;inp_&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$table_id</span> <span style="color: #339933;">=</span> myGetPostVarFunction<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'table_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>SQLX_Insert<span style="color: #009900;">&#40;</span><span style="color: #000088;">$table_id</span><span style="color: #339933;">,</span><span style="color: #000088;">$row</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
 myFrameworkErrorReporting<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>I don&#8217;t know PHP, but I think the code is reading every field in a posted form that starts with inp_, generates an insert statement straight from the ID&#8217;s on the form fields, and writes an insert statement with the results.</p>
<p>Perhaps it&#8217;s unfair to criticize this code because &#8220;it&#8217;s just a simple example,&#8221; but if this code is being held up as an example of how short and simple non-ORM code can be, one does have to wonder
<ul>
<li>When the database schema changes, does the HTML need to be updated so that the form fields match the database schema?</li>
<li>Where are the transactions?  What if I need to insert into several tables and roll back the transaction if one fails?</li>
<li>Does the handy SQLX_insert method prevent SQL injection attacks?</li>
</ul>
<p>He goes on to say that this task is made even easier by <a href="http://database-programmer.blogspot.com/2008/06/using-data-dictionary.html">using a data dictionary</a> to generate the SQL.  After reading the &#8220;Using a Data Dictionary&#8221; article, one has to wonder whether or not the author realizes that it is a very crude form of ORM.</p>
<p><span style="font-weight: bold;">What about Business Logic?</span><br />Kenneth Downs tries to head-off any arguments about business logic before they come up, knowing that ORM evangelists will argue that the domain objects can encapsulate essential business logic for the application.  His response?<br />
<blockquote>&#8220;The SQLX_Insert()    routine can call out to functions (fast) or objects     (much slower) that massage data before and after the    insert operation.  I will be demonstrating some of these    techniques in future essays, but of course the best     permforming and safest method is to use triggers.&#8221;</p></blockquote>
<p>For me, this sounds alarm bells.  Triggers slow down transactions.  Triggers are in your database, which is often your system&#8217;s biggest bottleneck.  Triggers silently do things behind your back without telling you.  Triggers change databases from vast, efficient places to store relational data, into a lumbering behemoth interpreting procedural code inside big iron.</p>
<p>Conversely, business logic that can be easily distributed across many smaller web servers scales horizontally.  The domain layer is a fantastic place to embed simple data massaging &#8211; sadly, I often see a pile of persistent entities with getters and setters that don&#8217;t do anything.</p>
<p><span style="font-weight: bold;">Counter Example: The Disaster Scenario</span><br />Lastly, Ken (can I call him that?  What is the ettiquite for this sort of thing, anyway?) shows an example of a piece of code that is likely to cause hundreds of unneeded reads to the database in an untuned ORM-based system.  I don&#8217;t dispute this; in fact, I <a href="http://mikedesjardins.us/blog/2008/03/pizza-shop-2-totaling-jpa-order-use.html">posted</a> about an almost identical nightmare scenario myself a while ago.</p>
<p>For this, I go back to my &#8220;bull in a china shop&#8221; analogy.  Programmers can write horrible code in any language, with any tool.  Layers of abstraction are a double-edged sword, because you need to understand what they are doing for you.  But it&#8217;s not the tool&#8217;s fault; it&#8217;s the person misusing it.</p>
<p><span style="font-weight: bold;">Computer Science&#8217;s Vietnam</span><br />In 2004, Ted Neward famously called ORM <a href="http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx">Computer Science&#8217;s Vietnam</a>.  Encouraged by early successes, we got sucked into the quagmire.  There are plenty of reasons to be frustrated with ORM, but I&#8217;m not sure I agree with Ken&#8217;s.  I try to hit the 80/20 rule with ORM, and use it where it makes sense.  When I get into a convoluted transaction or need to do a large batch of operations, I&#8217;m not afraid to dive into SQL and do the work in a stored procedure.  I think it&#8217;s a good mix.  How about you?</p>
<p><span style="font-style: italic;">Photo Credit: </span><a style="font-style: italic;" href="http://www.flickr.com/people/meesterdickey/">Ryan Dickey</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/06/why-you-should-not-not-use-orm/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>The Hibernate Song</title>
		<link>http://www.mikedesjardins.net/content/2008/06/the-hibernate-song/</link>
		<comments>http://www.mikedesjardins.net/content/2008/06/the-hibernate-song/#comments</comments>
		<pubDate>Fri, 06 Jun 2008 15:32:00 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[hibernate]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jpa]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/2008/06/the-hibernate-song/</guid>
		<description><![CDATA[(to the tune of The Spiderman Theme Song from the original cartoon series)
Hibernate, HibernateO/R Mapping sure is greatGavin King, and H-Q-LMake my life a living hellLook out!  Here comes Hibernate!
Mapping Files in HibernateWish my team would annotateAre its queries optimized?Who knows &#8211; it&#8217;s always a surpriseHey there, there goes Hibernate!
Don&#8217;t fetch data nowLazy load, [...]]]></description>
			<content:encoded><![CDATA[<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/spiderman-704658.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/spiderman-704633.png" alt="" border="0" /></a>(to the tune of <span style="font-style: italic;">The Spiderman Theme Song</span> from the original cartoon series)</p>
<p>Hibernate, Hibernate<br />O/R Mapping sure is great<br />Gavin King, and H-Q-L<br />Make my life a living hell<br />Look out!  Here comes Hibernate!</p>
<p>Mapping Files in Hibernate<br />Wish my team would annotate<br />Are its queries optimized?<br />Who knows &#8211; it&#8217;s always a surprise<br />Hey there, there goes Hibernate!</p>
<p>Don&#8217;t fetch data now<br />Lazy load, &#8216;cuz you might guess<br />I don&#8217;t need it now<br />Hibernate, you do know best!</p>
<p>Hibernate, Hibernate<br />Friendly neighborhood Hibernate<br />Grab the jars, and climb aboard<br />OO models are your reward<br />To it&#8230;<br />Relational DBs are old-school<br />When you need a complex tool<br />You need the Hibernate!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/06/the-hibernate-song/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Holy crap &#8211; I like to write specs!</title>
		<link>http://www.mikedesjardins.net/content/2008/05/holy-crap-i-like-to-write-specs/</link>
		<comments>http://www.mikedesjardins.net/content/2008/05/holy-crap-i-like-to-write-specs/#comments</comments>
		<pubDate>Thu, 29 May 2008 01:30:00 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[career]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/2008/05/holy-crap-i-like-to-write-specs/</guid>
		<description><![CDATA[I had an amazing revelation at work last week.
At my previous job, the company culture steadfastly clung to the waterfall model as the one true way to develop software.  The model was imposed as a series of documents with cryptic, archaic acronyms for names.  I actually had to draw a flowchart for my [...]]]></description>
			<content:encoded><![CDATA[<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/84056948_6d0dcc5728-756703.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/84056948_6d0dcc5728-756670.jpg" alt="" border="0" /></a>I had an amazing revelation at work last week.</p>
<p>At my previous job, the company culture steadfastly clung to the waterfall model as the one true way to develop software.  The model was imposed as a series of documents with cryptic, archaic acronyms for names.  I actually had to draw a flowchart for my team to help them keep track of when each document was required in the life cycle of an enhancement request.</p>
<p>No code was changed in our code-base without a minimum of literally five separate documents, each usually spanning tens of pages.  Project managers at the company enforced the production of these documents in a near-religious deference to &#8220;the process.&#8221;  Each document was reviewed, often via conference call, to receive it&#8217;s &#8220;stamp of approval&#8221; (basically a C.Y.A. cross-check) among the affected teams (usually development, production support, professional services, client management, security, perhaps others).</p>
<p>It often felt as though I worked at a documentation company that happened to create software as a by-product.</p>
<p>It was in this atmosphere that I first started reading about so-called Agile methodologies.  Iterative prototyping, unit testing, and tight user/developer communications, their practitioners argued, were a more effective way to deliver software that met customer expectations.  Because specifications change, and users don&#8217;t know what they want, you&#8217;re already behind schedule by the time you get done with all of that front-end junk.</p>
<p>It all sounded so wonderful &#8211; too good to be true.  If only my company were more like that.</p>
<p>Now I&#8217;m at a new job.  There&#8217;s very little process here &#8211; it goes something like this: A nominal business analyst creates a document with a punch-list of specifications, and the developers go off and implement it.  That&#8217;s it.</p>
<p>You&#8217;d think I was in paradise!  I would be freed of the shackles of Microsoft Word, and I&#8217;d be able to churn out code as efficiently as possible.</p>
<p><span style="font-weight: bold;">What Really Happened</span><br />I soon discovered myself going in circles.  I&#8217;d spend a lot of time in front of the whiteboard drawing ERDs for the database, and then I wouldn&#8217;t know where to go next.  Start Object-Relational mapping?  Hmm&#8230; seems to soon for that.  The business model?  And what is the business model&#8230; what does it need to do?  And will the business model&#8217;s persistent data be adequately served by the data model on this white board?</p>
<p>Maybe I&#8217;ll just dive in and start implementing&#8230; Agile-style.  I guess that means I should start with the UI; how do I do the UI?  That&#8217;s what the user wants, right?  The spec says I need to do such-and-such&#8230; I know!  I&#8217;ll crate a UI, and wire it up to the model&#8217;s interface, and mock-out the actual implementation of the model!  So there&#8217;s really no ugly business model code to worry about.</p>
<p>So what should the model&#8217;s API&#8217;s be?  What parameters do I need to pass around to make this thing re-usable?  Will I end up needing to refactor the whole thing to support some relationship I haven&#8217;t considered yet?  Oh well.  Don&#8217;t worry about that for now.</p>
<p>And, by the way, the UI is just an admistrative, ancillary part of this project.  It&#8217;s actually a batch process that runs nightly which is configured via the UI.  The UI isn&#8217;t even technically necessary.  Am I putting the proverbial cart before the horse?  Hmmph &#8211; probably I shouldn&#8217;t start with the UI, then.</p>
<p>Hey &#8211; look at this whiteboard&#8230; an ERD&#8230; let&#8217;s work on that for a while!</p>
<p><span style="font-weight: bold;">What Works for Me</span><br />What was actually wrong with my old job was the sheer volume of documentation, and the ratio of useful information to the total number of pages.  That documentation was almost never for me &#8211; it was for <span style="font-style: italic;">other people</span> (although I still wonder how valuable it really was to other people).</p>
<p>Personally, I need something to ground the project.  I need a place to organize my thoughts.  For me, a &#8220;specification&#8221; isn&#8217;t a giant UML class diagram that I slavishly adhere to, and keep in sync with the code at all times.  It&#8217;s a place where I enumerate the affected components, discover how they interact, and itemize the work that needs to be done.  It&#8217;s where I validate that the thing I&#8217;m about to build is going to come somewhat close to meeting the user&#8217;s expectations.</p>
<p>Sometimes, I share the document with other people.  Sometimes I don&#8217;t.  But I&#8217;ve learned that personally, for me, I need a place to focus, and collect the pieces that need to interact, before I start writing.</p>
<p>For some reason, this was an amazing revelation to me.  My experience at my last job had led me to believe that I was firmly in the anti-documentation camp.  It turns out that, in my case, that wasn&#8217;t true at all. I need some documentation.  And I don&#8217;t think it&#8217;s true for everybody, either.  I&#8217;m sure there are people who are better at diving right in, and still others that want even more documentation than I do.</p>
<p>What works for you?<br /><span style="font-style: italic;">Photo Credit: </span><a style="font-style: italic;" href="http://www.flickr.com/people/effbot/">Fredrik Lundh</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/05/holy-crap-i-like-to-write-specs/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Amp&#8217;d Mobile, (Almost) One Year Later</title>
		<link>http://www.mikedesjardins.net/content/2008/05/ampd-mobile-almost-one-year-later/</link>
		<comments>http://www.mikedesjardins.net/content/2008/05/ampd-mobile-almost-one-year-later/#comments</comments>
		<pubDate>Wed, 14 May 2008 12:26:00 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[wireless]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/2008/05/ampd-mobile-almost-one-year-later/</guid>
		<description><![CDATA[It&#8217;s been almost a year since Amp&#8217;d Mobile imploded.  Amp&#8217;d Mobile was a Mobile Virtual Network Operator (MVNO).  This meant that they were a wireless carrier without a network &#8211; instead, they relied on a &#8220;real&#8221; national carrier&#8217;s network (in Amp&#8217;d&#8217;s case, Verizon&#8217;s) to deliver voice and data services.  As one of [...]]]></description>
			<content:encoded><![CDATA[<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mikedesjardins.us/blog/uploaded_images/ampdlogo-792920.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 220px; height: 166px;" src="http://mikedesjardins.us/blog/uploaded_images/ampdlogo-792909.jpg" alt="" border="0" /></a>It&#8217;s been almost a year since <a href="http://en.wikipedia.org/wiki/Amp%27d_Mobile">Amp&#8217;d Mobile</a> imploded.  Amp&#8217;d Mobile was a Mobile Virtual Network Operator (MVNO).  This meant that they were a wireless carrier without a network &#8211; instead, they relied on a &#8220;real&#8221; national carrier&#8217;s network (in Amp&#8217;d&#8217;s case, Verizon&#8217;s) to deliver voice and data services.  As one of the software architects who designed their central integration point and contributed to their billing platform, <span>I had a unique view into it&#8217;s rise and abrupt demise</span>.  I&#8217;ve wanted to write a post about my experience for quite some time now, and I think that enough time has passed that I can safely speak my mind &#8211; both companies are more-or-less defunct at this point.</p>
<p>I should note that all of these opinions are my own &#8211; <span style="font-weight: bold;">I don&#8217;t speak on behalf of BCGI, Amp&#8217;d Mobile, or anybody else</span>.</p>
<p><span style="font-weight: bold;font-size:130%;" >My Role</span><br />Amp&#8217;d Mobile <a href="http://www.prnewswire.com/cgi-bin/stories.pl?ACCT=104&amp;STORY=/www/story/03-15-2005/0003196252&amp;EDATE=">contracted</a> with my former employer, Boston Communications Group (usually known by its acronym, BCGI).  Among other things, BCGI sold a Postpaid Billing platform called Voyager.  Up until Amp&#8217;d Mobile, <span>Voyager&#8217;s primary market was small, regional wireless carriers</span> with fewer than 100,000 subscribers.  Before Amp&#8217;d, the Voyager product didn&#8217;t contribute much to BCGI&#8217;s bottom line and served more as a product portfolio completer than as a real potential for revenue.  BCGI&#8217;s main focus had instead been on Prepaid Wireless and Payment Services.</p>
<p>My role was primarily to design and create a web service API to Voyager, so that other components in Amp&#8217;d&#8217;s back office could interact with the billing system.  This not only included billing for voice and content, but also provisioning prepaid and postpaid services on Verizon&#8217;s network, accepting payments, and providing a customer care UI for Amp&#8217;d&#8217;s call center.  Additionally, I did some testing to gauge how well the system would scale once Amp&#8217;d added the half-million-or-so subscribers that they were projecting they&#8217;d have in their first year.</p>
<p><span style="font-weight: bold;"><span style="font-size:130%;">What Went Well</span><br /><span style="font-weight: bold;"></span></span><span>I really don&#8217;t intend for this post to be an airing of dirty laundry.  Despite the implosion of both companies, there were a few things that went very well.</span><span style="font-weight: bold;"><span style="font-weight: bold;"></span><br /></span>
<ul>
<li>BCGI was a fairly stodgy company for its size, with a heritage in larger telecom and wireless companies like Verizon and EDS.  Having said that, they gave a lot of latitude to the developers involved with this project.  The pace of the development necessitated a more agile approach than BCGI was accustomed to, and <span style="font-weight: bold;">the upper management at BCGI did a good job of trying to accommodate the furious speed at which things needed to be done</span>.  A lot of the normal paperwork and bureaucracy was pushed aside to get things done more quickly, to everyone&#8217;s benefit.</li>
<li>Some of the development work for the project was offshored, with mixed success.  The projects that I&#8217;d consider successes related to components that did real-time provisioning of services with the carrier&#8217;s network elements.  These projects were <span style="font-weight: bold;">small, self-contained, with clear objectives that did require a lot of business domain knowledge</span>.</li>
<li>With a few exceptions, the API scaled quite well.  <span style="font-weight: bold;">We quickly ramped up to support hundreds of thousands of transactions per day</span>. These came handsets, web sites, payment platforms, etc.</li>
<li>Integration between our API and Amp&#8217;d&#8217;s web components went very well.  <span style="font-weight: bold;">Developers  from geographically dispersed areas </span><span style="font-weight: bold;">used Instant Messaging quite extensively</span> to communicate, and it was a far more productive means of communication than the old &#8220;our developer talks to our project manager who talks to their project manager who talks to their developer&#8221; scheme that seems so pervasive in larger companies.</li>
</ul>
<p><span style="font-size:130%;"><span style="font-weight: bold;">What Didn&#8217;t Go Well</span></span><br />There wouldn&#8217;t be much to write about if there weren&#8217;t a few negatives in the postmortem, right?  So here they are; first, the technical Challenges:
<ul>
<li>Scaling the batch billing processes were more difficult than I anticipated.  When I did my initial testing, I used an existing carrier&#8217;s data, and multiplied their user data gradually to project how quickly we&#8217;d be able to rate call records with larger carriers.  <span style="font-weight: bold;">I didn&#8217;t count on the fact that my source carrier&#8217;s subscribers made far fewer calls per subscriber than Amp&#8217;d&#8217;s subscribers eventually made</span>.  Amp&#8217;d&#8217;s market demographic was much younger than the demographic for the source data that I used, and younger subscribers make more calls.  In retrospect, this should have been obvious.</li>
<li>Another scaling difficulty was caused by the manner by which we received call detail records.  Mediation is the process by which you obtain raw call records from a network device, and turn those records into a billable records in your billing system.  For a traditional carrier, this process takes place daily (at an absolute minimum) or more often as necessary.  In Amp&#8217;d&#8217;s case, we received call records <span style="font-style: italic;">once per month</span>.  This meant that <span style="font-weight: bold;">we needed to process and rate over 50 million call records in a matter of hours</span>, which is no small feat.  It&#8217;s especially difficult when you&#8217;re using a billing system that was designed to mediate only hundreds of thousands of records daily, and bill an order of magnitude fewer records once per month.  We managed to scrape by, but there were some pretty severe growing pains.</li>
<li><span style="font-weight: bold;">We didn&#8217;t adequately anticipate the level of fraud that we encountered</span>.  We were required to make changes to head off fraud problems rather hurriedly, and that led to slapdash implementations that were prone to errors.</li>
<li>The customer care UI was buggy.  I previously did an <a href="http://mikedesjardins.us/blog/2008/03/anatomy-of-project-failure-corporate.html">entire post</a> just about that topic.</li>
</ul>
<p>Of course, there were business-related challenges, too.
<ul>
<li>Most of the executive staff in <span style="font-style: italic;">both </span>companies (Amp&#8217;d and BCGI) had a lot of experience with prepaid environments and mobile content, but <span style="font-weight: bold;">very little experience in postpaid environments</span>.  This was particularly true when Amp&#8217;d Mobile was first getting started.  By the time Amp&#8217;d brought on more seasoned management with post-paid experience, it was already too late.  It&#8217;s important to note that the postpaid business was about three-quarters of Amp&#8217;d&#8217;s subscriber base.</li>
<li>Because many of the key players came from a prepaid background, the enhancements that were requested for the platform often involved marketing content or prepaid services, instead off addressing fundamental business processes like billing and collections.   BCGI, itself of prepaid pedigree, was happy to oblige. <span style="font-weight: bold;">Thus, the limited development resources were allocated to content, marketing, and prepaid tasks instead of revenue assurance</span>,<span style="font-weight: bold;"> payment, </span><span style="font-weight: bold;">and other postpaid tasks</span>.  Sadly, Voyager had built-in collections modules that were never used by Amp&#8217;d because it was never a priority for them.  If this had been made a priority in the very beginning, Amp&#8217;d might still be in business today.</li>
<li><span style="font-weight: bold;">People still buy handsets with the intention to talk on them, not to purchase media content.</span>  When Amp&#8217;d launched, their voice plans were not competitive, and the rate of adoption was low.  I think the belief was that the content was a compelling enough reason to sell the phone.  However, having a good plan for good old send-to-end voice calls is still critical to attract new subscribers.  Once they adjusted their rate plans for this, net add rates improved significantly.</li>
</ul>
<p><span style="font-size:130%;"><span style="font-weight: bold;">What I Learned</span></span><br />It&#8217;s easy to armchair-quarterback the Amp&#8217;d experience.  I obviously have the benefit of hindsight.  Here are some of the things that I took away from the experience:
<ul>
<li>As I wrote in an earlier post, <a href="http://mikedesjardins.us/blog/2008/03/anatomy-of-project-failure-corporate.html"><span style="font-weight: bold;">business domain knowledge is key</span></a>.  If you&#8217;re entering a new business space, make sure you have an expert on your side who knows what the pitfalls will be, from the very beginning.</li>
<li><span style="font-weight: bold;">Building a national MVNO, particularly one that offers post-paid service, is a lot harder than it sounds.</span>  I think that a lot of people mistakenly believe that the only difficult part of building a nationwide wireless carrier is having the network.  But building the operational staff to support billing, credit, collections, and customer care is a huge undertaking that takes <span style="font-style: italic;">years</span> to get right at traditional carriers.  These critical business processes aren&#8217;t cheap, either, even if you manage to outsource them.  I&#8217;m not sure if an MVNO can be competitive given the cost of using the host network, plus the cost of the back-office processes.</li>
<li><span style="font-weight: bold;">Always plan for fraud.</span>  The bigger you get, the bigger target you become for fraud.  Look at every process as a thief would &#8211; payment, distribution, service delivery, etc.  Everywhere in your system where there is something of value is a target.  Plan for it in advance.</li>
<li><span style="font-weight: bold;">Scalability tests might be less useful than you think they are.</span>  It&#8217;s hard to predict how things will scale, and which APIs or processes will take the hardest beating.  It&#8217;s probably safe to just assume that your processes will need to adapt quickly to cope with increased volume, and to be prepared for it by designing your processes to scale horizontally wherever possible.</li>
<li><span style="font-weight: bold;">I had a blast</span>.  This project was one of the most rewarding experiences I&#8217;ve ever had as a developer, and it&#8217;ll be a long time before I can top it.  I worked with some amazing people at Amp&#8217;d, BCGI, and a lot of Amp&#8217;d&#8217;s other vendors.  The brainstorming sessions in Amp&#8217;d&#8217;s amphitheater with the whiteboard is the stuff that developer/architect types love.  I still pine for the good old days when I felt like I was a part of something revolutionary in the wireless space.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/05/ampd-mobile-almost-one-year-later/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Programmers as Rock Stars &#8211; The Next Level</title>
		<link>http://www.mikedesjardins.net/content/2008/04/programmers-as-rock-stars-next-level/</link>
		<comments>http://www.mikedesjardins.net/content/2008/04/programmers-as-rock-stars-next-level/#comments</comments>
		<pubDate>Wed, 23 Apr 2008 23:56:00 +0000</pubDate>
		<dc:creator>Mike Desjardins</dc:creator>
				<category><![CDATA[industry]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[social]]></category>

		<guid isPermaLink="false">http://mikedesjardins.us/wordpress/2008/04/programmers-as-rock-stars-the-next-level/</guid>
		<description><![CDATA[I&#8217;ve been a fan of Michael Arrington&#8217;s TechCrunch blog for awhile now.  So I was a little horrified when I read today&#8217;s article &#8220;Amateur Hour Over at Twitter?&#8221;  The article was about the departure of Twitter&#8217;s Chief Architect, Blaine Cook.  In the article, Arrington doesn&#8217;t pull any punches, and takes Cook to [...]]]></description>
			<content:encoded><![CDATA[<p><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://mikedesjardins.us/blog/uploaded_images/tabloid-751008.jpg" alt="" border="0" />I&#8217;ve been a fan of Michael Arrington&#8217;s <a href="http://www.techcrunch.com/">TechCrunch</a> blog for awhile now.  So I was a little horrified when I read today&#8217;s article &#8220;<a href="http://www.techcrunch.com/2008/04/23/amateur-hour-over-at-twitter/">Amateur Hour Over at Twitter?</a>&#8221;  The article was about the departure of Twitter&#8217;s Chief Architect, Blaine Cook.  In the article, Arrington doesn&#8217;t pull any punches, and takes Cook to task for Twitter&#8217;s scalability problems:<br />
<blockquote>&#8220;Cook was directly responsible for scaling Twitter, and he very much failed in his job.&#8221;</p></blockquote>
<p>I&#8217;ll set aside the question of whether or not this claim is even true.  And I won&#8217;t even consider the legal ramifications of levying such claims.  Perhaps Arrington knows a lot more about rapidly scaling realtime communications systems, and the inner-workings and politics of Twitter, Inc., than most of us do.</p>
<p>This amateurish outburst made me ponder the rock-star status to which we now elevate some programmers and system architects.  There are a lot of geeks to whom we bestow a (perhaps unhealthy) share of idolatry, many of whom don&#8217;t even need their full names to be recognized: DHH, Guido, Linus, PG, Scoble, Spez, Steve (and his evil twin, FSJ), and, yes, even Arrington.  I could probably name dozens more.  Many of us pay a lot of money to be in the same room with these people, and hear them speak.</p>
<p>Was Blaine Cook at this level of stardom?  Probably not.  But he did give talks and apparently kept a blog about the challenges of scaling a project so quickly.  He was Chief Architect of arguably the hottest social service on the internet.  Perhaps that&#8217;s enough to become a target.</p>
<p>Arrington&#8217;s job is to attract eyeballs.  Eyeballs sell ads and (presumably) promote speaking engagements.  At its essence, TechCrunch is not that much different than a traditional magazine.  From where I sit, TechCrunch gleefully taunted a guy who left his job, forceably or otherwise.  What company does that put TechCrunch in when compared to traditional media?  Who follows the <span style="font-style: italic;">real</span> rock stars around, revelling in their success and revelling even more when they crash hard?</p>
<p>Michael Arrington needs to decide what TechCrunch is.  Is it <span style="font-style: italic;">The Wall Street Journal</span>?  Or is it <span style="font-style: italic;">The Star</span>?  The tabloids at the supermarket checkout get lots of eyeballs by celebrating the latest misery of Britney or Lindsey or Brad &amp; Angelina.  If that&#8217;s what TechCrunch is selling, then I ain&#8217;t buying.</p>
<p>Photo Credit: <a href="http://www.flickr.com/people/emutree/">Eric Mutrie</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikedesjardins.net/content/2008/04/programmers-as-rock-stars-next-level/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
