<?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>Wet Feet - Online Marketing and Technology Blog &#187; JDO</title>
	<atom:link href="http://www.wetfeetblog.com/tag/jdo/feed" rel="self" type="application/rss+xml" />
	<link>http://www.wetfeetblog.com</link>
	<description></description>
	<lastBuildDate>Wed, 19 May 2010 15:34:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Google App Engine &#8211; Full Text Search with JDO &#8211; Revisited</title>
		<link>http://www.wetfeetblog.com/google-app-engine-full-text-search-with-jdo-revisited/368</link>
		<comments>http://www.wetfeetblog.com/google-app-engine-full-text-search-with-jdo-revisited/368#comments</comments>
		<pubDate>Wed, 19 May 2010 15:08:45 +0000</pubDate>
		<dc:creator>Tomas Mazukna</dc:creator>
				<category><![CDATA[Google App Engine]]></category>
		<category><![CDATA[JDO]]></category>

		<guid isPermaLink="false">http://www.wetfeetblog.com/?p=368</guid>
		<description><![CDATA[Objective This article will show you how to implement a full text search in Google App Engine using JDO. I tried my hand at this couple month ago, but after watching this presentation I decided to do it properly. The Problem In my first attempt I managed to get the search working, but after watching [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.wetfeetblog.com/wp-content/uploads/2010/05/files_and_archives_3.jpg" alt="" title="files_and_archives_3" class="float-right" /></p>
<h3>Objective</h3>
<p>This article will show you how to implement a full text search in Google App Engine using JDO. I tried my hand at this <a href="http://www.wetfeetblog.com/google_app_engine-java-jdo-simple_search/287" >couple month ago</a>, but after watching <a href="http://code.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html">this presentation</a> I decided to do it properly.</p>
<h3>The Problem</h3>
<p>In my first attempt I managed to get the search working, but after watching Brett Slatkin&#8217;s presentaion I realized where the problem is. In short deserializing a list of strings (which is our search index) is a very costly operation, but he presented with a solution. Bellow you will find my solution to this problem.<br />
<span id="more-368"></span></p>
<h3>Data Model</h3>
<p>For this example we will use such data model: we have Customer (name, contact, notes) which has a list of Addresses and Phones. We need ability to find customer by name, address or phone. </p>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">@PersistenceCapable<span class="br0">&#40;</span>identityType <span class="sy0">=</span> IdentityType.<span class="me1">APPLICATION</span>, detachable<span class="sy0">=</span><span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
<span class="kw1">public</span> <span class="kw1">class</span> Customer <span class="br0">&#123;</span>
&nbsp; &nbsp; @PrimaryKey
&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>valueStrategy <span class="sy0">=</span> IdGeneratorStrategy.<span class="me1">IDENTITY</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Along+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Long</span></a> id<span class="sy0">;</span>

&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> name<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> contactName<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> comments<span class="sy0">;</span>

&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>mappedBy <span class="sy0">=</span> <span class="st0">&quot;customer&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; @<a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aelement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Element</span></a><span class="br0">&#40;</span>dependent <span class="sy0">=</span> <span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> List<span class="sy0">&lt;</span>Address<span class="sy0">&gt;</span> addresses <span class="sy0">=</span> <span class="kw1">new</span> ArrayList<span class="sy0">&lt;</span>Address<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>

&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>mappedBy <span class="sy0">=</span> <span class="st0">&quot;customer&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; @<a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aelement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Element</span></a><span class="br0">&#40;</span>dependent <span class="sy0">=</span> <span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> List<span class="sy0">&lt;</span>Phone<span class="sy0">&gt;</span> phones <span class="sy0">=</span> <span class="kw1">new</span> ArrayList<span class="sy0">&lt;</span>Phone<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>

&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>dependent<span class="sy0">=</span><span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> CustomerIndex index<span class="sy0">;</span>

&nbsp; &nbsp;<span class="co1">// getters and setter go here....</span>
<span class="br0">&#125;</span>

@PersistenceCapable<span class="br0">&#40;</span>identityType <span class="sy0">=</span> IdentityType.<span class="me1">APPLICATION</span>, detachable<span class="sy0">=</span><span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
<span class="kw1">public</span> <span class="kw1">class</span> Address <span class="br0">&#123;</span>
&nbsp; &nbsp; @PrimaryKey
&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>valueStrategy <span class="sy0">=</span> IdGeneratorStrategy.<span class="me1">IDENTITY</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Akey+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Key</span></a> id<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> type<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> line1<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> line2<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> city<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> state<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> zip<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> Customer customer<span class="sy0">;</span>

&nbsp; &nbsp;<span class="co1">// getters and setter go here....</span>
<span class="br0">&#125;</span>

@PersistenceCapable<span class="br0">&#40;</span>identityType <span class="sy0">=</span> IdentityType.<span class="me1">APPLICATION</span>, detachable<span class="sy0">=</span><span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
<span class="kw1">public</span> <span class="kw1">class</span> Phone <span class="br0">&#123;</span>
&nbsp; &nbsp;@PrimaryKey
&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>valueStrategy <span class="sy0">=</span> IdGeneratorStrategy.<span class="me1">IDENTITY</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Akey+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Key</span></a> id<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> type<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> phone<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> Customer customer<span class="sy0">;</span>

&nbsp; &nbsp;<span class="co1">// getters and setter go here....</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>If you paid attention you notice that we have an interesting child in the Customer class called CustomerIndex. Here it is:</p>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">@PersistenceCapable<span class="br0">&#40;</span>identityType <span class="sy0">=</span> IdentityType.<span class="me1">APPLICATION</span>, detachable<span class="sy0">=</span><span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
<span class="kw1">public</span> <span class="kw1">class</span> CustomerIndex <span class="br0">&#123;</span>
&nbsp; &nbsp; @PrimaryKey
&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>valueStrategy <span class="sy0">=</span> IdGeneratorStrategy.<span class="me1">IDENTITY</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Akey+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Key</span></a> id<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> Set<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span> index<span class="sy0">;</span>

&nbsp; &nbsp;<span class="co1">// getters and setter go here....</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<h3>Search Approach</h3>
<p>Here is the theory of what we gonna do: Since deserializing of List properties is a very very costly operation (and we do not care abut the data it holds anyway) we move customer search index property into a Child object. We will perform a search on this Child and we will get only the keys of the child objects. This way we do not have to incur the penalty of deserializing our search index (the search happens on the index). Once we have our child object keys we will load Parent objects with those keys. We can do this because a child key is a composite key and always includes parent key.<br />
To make our search more usable we will use <a href="http://lucene.apache.org/">Lucenen</a> and SnowballAnalyzer for word stemming.<br />
Here is the method that gives us the Set of words. We use it to generate the index of searchable words as well as search phrases.</p>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">protected</span> Set<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span> getIndex<span class="br0">&#40;</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> input, <span class="kw4">int</span> maxTokens <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; Set<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span> returnSet <span class="sy0">=</span> <span class="kw1">new</span> HashSet<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="kw1">try</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; Analyzer analyzer <span class="sy0">=</span> &nbsp;<span class="kw1">new</span> SnowballAnalyzer<span class="br0">&#40;</span> org.<span class="me1">apache</span>.<span class="me1">lucene</span>.<span class="me1">util</span>.<span class="me1">Version</span>.<span class="me1">LUCENE_30</span>,<span class="st0">&quot;English&quot;</span>, stopWords<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; TokenStream tokenStream <span class="sy0">=</span> analyzer.<span class="me1">tokenStream</span><span class="br0">&#40;</span> <span class="st0">&quot;content&quot;</span>, <span class="kw1">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astringreader+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">StringReader</span></a><span class="br0">&#40;</span>input<span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span> tokenStream.<span class="me1">incrementToken</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="br0">&#40;</span>returnSet.<span class="me1">size</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">&lt;</span> maxTokens<span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span> tokenStream.<span class="me1">hasAttribute</span><span class="br0">&#40;</span> TermAttribute.<span class="kw1">class</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; TermAttribute attr <span class="sy0">=</span> tokenStream.<span class="me1">getAttribute</span><span class="br0">&#40;</span> TermAttribute.<span class="kw1">class</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; logger.<span class="me1">debug</span><span class="br0">&#40;</span> attr.<span class="me1">term</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; returnSet.<span class="me1">add</span><span class="br0">&#40;</span> attr.<span class="me1">term</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; <span class="br0">&#125;</span><span class="kw1">catch</span><span class="br0">&#40;</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Exception</span></a> exc <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; logger.<span class="me1">equals</span><span class="br0">&#40;</span>exc<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp; <span class="kw1">return</span> returnSet<span class="sy0">;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>Here is our search method:</p>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">public</span> List<span class="sy0">&lt;</span>Customer<span class="sy0">&gt;</span> searchCustomers<span class="br0">&#40;</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> search1, <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Along+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Long</span></a> entityId <span class="br0">&#41;</span> <span class="kw1">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aioexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">IOException</span></a> <span class="br0">&#123;</span>
&nbsp; PersistenceManager pm <span class="sy0">=</span> PMF.<span class="me1">getManager</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>

&nbsp; Set<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span> search <span class="sy0">=</span> getIndex<span class="br0">&#40;</span>search1, 3<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; Query query <span class="sy0">=</span> pm.<span class="me1">newQuery</span><span class="br0">&#40;</span><span class="st0">&quot;SELECT id FROM &quot;</span> <span class="sy0">+</span> CustomerIndex.<span class="kw1">class</span>.<span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; query.<span class="me1">setFilter</span><span class="br0">&#40;</span><span class="st0">&quot;index == param0&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; query.<span class="me1">declareParameters</span><span class="br0">&#40;</span><span class="st0">&quot;String param0&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>

&nbsp; Query query2 <span class="sy0">=</span> pm.<span class="me1">newQuery</span><span class="br0">&#40;</span>Customer.<span class="kw1">class</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; query2.<span class="me1">setFilter</span><span class="br0">&#40;</span><span class="st0">&quot;id == keyParam&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; query2.<span class="me1">declareParameters</span><span class="br0">&#40;</span><span class="st0">&quot;com.google.appengine.api.datastore.Key keyParam&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>

&nbsp; List<span class="sy0">&lt;</span>Customer<span class="sy0">&gt;</span> custs <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span>
&nbsp; List<span class="sy0">&lt;</span>Key<span class="sy0">&gt;</span> keys<span class="sy0">;</span>
&nbsp; List<span class="sy0">&lt;</span>Key<span class="sy0">&gt;</span> parents <span class="sy0">=</span> <span class="kw1">new</span> ArrayList<span class="sy0">&lt;</span>Key<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>

&nbsp; <span class="kw1">try</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; keys <span class="sy0">=</span> <span class="br0">&#40;</span>List<span class="sy0">&lt;</span>Key<span class="sy0">&gt;</span><span class="br0">&#41;</span> query.<span class="me1">execute</span><span class="br0">&#40;</span> search <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Akey+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Key</span></a> k <span class="sy0">:</span> keys<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; parents.<span class="me1">add</span><span class="br0">&#40;</span> k.<span class="me1">getParent</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp; custs <span class="sy0">=</span> <span class="br0">&#40;</span>List<span class="sy0">&lt;</span>Customer<span class="sy0">&gt;</span><span class="br0">&#41;</span> query2.<span class="me1">execute</span><span class="br0">&#40;</span> parents <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="kw1">for</span><span class="br0">&#40;</span> Customer cust <span class="sy0">:</span> custs <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span> Address addr <span class="sy0">:</span> cust.<span class="me1">getAddresses</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; logger.<span class="me1">debug</span><span class="br0">&#40;</span> addr.<span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span> Phone ph <span class="sy0">:</span> cust.<span class="me1">getPhones</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; logger.<span class="me1">debug</span><span class="br0">&#40;</span> ph.<span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; <span class="br0">&#125;</span> <span class="kw1">catch</span> <span class="br0">&#40;</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Exception</span></a> exc <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; logger.<span class="me1">error</span><span class="br0">&#40;</span>exc<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span> <span class="kw1">finally</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; query.<span class="me1">closeAll</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; query2.<span class="me1">closeAll</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; pm.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp; <span class="kw1">return</span> custs<span class="sy0">;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>You will notice that we walk the address and Phone lists for each customer to load them form Storage. We do that so we can ship them over the wire. UI in this case is a Flex client, so we do JSON serialization of the results.</p>
<h3>Conclusion</h3>
<p>Text searching can be implemented in GAE and to boot it can be implemented efficiently. Just remember before you store this Customer record you need to build out the CustomerIndex object with the set of words that we will search on. I just concat all the properties to one string and Lucene build the set for me by calling my getIndex().</p>
]]></content:encoded>
			<wfw:commentRss>http://www.wetfeetblog.com/google-app-engine-full-text-search-with-jdo-revisited/368/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Spring JDBC Template &#8211; A leaner alternative to fat Hibernate</title>
		<link>http://www.wetfeetblog.com/spring-jdbc-template-leaner-alternative-fat-hibernate/328</link>
		<comments>http://www.wetfeetblog.com/spring-jdbc-template-leaner-alternative-fat-hibernate/328#comments</comments>
		<pubDate>Tue, 23 Feb 2010 14:00:12 +0000</pubDate>
		<dc:creator>Tomas Mazukna</dc:creator>
				<category><![CDATA[Spring Framework]]></category>
		<category><![CDATA[jdbc]]></category>
		<category><![CDATA[JDO]]></category>

		<guid isPermaLink="false">http://www.wetfeetblog.com/?p=328</guid>
		<description><![CDATA[Objective This post will show you how to use Spring JDBC Template to perform real world CRUD operations. I hope I can show you that you do not need overweight Hibernate to interact with database of your choice. The Problem Domain Almost all application I have coded needed to store and get data of some [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.wetfeetblog.com/wp-content/uploads/2010/02/network_server_2.jpg" alt="" title="network_server_2" width="300" height="225" class="float-right" /></p>
<h3>Objective</h3>
<p>This post will show you how to use Spring JDBC Template to perform real world CRUD operations. I hope I can show you that you do not need overweight Hibernate to interact with database of your choice.</p>
<h3>The Problem Domain</h3>
<p>Almost all application I have coded needed to store and get data of some sort. In most cases it was relational database. With hibernate being all the rage these days I have used it in multiple projects with varying degree of problems and success. In <strong>my personal</strong> opinion hibernate tries to solve a problem that really is not there. If you can not wire SQL you should not be using Hibernate or be doing any software development.<br />
<span id="more-328"></span><br />
I advise the use of Spring JDBC templates. In essence Spring JDBC Template will offload all the mundane steps of database access from you shoulders only requiring you to write SQL and move data from result set into your model objects. Here is how Spring documentation describes responsibilities:</p>
<table summary="Spring JDBC - who does what?" style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; border-left: 0.5pt solid ; border-right: 0.5pt solid ; " width="80%">
<colgroup>
<col>
<col>
<col></colgroup>
<thead>
<tr>
<th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">Action</th>
<th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">Spring</th>
<th style="border-bottom: 0.5pt solid ; " align="center">You</th>
</tr>
</thead>
<tbody>
<tr>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left">Define connection parameters.</td>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center"><span class="bold"><strong></strong></span></td>
<td style="border-bottom: 0.5pt solid ; " align="center">X</td>
</tr>
<tr>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left">Open the connection.</td>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">X</td>
<td style="border-bottom: 0.5pt solid ; " align="center">&nbsp;</td>
</tr>
<tr>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left">Specify the SQL statement.</td>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">&nbsp;</td>
<td style="border-bottom: 0.5pt solid ; " align="center">X</td>
</tr>
<tr>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left">Declare parameters and provide parameter values</td>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">&nbsp;</td>
<td style="border-bottom: 0.5pt solid ; " align="center">X</td>
</tr>
<tr>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left">Prepare and execute the statement.</td>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">X</td>
<td style="border-bottom: 0.5pt solid ; " align="center">&nbsp;</td>
</tr>
<tr>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left">Set up the loop to iterate through the results (if any).</td>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">X</td>
<td style="border-bottom: 0.5pt solid ; " align="center">&nbsp;</td>
</tr>
<tr>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left">Do the work for each iteration.</td>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">&nbsp;</td>
<td style="border-bottom: 0.5pt solid ; " align="center">X</td>
</tr>
<tr>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left">Process any exception.</td>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">X</td>
<td style="border-bottom: 0.5pt solid ; " align="center">&nbsp;</td>
</tr>
<tr>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left">Handle transactions.</td>
<td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="center">X</td>
<td style="border-bottom: 0.5pt solid ; " align="center">&nbsp;</td>
</tr>
<tr>
<td style="border-right: 0.5pt solid ; " align="left">Close the connection, statement and resultset.</td>
<td style="border-right: 0.5pt solid ; " align="center">X</td>
<td style="" align="center">&nbsp;</td>
</tr>
</tbody>
</table>
<p><br/></p>
<h3>CRUD Example with Spring JDBC Template</h3>
<p>For this example you will need spring-core, spring-tx and spring-aop components. We will use spring-tx to manage the transaction so we can get back the auto generated IDs of the persisted objects and aop to set up the transaction management. Here is meat for spring configuration file:</p>
<pre>
<div class="codesnip-container" >
<div class="xml codesnip" style="font-family:monospace;"><span class="sc3"><span class="re1">&lt;bean</span> <span class="re0">id</span>=<span class="st0">&quot;propertyPlaceholder&quot;</span> </span>
<span class="sc3"> &nbsp; &nbsp; &nbsp;<span class="re0">class</span>=<span class="st0">&quot;org.springframework.beans.factory.config.PropertyPlaceholderConfigurer&quot;</span> <span class="re2">&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;location&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;/WEB-INF/config.properties&quot;</span> <span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;/bean<span class="re2">&gt;</span></span></span>

<span class="sc3"><span class="re1">&lt;bean</span> <span class="re0">id</span>=<span class="st0">&quot;mysqlDataSource&quot;</span> <span class="re0">class</span>=<span class="st0">&quot;com.mchange.v2.c3p0.ComboPooledDataSource&quot;</span> </span>
<span class="sc3"> &nbsp; &nbsp; &nbsp;<span class="re0">destroy-method</span>=<span class="st0">&quot;close&quot;</span><span class="re2">&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;driverClass&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;com.mysql.jdbc.Driver&quot;</span><span class="re2">/&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;jdbcUrl&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;${database.url}&quot;</span><span class="re2">/&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;user&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;${database.user}&quot;</span><span class="re2">/&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;password&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;${database.password}&quot;</span><span class="re2">/&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;initialPoolSize&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;${database.connections.start}&quot;</span><span class="re2">/&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;maxPoolSize&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;${database.connections.max}&quot;</span><span class="re2">/&gt;</span></span> &nbsp;
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;idleConnectionTestPeriod&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;270&quot;</span> <span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;/bean<span class="re2">&gt;</span></span></span>

<span class="sc3"><span class="re1">&lt;bean</span> <span class="re0">id</span>=<span class="st0">&quot;txManager&quot;</span> </span>
<span class="sc3"> &nbsp; &nbsp; &nbsp;<span class="re0">class</span>=<span class="st0">&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;</span> <span class="re2">&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;dataSource&quot;</span> <span class="re0">ref</span>=<span class="st0">&quot;mysqlDataSource&quot;</span> <span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;/bean<span class="re2">&gt;</span></span></span>

<span class="sc3"><span class="re1">&lt;tx:advice</span> <span class="re0">id</span>=<span class="st0">&quot;txAdvice&quot;</span> <span class="re0">transaction-manager</span>=<span class="st0">&quot;txManager&quot;</span><span class="re2">&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;tx:attributes<span class="re2">&gt;</span></span></span>
&nbsp; &nbsp; <span class="sc-1">&lt;!-- all methods starting with 'get' are read-only --&gt;</span>
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;tx:method</span> <span class="re0">name</span>=<span class="st0">&quot;get*&quot;</span> <span class="re0">read-only</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;tx:method</span> <span class="re0">name</span>=<span class="st0">&quot;list*&quot;</span> <span class="re0">read-only</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
&nbsp; &nbsp; &nbsp; <span class="sc-1">&lt;!-- other methods use the default transaction settings (see below) --&gt;</span>
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;tx:method</span> <span class="re0">name</span>=<span class="st0">&quot;*&quot;</span><span class="re2">/&gt;</span></span>
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/tx:attributes<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/tx:advice<span class="re2">&gt;</span></span></span>

<span class="sc3"><span class="re1">&lt;aop:config<span class="re2">&gt;</span></span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;aop:pointcut</span> <span class="re0">id</span>=<span class="st0">&quot;uOwnerDataSvcOperation&quot;</span> </span>
<span class="sc3"> &nbsp; &nbsp; &nbsp;<span class="re0">expression</span>=<span class="st0">&quot;execution(* com.es.rto.dao.UOwnerDataServiceImpl.*(..))&quot;</span><span class="re2">/&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;aop:advisor</span> <span class="re0">advice-ref</span>=<span class="st0">&quot;txAdvice&quot;</span> <span class="re0">pointcut-ref</span>=<span class="st0">&quot;uOwnerDataSvcOperation&quot;</span><span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;/aop:config<span class="re2">&gt;</span></span></span>

<span class="sc3"><span class="re1">&lt;bean</span> <span class="re0">id</span>=<span class="st0">&quot;namedTemplate&quot;</span> </span>
<span class="sc3"> &nbsp; &nbsp;<span class="re0">class</span>=<span class="st0">&quot;org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate&quot;</span><span class="re2">&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;constructor-arg</span> <span class="re0">index</span>=<span class="st0">&quot;0&quot;</span> <span class="re0">ref</span>=<span class="st0">&quot;mysqlDataSource&quot;</span><span class="re2">/&gt;</span></span> &nbsp; 
<span class="sc3"><span class="re1">&lt;/bean<span class="re2">&gt;</span></span></span>

<span class="sc3"><span class="re1">&lt;bean</span> <span class="re0">id</span>=<span class="st0">&quot;qandADao&quot;</span> <span class="re0">class</span>=<span class="st0">&quot;com.es.rto.dao.QandADao&quot;</span> <span class="re2">&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;jdbcTemplate&quot;</span> <span class="re0">ref</span>=<span class="st0">&quot;namedTemplate&quot;</span> <span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;/bean<span class="re2">&gt;</span></span></span>

<span class="sc3"><span class="re1">&lt;bean</span> <span class="re0">id</span>=<span class="st0">&quot;uOwnerDataSvc&quot;</span> <span class="re0">class</span>=<span class="st0">&quot;com.es.rto.dao.UOwnerDataServiceImpl&quot;</span> <span class="re2">&gt;</span></span>
&nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;qandADao&quot;</span> <span class="re0">ref</span>=<span class="st0">&quot;qandADao&quot;</span> <span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;/bean<span class="re2">&gt;</span></span></span></div>
</div>
</pre>
<p>First thing we do we load our config.properties file where we have database configuration defined. Second we define a pooled data source to connect to mysql database. Third bean is a transaction manager that is watching our data source from the step two. Next we set up our transaction manager. We instruct transaction manager that methods starting with &#8220;get&#8221; and &#8220;list&#8221; are read only. This means that they will not be subject to transaction management. Then we define named jdbc template and pass in the data source as first constructor argument and then pass in the template into our own DAO bean.</p>
<h3>Why do we need Transaction Management?</h3>
<p>When we create a new row in a mysql table with autoincrement id value we need a way to get that auto generated id. To do so we need to query the database using same connection. When we use jdbcTemplate.update() or jdbcTemplate.query() it will check out a connection form the pool execute the query, process the results and return this connection to the pool. So if we do update() and then get() to query &#8220;SELECT LAST_INSERT_ID()&#8221; we will get another connection, which is a problem since we need to do this on the same connection to get the right id. This is where the transaction comes in. Instead of releasing connection back to the pool spring will hold on to it until we are done with it.</p>
<h3>Java code side of the Spring JDBC template</h3>
<p> We will use 3 beans to illustrate the scenario: question, answer and user.</p>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw1">class</span> Question <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">long</span> questionId<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">long</span> categoryId<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">long</span> userId<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">long</span> areaId<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> question<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> verifyKey<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adate+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Date</span></a> created<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> User user<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> List<span class="sy0">&lt;</span>Answer<span class="sy0">&gt;</span> answers<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">long</span> answerCount<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> name<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// getters and setters omited...</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw1">class</span> Answer <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">long</span> answerId<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">long</span> questionId<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">long</span> userId<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> answer<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> verifyKey<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> url<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Adate+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Date</span></a> created<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> User user<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> name<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// getters and setters omited...</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw1">class</span> User <span class="kw1">implements</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aserializable+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Serializable</span></a> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">long</span> id<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> email<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> retypeE<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> name<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> password<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> password2<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> verifyKey<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">boolean</span> buyer<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">boolean</span> seller<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">boolean</span> active<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">boolean</span> privacy<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">int</span> pageSize <span class="sy0">=</span> <span class="nu0">20</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> next<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">boolean</span> administrator<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// getters and setters omited...</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>Here are the 2 classes that do all the work:</p>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw1">class</span> QandADao <span class="br0">&#123;</span>

&nbsp; <span class="kw1">private</span> <span class="kw1">final</span> Logger logger <span class="sy0">=</span> Logger.<span class="me1">getLogger</span><span class="br0">&#40;</span>QandADao.<span class="kw1">class</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="kw1">protected</span> NamedParameterJdbcTemplate jdbcTemplate <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span>
&nbsp; 

&nbsp; @SuppressWarnings<span class="br0">&#40;</span><span class="st0">&quot;unchecked&quot;</span><span class="br0">&#41;</span>
&nbsp; <span class="kw1">public</span> List<span class="sy0">&lt;</span>Question<span class="sy0">&gt;</span> getQuestions<span class="br0">&#40;</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> search, <span class="kw4">int</span> page, <span class="kw4">int</span> step <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">try</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; MapSqlParameterSource params <span class="sy0">=</span> <span class="kw1">new</span> MapSqlParameterSource<span class="br0">&#40;</span> <span class="st0">&quot;search&quot;</span>, <span class="st0">&quot;%&quot;</span><span class="sy0">+</span>search<span class="sy0">+</span><span class="st0">&quot;%&quot;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> sql <span class="sy0">=</span> <span class="st0">&quot;SELECT q.*, count( a.answer_id ) as answers, u.name, u.seller &nbsp;FROM users u, questions q LEFT JOIN answers a &quot;</span><span class="sy0">+</span>
&nbsp; &nbsp; &nbsp; <span class="st0">&quot;ON &nbsp;a.question_id = q.question_id WHERE a.answer LIKE :search AND q.user_id = u.id &quot;</span><span class="sy0">+</span>
&nbsp; &nbsp; &nbsp; <span class="st0">&quot;GROUP BY q.question_id, q.category_id, q.user_id, q.question, q.created, q.area_id, u.name, u.seller &quot;</span><span class="sy0">+</span> &nbsp;
&nbsp; &nbsp; &nbsp; <span class="st0">&quot;UNION &quot;</span><span class="sy0">+</span>
&nbsp; &nbsp; &nbsp; <span class="st0">&quot;SELECT q.*, count( a.answer_id ) as answers, u.name, u.seller &nbsp;FROM users u, questions q LEFT JOIN answers a &quot;</span><span class="sy0">+</span> 
&nbsp; &nbsp; &nbsp; <span class="st0">&quot;ON &nbsp;a.question_id = q.question_id WHERE q.question LIKE :search AND q.user_id = u.id &quot;</span><span class="sy0">+</span>
&nbsp; &nbsp; &nbsp; <span class="st0">&quot;GROUP BY q.question_id, q.category_id, q.user_id, q.question, q.created, q.area_id, u.name, u.seller &quot;</span><span class="sy0">+</span>
&nbsp; &nbsp; &nbsp; <span class="st0">&quot;LIMIT &quot;</span><span class="sy0">+</span><span class="br0">&#40;</span>step<span class="sy0">*</span><span class="br0">&#40;</span>page<span class="sy0">-</span><span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">+</span><span class="st0">&quot;, &quot;</span><span class="sy0">+</span>step<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; logger.<span class="me1">debug</span><span class="br0">&#40;</span> sql <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> jdbcTemplate.<span class="me1">query</span><span class="br0">&#40;</span>sql, params, <span class="kw1">new</span> RowMappers.<span class="me1">QuestionsMapper</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">catch</span> <span class="br0">&#40;</span> DataAccessException exc <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; logger.<span class="me1">error</span><span class="br0">&#40;</span><span class="st0">&quot;FAILED to get Question List&quot;</span>, exc<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">new</span> ArrayList<span class="sy0">&lt;</span>Question<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; <span class="br0">&#125;</span>

&nbsp; <span class="kw1">public</span> Question saveQuestion<span class="br0">&#40;</span> Question question <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">try</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; BeanPropertySqlParameterSource namedParameters <span class="sy0">=</span> <span class="kw1">new</span> BeanPropertySqlParameterSource<span class="br0">&#40;</span>question<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> sql<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span> question.<span class="me1">getQuestionId</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">==</span> <span class="nu0">0</span> <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; sql <span class="sy0">=</span> <span class="st0">&quot;INSERT INTO questions ( category_id, user_id, question, area_id, uname ) VALUES ( :categoryId, :userId, :question, :areaId, :name )&quot;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; &nbsp; &nbsp; sql <span class="sy0">=</span> <span class="st0">&quot;UPDATE questions SET question=:question, category_id=:categoryId, area_id=:areaId WHERE question_id=:questionId&quot;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; logger.<span class="me1">debug</span><span class="br0">&#40;</span> sql <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; jdbcTemplate.<span class="me1">update</span><span class="br0">&#40;</span>sql, namedParameters<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span> question.<span class="me1">getQuestionId</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">==</span> 0 <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; question.<span class="me1">setQuestionId</span><span class="br0">&#40;</span> <span class="kw1">this</span>.<span class="me1">getInsertedID</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">catch</span> <span class="br0">&#40;</span> DataAccessException exc <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; logger.<span class="me1">error</span><span class="br0">&#40;</span><span class="st0">&quot;SAVE answer FAILED!&quot;</span>, exc<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">throw</span> exc<span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="kw1">return</span> question<span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>

&nbsp; <span class="kw1">protected</span> <span class="kw4">long</span> getInsertedID<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> jdbcTemplate.<span class="me1">queryForLong</span><span class="br0">&#40;</span> <span class="st0">&quot;SELECT LAST_INSERT_ID()&quot;</span> , <span class="kw1">new</span> MapSqlParameterSource<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp; 
<span class="br0">&#125;</span></div>
</div>
</pre>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw1">class</span> RowMappers <span class="br0">&#123;</span>

&nbsp; <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">final</span> <span class="kw1">class</span> QuestionMapper <span class="kw1">implements</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Arowmapper+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">RowMapper</span></a> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">public</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aobject+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Object</span></a> mapRow<span class="br0">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aresultset+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">ResultSet</span></a> rs, <span class="kw4">int</span> rowNum<span class="br0">&#41;</span> <span class="kw1">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asqlexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">SQLException</span></a> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; Question q <span class="sy0">=</span> <span class="kw1">new</span> Question<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; q.<span class="me1">setQuestionId</span><span class="br0">&#40;</span>rs.<span class="me1">getLong</span><span class="br0">&#40;</span> <span class="st0">&quot;question_id&quot;</span> <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; q.<span class="me1">setCategoryId</span><span class="br0">&#40;</span>rs.<span class="me1">getLong</span><span class="br0">&#40;</span> <span class="st0">&quot;category_id&quot;</span> <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; q.<span class="me1">setUserId</span><span class="br0">&#40;</span>rs.<span class="me1">getLong</span><span class="br0">&#40;</span> <span class="st0">&quot;user_id&quot;</span> <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; q.<span class="me1">setAreaId</span><span class="br0">&#40;</span> rs.<span class="me1">getLong</span><span class="br0">&#40;</span><span class="st0">&quot;area_id&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; q.<span class="me1">setQuestion</span><span class="br0">&#40;</span> rs.<span class="me1">getString</span><span class="br0">&#40;</span><span class="st0">&quot;question&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; q.<span class="me1">setCreated</span><span class="br0">&#40;</span> rs.<span class="me1">getTimestamp</span><span class="br0">&#40;</span> <span class="st0">&quot;created&quot;</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; q.<span class="me1">setName</span><span class="br0">&#40;</span> rs.<span class="me1">getString</span><span class="br0">&#40;</span><span class="st0">&quot;uname&quot;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; User u <span class="sy0">=</span> <span class="kw1">new</span> User<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; u.<span class="me1">setName</span><span class="br0">&#40;</span> rs.<span class="me1">getString</span><span class="br0">&#40;</span><span class="st0">&quot;name&quot;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; u.<span class="me1">setSeller</span><span class="br0">&#40;</span> rs.<span class="me1">getBoolean</span><span class="br0">&#40;</span><span class="st0">&quot;seller&quot;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; u.<span class="me1">setId</span><span class="br0">&#40;</span>q.<span class="me1">getUserId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; q.<span class="me1">setUser</span><span class="br0">&#40;</span>u<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> q<span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; <span class="br0">&#125;</span> 
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>So what is going on here? Lets look at the <strong>QuestionMapper</strong>. It implements one method &#8211; mapRow. Its hob is to process a single row of the result set. As you see here we create a Question bean and a User bean which is included in the Questions bean. It can not be more strait forward then this.</p>
<p><strong>QandADao</strong> is the class where all the magic happens. First lets examine the getQuestions() method. First we define query parameter(s) using MapSqlParameterSource class. We simply put the values in the map and jdbc template will pull them out by the key. Next we write our sql query. In this case iti is pretty complex to pull out any questions where either question or the answer have the thing we are searching for. We use union to be able to pull out  the questions without the answers. Lastly we call query method on the jdbc template and we pass in our query, parameters and the row mapper instance. Spring takes care of all the plumbing. What we get out of this call is a list of Question objects.</p>
<p>saveQuestion() method is not much different. In this case we use BeanPropertySqlParameterSource which maps bean properties to sql parameters. If you define a sql parameter &#8220;name&#8221; your bean should have &#8220;getName()&#8221; method. Instead of calling query() we call update() on the jdbc template which only takes sql and the parameters.</p>
<h3>Conclusion</h3>
<p>You may have noticed that the effort to use the Spring approach to JDCB is very simple, flexible and powerful. You have all the control in all the right places! You write the sql with all the performance hints and tweaks, you write code how to transfer results to the domain objects the way you need it or like it. I only mentioned about one tenth of the options you have with spring. <a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jdbc.html">Read The Fine Manual (RTFM)</a> to explore the full potential.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.wetfeetblog.com/spring-jdbc-template-leaner-alternative-fat-hibernate/328/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google App Engine + JAVA + JDO = Simple Search</title>
		<link>http://www.wetfeetblog.com/google_app_engine-java-jdo-simple_search/287</link>
		<comments>http://www.wetfeetblog.com/google_app_engine-java-jdo-simple_search/287#comments</comments>
		<pubDate>Wed, 10 Feb 2010 15:02:24 +0000</pubDate>
		<dc:creator>Tomas Mazukna</dc:creator>
				<category><![CDATA[Google App Engine]]></category>
		<category><![CDATA[Spring Framework]]></category>
		<category><![CDATA[JDO]]></category>

		<guid isPermaLink="false">http://www.wetfeetblog.com/?p=287</guid>
		<description><![CDATA[Objective This article will show you how to implement a simple search in Google App Engine using JDO engine including searching in child objects. The Problem Domain In my application I need to search for data and you probably need to do the same in yours. In Google App Engine you can not query for [...]]]></description>
			<content:encoded><![CDATA[<p><img class="float-right" title="files_and_archives" src="http://www.wetfeetblog.com/wp-content/uploads/2010/02/files_and_archives.jpg" alt="" width="200" height="144" /></p>
<h3>Objective</h3>
<p>This article will show you how to implement a simple search in Google App Engine using JDO engine including searching in child objects.</p>
<h3>The Problem Domain</h3>
<p>In my application I need to search for data and you probably need to do the same in yours. In Google App Engine you can not query for properties of the child objects. In SQL world this means you can not use &#8220;where&#8221; clause. So how we can not construct a query which looks at child objects. So how can we implement search in such restrictive environment?<br />
<span id="more-287"></span></p>
<h3>The Solution</h3>
<p>I came up with a very simple solution &#8211; I created an &#8220;index&#8221; property where I store all the data that I need to search on. Let&#8217;s say we have a Customer bean that has multiple addresses and phones. We want to be able to search on address, phone and customer name. Here are our beans:</p>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">@PersistenceCapable<span class="br0">&#40;</span>identityType <span class="sy0">=</span> IdentityType.<span class="me1">APPLICATION</span>, detachable<span class="sy0">=</span><span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
<span class="kw1">public</span> <span class="kw1">class</span> Customer <span class="kw1">implements</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aserializable+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Serializable</span></a> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">private</span> <span class="kw1">static</span> <span class="kw1">final</span> <span class="kw4">long</span> serialVersionUID <span class="sy0">=</span> <span class="sy0">-</span>3665292067832675548L<span class="sy0">;</span>

&nbsp; &nbsp; @PrimaryKey
&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>valueStrategy <span class="sy0">=</span> IdGeneratorStrategy.<span class="me1">IDENTITY</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Along+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Long</span></a> id<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> name<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> contactName<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> comments<span class="sy0">;</span>

&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>mappedBy <span class="sy0">=</span> <span class="st0">&quot;customer&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; @<a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aelement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Element</span></a><span class="br0">&#40;</span>dependent <span class="sy0">=</span> <span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> List<span class="sy0">&lt;</span>Address<span class="sy0">&gt;</span> addresses <span class="sy0">=</span> <span class="kw1">new</span> ArrayList<span class="sy0">&lt;</span>Address<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>

&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>mappedBy <span class="sy0">=</span> <span class="st0">&quot;customer&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; @<a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aelement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Element</span></a><span class="br0">&#40;</span>dependent <span class="sy0">=</span> <span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> List<span class="sy0">&lt;</span>Phone<span class="sy0">&gt;</span> phones <span class="sy0">=</span> <span class="kw1">new</span> ArrayList<span class="sy0">&lt;</span>Phone<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>

&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> List<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span> index<span class="sy0">;</span>

&nbsp; &nbsp; <span class="co1">// Getters and Setter go here...</span>
<span class="br0">&#125;</span>

@PersistenceCapable<span class="br0">&#40;</span>identityType <span class="sy0">=</span> IdentityType.<span class="me1">APPLICATION</span>, detachable<span class="sy0">=</span><span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
<span class="kw1">public</span> <span class="kw1">class</span> Address <span class="br0">&#123;</span>
&nbsp; &nbsp; @PrimaryKey
&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>valueStrategy <span class="sy0">=</span> IdGeneratorStrategy.<span class="me1">IDENTITY</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Akey+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Key</span></a> id<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> type<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> name<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> line1<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> line2<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> city<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> state<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> zip<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> Customer customer<span class="sy0">;</span>

&nbsp; &nbsp; <span class="co1">// Getters and Setter go here...</span>
<span class="br0">&#125;</span>

@PersistenceCapable<span class="br0">&#40;</span>identityType <span class="sy0">=</span> IdentityType.<span class="me1">APPLICATION</span>, detachable<span class="sy0">=</span><span class="st0">&quot;true&quot;</span><span class="br0">&#41;</span>
<span class="kw1">public</span> <span class="kw1">class</span> Phone <span class="br0">&#123;</span>
&nbsp; &nbsp; @PrimaryKey
&nbsp; &nbsp; @Persistent<span class="br0">&#40;</span>valueStrategy <span class="sy0">=</span> IdGeneratorStrategy.<span class="me1">IDENTITY</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Akey+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Key</span></a> id<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> type<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Anumber+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Number</span></a> phone<span class="sy0">;</span>
&nbsp; &nbsp; @Persistent
&nbsp; &nbsp; <span class="kw1">private</span> Customer customer<span class="sy0">;</span>

&nbsp; &nbsp; <span class="co1">// Getters and Setter go here...</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>In the Customer bean we defined an &#8220;index&#8221; property which is a String array. We will put all our searchable words int this index, so later we can construct a query. Before we save our customer we want to populate index property like this:</p>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw4">void</span> rebuildIndex<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; index <span class="sy0">=</span> <span class="kw1">new</span> ArrayList<span class="sy0">&lt;</span>String<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; Iterator<span class="sy0">&lt;</span>Address<span class="sy0">&gt;</span> it <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">addresses</span>.<span class="me1">iterator</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span><span class="br0">&#40;</span> it.<span class="me1">hasNext</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Address ad <span class="sy0">=</span> it.<span class="me1">next</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span> ad.<span class="me1">getLine1</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> <span class="kw2">null</span> <span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> idx <span class="sy0">=</span> ad.<span class="me1">getLine1</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">split</span><span class="br0">&#40;</span><span class="st0">&quot; &quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span> <span class="kw4">int</span> i <span class="sy0">=</span> 0 <span class="sy0">;</span> i <span class="sy0">&lt;</span> idx.<span class="me1">length</span> <span class="sy0">;</span> i<span class="sy0">++</span> <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index.<span class="me1">add</span><span class="br0">&#40;</span> idx<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span> ad.<span class="me1">getLine2</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> <span class="kw2">null</span> <span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> idx <span class="sy0">=</span> ad.<span class="me1">getLine2</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">split</span><span class="br0">&#40;</span><span class="st0">&quot; &quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span> <span class="kw4">int</span> i <span class="sy0">=</span> 0 <span class="sy0">;</span> i <span class="sy0">&lt;</span> idx.<span class="me1">length</span> <span class="sy0">;</span> i<span class="sy0">++</span> <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index.<span class="me1">add</span><span class="br0">&#40;</span> idx<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; Iterator<span class="sy0">&lt;</span>Phone<span class="sy0">&gt;</span> it2 <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">phones</span>.<span class="me1">iterator</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span><span class="br0">&#40;</span> it2.<span class="me1">hasNext</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Phone ph <span class="sy0">=</span> it2.<span class="me1">next</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span> ph.<span class="me1">getPhone</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> <span class="kw2">null</span> <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index.<span class="me1">add</span><span class="br0">&#40;</span> ph.<span class="me1">getPhone</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">toString</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> idx <span class="sy0">=</span> name.<span class="me1">split</span><span class="br0">&#40;</span><span class="st0">&quot; &quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span> <span class="kw4">int</span> i <span class="sy0">=</span> 0 <span class="sy0">;</span> i <span class="sy0">&lt;</span> idx.<span class="me1">length</span> <span class="sy0">;</span> i<span class="sy0">++</span> <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index.<span class="me1">add</span><span class="br0">&#40;</span> idx<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; idx <span class="sy0">=</span> contactName.<span class="me1">split</span><span class="br0">&#40;</span><span class="st0">&quot; &quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span> <span class="kw4">int</span> i <span class="sy0">=</span> 0 <span class="sy0">;</span> i <span class="sy0">&lt;</span> idx.<span class="me1">length</span> <span class="sy0">;</span> i<span class="sy0">++</span> <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index.<span class="me1">add</span><span class="br0">&#40;</span> idx<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>Now we have all our searchable words from child beans and parent bean in one property we can search on. Here is how my search method looks like:</p>
<pre>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">@SuppressWarnings<span class="br0">&#40;</span><span class="st0">&quot;unchecked&quot;</span><span class="br0">&#41;</span>
@ModelAttribute<span class="br0">&#40;</span><span class="st0">&quot;custs&quot;</span><span class="br0">&#41;</span>
@RequestMapping<span class="br0">&#40;</span>value <span class="sy0">=</span> <span class="st0">&quot;/{search}&quot;</span>, method <span class="sy0">=</span> RequestMethod.<span class="me1">GET</span><span class="br0">&#41;</span>
<span class="kw1">public</span> List<span class="sy0">&lt;</span>Customer<span class="sy0">&gt;</span> searchCustomers<span class="br0">&#40;</span> @PathVariable <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> search, HttpSession session<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aioexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">IOException</span></a> <span class="br0">&#123;</span>
&nbsp; &nbsp; PersistenceManager pm <span class="sy0">=</span> pmf.<span class="me1">getManager</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; Query query <span class="sy0">=</span> pm.<span class="me1">newQuery</span><span class="br0">&#40;</span>Customer.<span class="kw1">class</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; query.<span class="me1">setFilter</span><span class="br0">&#40;</span><span class="st0">&quot;index == searchParam&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; query.<span class="me1">declareParameters</span><span class="br0">&#40;</span><span class="st0">&quot;String searchParam&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; List<span class="sy0">&lt;</span>Customer<span class="sy0">&gt;</span> custs<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">try</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; custs <span class="sy0">=</span> <span class="br0">&#40;</span>List<span class="sy0">&lt;</span>Customer<span class="sy0">&gt;</span><span class="br0">&#41;</span> query.<span class="me1">execute</span><span class="br0">&#40;</span> search <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">finally</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; query.<span class="me1">closeAll</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="kw1">return</span> custs<span class="sy0">;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<h3>Conclusion</h3>
<p>We found an easy way around the big table JDO implementation limitation in Google App Engine. It is a simple and strait forward workaround, but it has couple drawbacks: we can only search on full words and we duplicate data using more storage space. In my book storage is cheap so that is not a big concern for me. </p>
<p>As I progress more with my projects on Google App Engine, I will surely revisit the search topic and post about other solutions to this challenge. </p>
<p>If you have a better solution please post it in the comments, I would love to give it a try!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.wetfeetblog.com/google_app_engine-java-jdo-simple_search/287/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
