<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.0.1" -->
<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/"
	>

<channel>
	<title>SpencerUresk</title>
	<link>http://www.spenceruresk.com</link>
	<description>Random posts about Java, software development, politics, and economics</description>
	<pubDate>Thu, 03 Jul 2008 06:14:07 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.0.1</generator>
	<language>en</language>
			<item>
		<title>Quickly Redeploying Grails Apps</title>
		<link>http://www.spenceruresk.com/2008/07/02/quickly-redeploying-grails-apps/</link>
		<comments>http://www.spenceruresk.com/2008/07/02/quickly-redeploying-grails-apps/#comments</comments>
		<pubDate>Wed, 02 Jul 2008 06:30:53 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Software Development</category>
	<category>Websites</category>
	<category>Groovy</category>
	<category>Grails</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/07/02/quickly-redeploying-grails-apps/</guid>
		<description><![CDATA[I&#8217;ve been developing a bunch of small Grails apps lately, and I end up deploying them to my production box fairly frequently. This is kind of annoying because the upload speed on my home internet connection is terrible - it sometimes takes 7 or 8 minutes to upload a new WAR and during that time, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been developing a bunch of small Grails apps lately, and I end up deploying them to my production box fairly frequently. This is kind of annoying because the upload speed on my home internet connection is terrible - it sometimes takes 7 or 8 minutes to upload a new WAR and during that time, my internet connection is unusable for anything else. I wanted a simple way to push new code to production without uploading a new WAR every time, and I know a few other people were looking for something similar, so here it is. It is pretty boring but it does the job. In my case, I deploy all of mine as ROOT.war, because they are always the default app for their domain. If yours is setup different, just replace ROOT.war with whatever your war should be named.</p>
<p>1. Check your code into Subversion (or CVS or whatever SCM of your choice - this guide assumes Subversion, however).</p>
<p>2. Add a build directory on your prod box (I have mine at /home/build/) - then check out individual projects under it (ie, /home/build/wiifit/).</p>
<p>3. In each project, add a property to application.properties for the deployment directory (ie - deploy.dir=/home/tc6/server/wiifit).</p>
<p>4. In grails, you can add groovy scripts to the /scripts/ directory, and then run them with grails <script-name>, ie, ProdPush.groovy can be called with &#8216;grails prod-push&#8217;. Let&#8217;s add a script in to do the following things:</p>
<p>- Do a subversion checkout to get our latest changes.<br />
- Build the war<br />
- Copy it to our directory</p>
<p>This is what I came up with:</p>
<div class="codesnip-container" >
<div class="codesnip">grailsHome = Ant.<span class="me1">project</span>.<span class="me1">properties</span>.<span class="st0">&#8220;environment.GRAILS_HOME&#8221;</span></p>
<p>includeTargets &lt;&lt; <span class="kw2">new</span> <a href="http://www.google.com/search?q=allinurl%3AFile+java.sun.com&#038;bntl=1"><span class="kw3">File</span></a> <span class="br0">&#40;</span> <span class="st0">&#8220;${grailsHome}/scripts/War.groovy&#8221;</span><span class="br0">&#41;</span></p>
<p>target<span class="br0">&#40;</span><span class="st0">&#8216;default&#8217;</span>: <span class="st0">&#8220;Push a war to prod&#8221;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;println <span class="st0">&#8220;svn up&#8221;</span>.<span class="me1">execute</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">text</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;war<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;Ant.<span class="me1">copy</span><span class="br0">&#40;</span>todir:Ant.<span class="me1">antProject</span>.<span class="me1">properties</span>.<span class="st0">&#8216;deploy.dir&#8217;</span>, overwrite:<span class="kw2">true</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fileset<span class="br0">&#40;</span>dir:<span class="st0">&#8220;.&#8221;</span>, includes:<span class="st0">&#8220;ROOT.war&#8221;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>Your script can have multiple targets. If you specify a &#8216;default&#8217; one, like I have above, it is what will be run if you supply no target (which is what we want).</p>
<p>5. Now I have a simple shell script on my server to setup the environment variables and run the build.</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="co1">#!/bin/bash</span></p>
<p><span class="kw3">export</span> <span class="re2">GROOVY_HOME=</span>/usr/share/groovy<br />
<span class="kw3">export</span> <span class="re2">GRAIILS_HOME=</span>/usr/share/grails<br />
<span class="kw3">export</span> <span class="re2">JAVA_HOME=</span>/usr/java/jdk<br />
<span class="kw3">export</span> <span class="re2">GWT_HOME=</span>/usr/share/gwt</p>
<p><span class="kw3">cd</span> $<span class="nu0">1</span></p>
<p><span class="re1">$GRAILS_HOME</span>/bin/grails -Dgrails.<span class="re2">env=</span>production prod-push ROOT.war</div>
</div>
<p>This script can then be re-used for all projects on the server.</p>
<p>6. To update our app, we simply do the following:</p>
<p>- Check our changes into Subversion<br />
- SSH into our server and go to our /build/ directory<br />
- Run the build script (ie, ./build.sh wiifit)</p>
<p>Our new app is live in less than a minute and we don&#8217;t kill our home internet connection :)</p>
<p>This solution may not be very good for high-usage, critical apps - if I were building (and leaving code) on a production app server at my day job, I&#8217;d be fired (and deserve it!) - but for small apps like I build, it is a good solution. This solution is pretty simple, but I&#8217;m working on a full deployment plugin for grails - fewer setup steps, tomcat management, etc.. If you have any suggestions or ideas, let me know.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/07/02/quickly-redeploying-grails-apps/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Grails + GWT with GWT-EXT + GoogleMaps + MaxMind sample application</title>
		<link>http://www.spenceruresk.com/2008/06/15/grails-gwt-with-gwt-ext-googlemaps-maxmind-sample-application/</link>
		<comments>http://www.spenceruresk.com/2008/06/15/grails-gwt-with-gwt-ext-googlemaps-maxmind-sample-application/#comments</comments>
		<pubDate>Sun, 15 Jun 2008 06:04:38 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Software Development</category>
	<category>Java</category>
	<category>Groovy</category>
	<category>Grails</category>
	<category>GWT</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/06/15/grails-gwt-with-gwt-ext-googlemaps-maxmind-sample-application/</guid>
		<description><![CDATA[I&#8217;ve been playing around with Grails and a bit of GWT lately, and it sure is a lot of fun. I&#8217;ve made some applications that use Grails, GWT, and GoogleMaps (see: Find A Wii Fit), and thought I&#8217;d write a quick tutorial on how to do it - it can be a little tricky.
This application [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been playing around with Grails and a bit of GWT lately, and it sure is a lot of fun. I&#8217;ve made some applications that use <a href="http://www.grails.org/">Grails</a>, <a href="http://code.google.com/webtoolkit/">GWT</a>, and <a href="http://code.google.com/apis/maps/">GoogleMaps</a> (see: <a href="http://www.findawiifit.com/site/map">Find A Wii Fit</a>), and thought I&#8217;d write a quick tutorial on how to do it - it can be a little tricky.</p>
<p>This application is fairly simple - it displays a google map view that is centered on the user&#8217;s location, and inserts a marker where they are located. I am using <a href="http://www.maxmind.com/?rId=uresk">MaxMind</a> to turn an IP into latitude and longitude coordinates. They cost money and you may be able to find a free one, but they aren&#8217;t that expensive (something like $20 for 50,000 lookups) and I&#8217;ve been pretty happy with them so far.</p>
<p>There is a <a href="http://www.grails.org/GWT+Plugin">GWT+Grails</a> plugin that makes it easy for Grails and GWT to work together. I am also using <a href="http://gwt-ext.com/">GWT-EXT</a> to make it look nice, and to make the GoogleMaps integration a little easier. If you want to see this app in action, you can see it <a href="http://www.maptutorials.com/">here</a> (it may not match the example exactly - I&#8217;m actively developing it). I&#8217;ve also made the entire project available for free, <a href="http://www.spenceruresk.com/findme.zip">here</a>.</p>
<p>1.Create a new Grails application (grails create-app findme)</p>
<p>2.Install the Grails + GWT plugin (grails install-plugin gwt)</p>
<p>3.Create your Grails Module (grails create-gwt-module net.uresk.FindMe)</p>
<p>4. Create your page (grails create-gwt-page main/index.gsp net.uresk.FindMe, answer yes when it asks if you want it to create the controller)</p>
<p>5. Download GWT-EXT (<a href="http://gwt-ext.com/download/">http://gwt-ext.com/download/</a>), put gwtext.jar in your project’s lib/gwt directory (ie, $PROJECT_NAME/lib/gwt). You’ll also have to put it into the plugins/gwt-0.2.4/lib directory.</p>
<p>6. We&#8217;ll then have to hack _Internal in the /plugins/gwt-0.2.4/scripts/ directory (hopefully this won&#8217;t be necessary in the next version of the plugin). Around line 89, you&#8217;ll have to add in another include entry after the others:</p>
<p>Include(name: &#8216;gwtext.jar&#8217;);</p>
<p>We&#8217;ll also need to go down a few more lines, and before &#8216;pathElement(location: &#8220;${basedir}/${srcDir}&#8221;)&#8217;, add &#8216;pathElement(location: &#8220;${basedir}/lib/gwt/gwtext.jar&#8221;)&#8217;.</p>
<p>Lastly, if you get an error about heap space, you&#8217;ll need to give the gwt compiler more heap space. Do this by adding in &#8216;jvmarg(value: &#8216;-Xmx256M&#8217;)&#8217; a few lines down (around line 102), just above where the other arg() lines start. Not sure if this is related to using gwt-ext, running on Mac OS X, or what, but I did run into it a few times.</p>
<p>7. Download EXT 2.0.2 (<a href="http://yogurtearl.com/ext-2.0.2.zip">http://yogurtearl.com/ext-2.0.2.zip</a>), copy the &#8216;adapter&#8217; and &#8216;resources&#8217; directory, along with the &#8216;ext-all.js&#8217;, &#8216;ext-all-debug.js&#8217;, &#8216;ext-core.js&#8217;,  and &#8216;ext-core-debug.js&#8217; into your project&#8217;s /web-app/js/ directory.</p>
<p>8. Download mapstraction (<a href="http://mapstraction.com/svn/source/mapstraction.js">http://mapstraction.com/svn/source/mapstraction.js</a>) and copy it into your applications web-app/js directory as well.</p>
<p>9. Open up your Grails project (I prefer IntelliJ for Groovy/Grails development at the moment, btw) and find the FindMe.gwt.xml file (it is in /src/java/net/uresk directory). Add in the following:</p>
<pre>
<div class="codesnip-container" >
<div class="codesnip"><span class="sc2">&lt;inherits <span class="kw3">name</span>=<span class="st0">&#8220;com.gwtext.GwtExt&#8221;</span> /<span class="kw2">&gt;</span></a></span>
<span class="sc2">&lt;stylesheet <span class="kw3">src</span>=<span class="st0">&#8220;/findme/js/resources/css/ext-all.css&#8221;</span> /<span class="kw2">&gt;</span></a></span>
<span class="sc2"><a href="http://december.com/html/4/element/script.html"><span class="kw2">&lt;script</span></a> <span class="kw3">src</span>=<span class="st0">&#8220;/findme/js/adapter/ext/ext-base.js&#8221;</span> /<span class="kw2">&gt;</span></a></span>
<span class="sc2"><a href="http://december.com/html/4/element/script.html"><span class="kw2">&lt;script</span></a> <span class="kw3">src</span>=<span class="st0">&#8220;/findme/js/ext-all.js&#8221;</span> /<span class="kw2">&gt;</span></a></span></div>
</div>
</pre>
<p>10. Add the following entries in:<br />
Create your Google Maps keys for localhost and for your production domain. To make things easy, I added a config property in called &#8216;googlemaps.key&#8217;, and then added this into my controller to get it for the right environment:[key: grailsApplication.config.googlemaps.key]12. In your index.gsp, add in the following:</p>
<p>A reference to mapstraction: &lt;script type=&#8221;text/javascript&#8221; src=&#8221;/findme/js/map/mapstraction.js&#8221;&gt;&lt;/script></pre>
<p>The google maps js include: &lt;script type=&#8221;text/javascript&#8221; src=&#8221;http://maps.google.com/maps?file=api&#038;v=2.x&#038;key=${key}&#8221;&gt;&lt;/script&gt;</pre>
<p>13. Now create a service called something like LookupService, and add in the following code to access MaxMind:</p>
<pre>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">class</span> LookupService <span class="br0">&#123;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">static</span> expose = <span class="br0">&#91;</span><span class="st0">&#8216;gwt:net.uresk.client&#8217;</span><span class="br0">&#93;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> getLatLonFromIp<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&#038;bntl=1"><span class="kw3">String</span></a> ip<span class="br0">&#41;</span><span class="br0">&#123;</span>

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>!<span class="br0">&#40;</span>ip ==~ /bd<span class="br0">&#123;</span><span class="nu0">1</span>,<span class="nu0">3</span><span class="br0">&#125;</span>.d<span class="br0">&#123;</span><span class="nu0">1</span>,<span class="nu0">3</span><span class="br0">&#125;</span>.d<span class="br0">&#123;</span><span class="nu0">1</span>,<span class="nu0">3</span><span class="br0">&#125;</span>.d<span class="br0">&#123;</span><span class="nu0">1</span>,<span class="nu0">3</span><span class="br0">&#125;</span>b/<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip = defaultIp
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; def res = <span class="st0">&#8220;http://geoip1.maxmind.com/b?l=${maxMindKey}&amp;i=${ip}&#8221;</span>.<span class="me1">toURL</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">text</span>.<span class="me1">split</span><span class="br0">&#40;</span><span class="st0">&#8220;,&#8221;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> result = <span class="kw2">new</span> <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> = <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a>.<span class="me1">parseDouble</span><span class="br0">&#40;</span>res<span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span> = <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a>.<span class="me1">parseDouble</span><span class="br0">&#40;</span>res<span class="br0">&#91;</span><span class="nu0">4</span><span class="br0">&#93;</span><span class="br0">&#41;</span>

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> result
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>You can swap out <a href="http://www.maxmind.com/?rId=uresk">MaxMind</a> with any other service. I added a maxMindKey config property in Config.groovy, but you can easily hard-code it.</p>
<p>14. Now create your GWT client code, something like this:</p>
<pre>
<div class="codesnip-container" >
<div class="codesnip">GoogleMap mainPanel;

&nbsp; &nbsp; <span class="coMULTI">/**
&nbsp; &nbsp; &nbsp;* This is the entry point method.
&nbsp; &nbsp; &nbsp;*/</span>
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw4">void</span> onModuleLoad<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; createPanel<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;<span class="kw2">new</span> Viewport<span class="br0">&#40;</span>mainPanel<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;updateLatLonFromMaxMind<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="kw4">void</span> updateLatLonFromMaxMind<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LookupServiceAsync myService = <span class="br0">&#40;</span>LookupServiceAsync<span class="br0">&#41;</span> GWT.<span class="me1">create</span><span class="br0">&#40;</span>LookupService.<span class="kw2">class</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServiceDefTarget endpoint = <span class="br0">&#40;</span>ServiceDefTarget<span class="br0">&#41;</span> myService;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&#038;bntl=1"><span class="kw3">String</span></a> moduleRelativeURL = GWT.<span class="me1">getModuleBaseURL</span><span class="br0">&#40;</span><span class="br0">&#41;</span> + <span class="st0">&#8220;rpc&#8221;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; endpoint.<span class="me1">setServiceEntryPoint</span><span class="br0">&#40;</span>moduleRelativeURL<span class="br0">&#41;</span>;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AsyncCallback callback = <span class="kw2">new</span> AsyncCallback<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">public</span> <span class="kw4">void</span> onSuccess<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AObject+java.sun.com&#038;bntl=1"><span class="kw3">Object</span></a> result<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> latLon = <span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>result;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setLatLong<span class="br0">&#40;</span>latLon<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>, latLon<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">public</span> <span class="kw4">void</span> onFailure<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AThrowable+java.sun.com&#038;bntl=1"><span class="kw3">Throwable</span></a> caught<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;<span class="co1">// do some UI stuff to show failure</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; myService.<span class="me1">getLatLonFromIp</span><span class="br0">&#40;</span>callback<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="kw4">void</span> setLatLong<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a> lat, <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a> lon<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LatLonPoint llp = <span class="kw2">new</span> LatLonPoint<span class="br0">&#40;</span>lat.<span class="me1">doubleValue</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, lon.<span class="me1">doubleValue</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Marker m = <span class="kw2">new</span> Marker<span class="br0">&#40;</span>llp<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m.<span class="me1">setInfoBubble</span><span class="br0">&#40;</span><span class="st0">&#8220;&lt;div&gt;You are here!&lt;/div&gt;&#8221;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel.<span class="me1">setCenterAndZoom</span><span class="br0">&#40;</span>llp, <span class="nu0">10</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel.<span class="me1">addMarker</span><span class="br0">&#40;</span>m<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="kw4">void</span> createPanel<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel = <span class="kw2">new</span> GoogleMap<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel.<span class="me1">setTitle</span><span class="br0">&#40;</span><span class="st0">&#8220;Spencer&#8217;s Google Map Page&#8221;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel.<span class="me1">addLargeControls</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</div>
</pre>
<p>15. Now, we need to create the stubs for this service so that GWT can use it. Do this by running &#8216;grails run-app&#8217;.</p>
<p>16. Unfortunately, there currently isn&#8217;t an easy way to get at the HttpRequest object inside our service. There is a <a href="http://jira.codehaus.org/browse/GRAILSPLUGINS-386">JIRA item</a> open for this, and I&#8217;m working on a potential solution. In the meantime, we’ll have to do a bit of hacking.</p>
<p>First, we&#8217;ll need to open up the LookupService and LookupServiceAsync java files that the plugin generated – they are in /src/net/uresk/client in this example. Modify the method signatures so they don’t take a String object (the IP). They should look like: java.lang.Double[] getLatLonFromIp(); and void getLatLonFromIp(AsyncCallback callback);</p>
<p>Next, we&#8217;ll need to modify the GrailsRemoteServiceServlet (in /plugins/gwt-0.2.4/src/groovy/org/codehaus/groovy/grails/plugins/gwt). On line 53, we are going to modify the method call so that it explicitly passes in the ip address, by changing it to say this:</p>
<p>def retval = service.invokeMethod(serviceMethod.name, this.getThreadLocalRequest().getRemoteAddr())</p>
<p>If you are using this behind a proxy (ie, behind Apache HTTPD with mod_proxy), getRemoteAddr() won&#8217;t work – you&#8217;ll have to instead get the X-Forwarded-For header value.</p>
<p>This is a nasty hack, and will break all your other GWT RPC calls, so if you are going to do more with this example, you&#8217;ll have to do something a little smarter to inject the IP (contact me if you want some ideas, and also keep an eye on the JIRA item mentioned above). Hopefully it won&#8217;t be necessary much longer.</p>
<p>You should be able to run your application now! Do &#8216;grails run-app&#8217; again and browse to <a mce_href="http://localhost:8080/findme/main" xhref="http://localhost:8080/findme/main">http://localhost:8080/findme/main</a>.</p>
<p>Let me know if you have any questions or suggestions. I also hang out on the #groovy IRC channel on the evenings and weekends (GMT -700) if you need help.</p>
<p>Have fun :)</p>
<p>Special Thanks to <a href="http://abhijeetmaharana.com/blog/2008/04/07/gwt-ext-and-google-maps/">Abhijeet Maharana</a> who provided an excellent how-to for using GoogleMaps with Gwt-Ext.</p>
<p><b>Update:</b> Sorry, I forgot to include the GWT client code in the original post. It is in there, step 14 now. Let me know if I missed anything else.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/06/15/grails-gwt-with-gwt-ext-googlemaps-maxmind-sample-application/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Running Grails applications on a VPS</title>
		<link>http://www.spenceruresk.com/2008/06/12/running-grails-applications-on-a-vps/</link>
		<comments>http://www.spenceruresk.com/2008/06/12/running-grails-applications-on-a-vps/#comments</comments>
		<pubDate>Fri, 13 Jun 2008 04:02:49 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Enterprise Development</category>
	<category>Websites</category>
	<category>Groovy</category>
	<category>Grails</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/06/12/running-grails-applications-on-a-vps/</guid>
		<description><![CDATA[For some time, it has been one of my dreams to see Java-based web applications be more viable for small websites. This means two things: rapid development capabilities (like Ruby on Rails), and inexpensive, reliable, and economical hosting options.
For goal #1, Grails is clearly fitting the bill. I spent the last year or so developing [...]]]></description>
			<content:encoded><![CDATA[<p>For some time, it has been one of my dreams to see Java-based web applications be more viable for small websites. This means two things: rapid development capabilities (like Ruby on Rails), and inexpensive, reliable, and economical hosting options.</p>
<p>For goal #1, <a href="http://www.grails.org/">Grails</a> is clearly fitting the bill. I spent the last year or so developing Rails apps, and Grails feels almost as productive. The community around it is getting quite active and there are some excellent plugins.</p>
<p>Reaching Goal #2 is going to be a bit trickier, but I think we are getting close. I am able to deploy 3 or 4 Grails applications on a 256 MB VPS now, and they work reasonably well. The good thing is that VPS&#8217; are getting quite cheap, and a VPS with 256 MB of memory can easily be had for less than $20/month. (Shameless plug - I am putting together a site - <a href="http://www.vps-hosting-reviews.com/">VPS hosting reviews</a> - that lists vps providers, their plans, prices, and reviews. And it is developed with Grails and running on a VPS :) )That said, you wouldn&#8217;t want to do this if your applications get a ton of traffic, and hosting a Java application will never be as cheap as hosting PHP applications.</p>
<p>Getting several Grails/Java applictions deployed on a server with only 256 MB of RAM (and on a VPS, no less, where getting a big block of contiguous memory can be tricky) takes a bit of work, so I&#8217;ve decided to detail a few things I&#8217;ve learned. This is specifically for Grails applications, although most of the tips should be helpful for any other Java application deployment as well. It also assumes you are using Tomcat as your app server.</p>
<p><strong>1. Dump Apache HTTP server</strong></p>
<p>A lot of people (including me for the longest time) would use Apache to forward requests to Tomcat. There is nothing wrong with Apache HTTP server itself, but in this setup, it can eat up a bunch of memory and really isn&#8217;t necessary. You can use iptables or xinetd to forward requests from port 80 to your app server. A good tutorial for these options can be found <a href="http://www.ibm.com/developerworks/linux/library/l-secjav.html">here</a>. Doing this should free up a bit more precious memory for your app server.</p>
<p><strong>2. Make sure you are using the server JVM</strong></p>
<p>This is easy to forget to do - HotSpot will automatically choose which vm to run based on server attributes, so on a real production box, it will choose the server vm automatically. On a VPS, you&#8217;ll need to manually do this by adding &#8220;-server&#8221; to CATALINA_OPTS.</p>
<p><strong>3. Give you server more PermGen space</strong></p>
<p>Groovy uses a bit more PermGen space than normal, due to all the classloading it does. This means you&#8217;ll probably want to configure your vm to use a bit more PermGen space than usual by doing -XX:MaxPermSize=m. On my server, setting this to about half of the overall memory allocated seemed to be the best, but your results may vary.</p>
<p><strong>4. Experiment</strong></p>
<p>Ideally, you&#8217;d just upload your apps and not worry about tuning, but when you are trying to squeeze the most out of a VPS, this isn&#8217;t the case. Play around with different memory settings and other vm options to see what gets your particular setup the best performance and stability. Feel free to share what works well for you :)
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/06/12/running-grails-applications-on-a-vps/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Avoiding unpleasant code with peer reviews</title>
		<link>http://www.spenceruresk.com/2008/05/26/avoiding-unpleasant-code-with-peer-reviews/</link>
		<comments>http://www.spenceruresk.com/2008/05/26/avoiding-unpleasant-code-with-peer-reviews/#comments</comments>
		<pubDate>Mon, 26 May 2008 23:07:20 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Enterprise Development</category>
	<category>Software Development</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/05/26/avoiding-unpleasant-code-with-peer-reviews/</guid>
		<description><![CDATA[
Ah, the smell of a fresh codebase.
I’m certain most software developers who have been around for any amount of time have had to work on “The Project”. This project has probably been going for years, has had a fair amount of turnover on the development team, and has had a handful of architects (with their [...]]]></description>
			<content:encoded><![CDATA[<div class="Section1">
<p class="MsoNormal">Ah, the smell of a fresh codebase.</p>
<p class="MsoNormal">I’m certain most software developers who have been around for any amount of time have had to work on “The Project”. This project has probably been going for years, has had a fair amount of turnover on the development team, and has had a handful of architects (with their own way of doing things).</p>
<p class="MsoNormal">Projects like this may work wonderfully and be very successful from a business standpoint, and the individuals working on them are likely quite competent. Yet, from a development perspective, they are a nightmare. They contain difficult to understand code, lots of unused (or commented out) code, little testing, little adherence to good development practices, few comments, and a general feeling of brittleness.</p>
<p class="MsoNormal">Code like this may work exactly as intended, but when a codebase gets disorganized, chaotic, and sloppy it can lead to other problems, such as:</p>
<ul>
<li><!--[if !supportLists]--><span />An unpleasant experience for developers</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />High cost to refactor code</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />More bugs</li>
</ul>
<p class="MsoNormal">I’ve worked on a few projects like this over the last 5 years or so, and was naturally excited when I found we were going to be starting with a fresh codebase. At last, all of this cruft that has accumulated over the half a decade this project has been going will no more!</p>
<p class="MsoNormal">Imagine my surprise (and dismay) a month after the new project started when I found most of the symptoms of “The Project” starting to present themselves in the new codebase. Looking through our project and the reports we generate (PMD, CPD, Clover), I saw:</p>
<ul>
<li><!--[if !supportLists]--><span />Lots of untested code</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />Lots of bad practices and sloppy coding (as shown by PMD – we really pared down the ruleset so we don’t get a ton of false positives)</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />Unused code (already, after less than a month!?)</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />Commented-out code</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />Methods that were too big, hard to understand, or uncommented</li>
</ul>
<p class="MsoNormal">Part of this was due to spikes being done for the new project, which led me to conclude that spikes or experimental work of any kind should always be done in a branch. I also became interested in how code gets to this state so quickly, and of far more importance, how to keep it from reaching this state.</p>
<p class="MsoNormal">I don’t think this happens because people are bad developers necessarily, but because it requires a large degree of diligence and policing to keep a codebase clean and well-organized. It is easy to let organizational or quality issues fall to the wayside when working on functionality, and timelines sometimes leave little time for these tasks.</p>
<p class="MsoNormal">Some people offer up pair programming as a way to avoid this, but I don’t particular care for it (see my comments on <a href="http://www.spenceruresk.com/2007/03/25/impaired-programming-how-neither-of-us-is-as-dumb-as-both-of-us/">pair programming</a>). I think situational pair programming is an excellent practice, but I think full-time pair programming is, besides a terrible waste of time, largely ineffective.</p>
<p class="MsoNormal">After doing some research and analysis of how we work, I’m beginning to think that peer reviews are an excellent solution and practice. They provide most of the benefits of pair programming with few of the drawbacks. You still have someone examining your code, asking questions, and offering feedback, but instead of doing it for an entire iteration or whatever (where one of you will likely be bored for a good portion of the time), you do it for an hour or whatever is necessary. The only potential drawback is that if someone is totally off on their approach and it isn’t noticed until the end, it could be costly to refactor (so costly, in some cases, that it may be left in its sub-optimal state).</p>
<p class="MsoNormal">With that in mind, I set out to attempt to come up with good practices for conducting code reviews, and also best practices we should be following to keep our codebase clean and easy to work with. I’m wondering what other organizations are doing for peer reviews, and what I can do to improve the stuff I came up with.</p>
<p class="MsoNormal">It should be noted that a peer review is largely orthogonal from a QA review – a particular block of work can pass the QA review with flying colors and totally fail the peer review. The way I see it, QA reviews inspect the interface, peer reviews inspect the implementation.</p>
<p class="MsoNormal">Here is the document I came up with:</p>
<p class="MsoNormal">&#8211;</p>
<p class="MsoNormal">The peer review should occur prior to resolving a story or bug. At least 30 minutes should be set aside for a peer review, to allow for a thorough review. Once the review has been completed and the reviewer is satisfied, they should leave a comment on the JIRA entry stating that they have peer reviewed the unit of work.</p>
<p class="MsoNormal">Besides following this checklist, you both should go over all the code you wrote for this story. The reviewer should not hesitate to point out how something could have been done in a better way. If the reviewer cannot figure out what a particular piece of code does in a relatively short amount of time, it should be re-written or comments should be added in the code.</p>
<p class="MsoNormal"><strong>1. Metrics / Standards </strong></p>
<p class="MsoNormal">- (<span style="font-size: 11pt; line-height: 115%; font-family: "Calibri","sans-serif"">any coding metrics – code coverage, static analysis, etc)</span></p>
<p class="MsoNormal">- Test coverage should be meaningful – ie, don’t just check that a method executed without throwing an exception</p>
<p class="MsoNormal">- Use the right kind of test for your code (ie, some code may need just unit tests, others may need integration tests, and some might need functional tests)</p>
<p class="MsoNormal">- Business logic is properly tested with unit tests</p>
<p class="MsoNormal">- If this is a bug, was a unit test specifically for that bug created?</p>
<p class="MsoNormal"><strong>2. Code Style </strong></p>
<p class="MsoNormal">- Properly formatted Java code</p>
<p class="MsoNormal">- No commented-out code</p>
<p class="MsoNormal">- No unused code</p>
<p class="MsoNormal">- JPA standards followed (we have a separate document for this)</p>
<p class="MsoNormal">- If you have to explain a piece of code to your reviewer, that piece of code should be documented</p>
<p class="MsoNormal">- If your code is meant to be re-used throughout the app (ie, a utility class) it should have descriptive and useful JavaDocs</p>
<p class="MsoNormal">- Classes should be fewer than 500 lines of code, and any over 250 lines should be scrutinized closely</p>
<p class="MsoNormal"><strong>3. View </strong></p>
<p class="MsoNormal">- All JSF controls have explicit ids</p>
<p class="MsoNormal">- Everything works in IE (firefox support is strongly recommended, as well)</p>
</div>
<p class="MsoNormal">- All fields validate properly (ie, no 500 errors when you put in invalid values)</p>
<p class="MsoNormal">- JSF pages named consistently</p>
<p class="MsoNormal">&#8211;</p>
<p class="MsoNormal">This is part policing – making sure people are following best practices we’ve set forth, and that part of it kind of sucks. It is also part informative, however. Ideally, both the reviewer and the developer are learning from the experience. The reviewer may see a way to do something better and thereby make the code better and increase the skill of the developer. The reviewer may also see something that educates them as well.</p>
<p class="MsoNormal">In the limited testing I’ve done with this, it has worked well. I personally like having someone look at my code with me and let me know what I could have done better, or what piece of code is not quite as intuitive as I thought it was (everything I write is totally intuitive – to me!). I’m curious as to what other people’s thoughts and experiences with regards to peer reviews are, however.</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/05/26/avoiding-unpleasant-code-with-peer-reviews/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Amazon Associates Web Service with GroovyWS</title>
		<link>http://www.spenceruresk.com/2008/05/18/amazon-associates-web-service-with-groovyws/</link>
		<comments>http://www.spenceruresk.com/2008/05/18/amazon-associates-web-service-with-groovyws/#comments</comments>
		<pubDate>Mon, 19 May 2008 02:36:06 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Web Services</category>
	<category>Java</category>
	<category>Groovy</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/05/18/amazon-associates-web-service-with-groovyws/</guid>
		<description><![CDATA[I couldn&#8217;t find any tutorials on how to use Amazon AWS with GroovyWS, so I took a few minutes to figure out how to do it. Here is some sample code:


import groovyx.net.ws.WSClient

def proxy = new WSClient&#40;&#8220;http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl?&#8221;, this.class.classLoader&#41;

def req = proxy.create&#40;&#8220;com.amazon.webservices.awsecommerceservice._2008_04_07.ItemSearchRequest&#8221;&#41;

req.searchIndex = &#8216;Books&#8217;
req.keywords = &#8220;Groovy and Grails&#8221;

def search = proxy.create&#40;&#8220;com.amazon.webservices.awsecommerceservice._2008_04_07.ItemSearch&#8221;&#41;

search.AWSAccessKeyId = &#8220;your id here&#8221;
search.request.add&#40;req&#41;

def res = [...]]]></description>
			<content:encoded><![CDATA[<p>I couldn&#8217;t find any tutorials on how to use Amazon AWS with GroovyWS, so I took a few minutes to figure out how to do it. Here is some sample code:</p>
<pre>
<div class="codesnip-container" >
<div class="codesnip"><span class="co2">import groovyx.net.ws.WSClient</span>

def proxy = <span class="kw2">new</span> WSClient<span class="br0">&#40;</span><span class="st0">&#8220;http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl?&#8221;</span>, <span class="kw2">this</span>.<span class="kw2">class</span>.<span class="me1">classLoader</span><span class="br0">&#41;</span>

def req = proxy.<span class="me1">create</span><span class="br0">&#40;</span><span class="st0">&#8220;com.amazon.webservices.awsecommerceservice._2008_04_07.ItemSearchRequest&#8221;</span><span class="br0">&#41;</span>

req.<span class="me1">searchIndex</span> = <span class="st0">&#8216;Books&#8217;</span>
req.<span class="me1">keywords</span> = <span class="st0">&#8220;Groovy and Grails&#8221;</span>

def search = proxy.<span class="me1">create</span><span class="br0">&#40;</span><span class="st0">&#8220;com.amazon.webservices.awsecommerceservice._2008_04_07.ItemSearch&#8221;</span><span class="br0">&#41;</span>

search.<span class="me1">AWSAccessKeyId</span> = <span class="st0">&#8220;your id here&#8221;</span>
search.<span class="me1">request</span>.<span class="me1">add</span><span class="br0">&#40;</span>req<span class="br0">&#41;</span>

def res = proxy.<span class="me1">ItemSearch</span><span class="br0">&#40;</span>search<span class="br0">&#41;</span>

res.<span class="me1">getItems</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">each</span> <span class="br0">&#123;</span>it.<span class="me1">getItem</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">each</span> <span class="br0">&#123;</span>
println it.<span class="me1">getASIN</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span><span class="br0">&#125;</span></div>
</div>
</pre>
<p>If you&#8217;ve downloaded the <a href="http://groovy.codehaus.org/GroovyWS">GroovyWS</a> jar and put it in your GROOVY_HOME/lib, that should work. I think it is kinda cool how quick and easy it is you can get something simple working with GroovyWS, but if you are going to be using Amazon Web Services a lot, it is probably easier to grab the Java Library that Amazon provides and use it. Here is the code for using that in Groovy:</p>
<pre>
<div class="codesnip-container" >
<div class="codesnip"><span class="co2">import com.amazonaws.a2s.model.*;</span>
<span class="co2">import com.amazonaws.a2s.*;</span>

<span class="kw2">class</span> AmazonSearch <span class="br0">&#123;</span>

<a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&#038;bntl=1"><span class="kw3">String</span></a> key = <span class="st0">&#8216;your key&#8217;</span>
<a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&#038;bntl=1"><span class="kw3">String</span></a> tag = <span class="st0">&#8216;your associates tag&#8217;</span>

def doSearch<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&#038;bntl=1"><span class="kw3">String</span></a> keywords<span class="br0">&#41;</span> <span class="br0">&#123;</span>
AmazonA2S service = <span class="kw2">new</span> AmazonA2SClient<span class="br0">&#40;</span>key, tag<span class="br0">&#41;</span>
ItemSearchRequest request = <span class="kw2">new</span> ItemSearchRequest<span class="br0">&#40;</span><span class="br0">&#41;</span>
request.<span class="me1">searchIndex</span> = <span class="st0">&#8216;Books&#8217;</span>
request.<span class="me1">keywords</span> = keywords
processRequest<span class="br0">&#40;</span>service, request<span class="br0">&#41;</span>
<span class="br0">&#125;</span>

<span class="kw2">private</span> processRequest<span class="br0">&#40;</span>AmazonA2S service, ItemSearchRequest request<span class="br0">&#41;</span> <span class="br0">&#123;</span>
ItemSearchResponse response = service.<span class="me1">itemSearch</span><span class="br0">&#40;</span>request<span class="br0">&#41;</span>
response.<span class="me1">getItems</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>.<span class="me1">getItem</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">each</span> <span class="br0">&#123;</span>
println it.<span class="me1">getASIN</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span>
<span class="br0">&#125;</span>

<span class="kw4">static</span> <span class="kw4">void</span> main<span class="br0">&#40;</span>args<span class="br0">&#41;</span> <span class="br0">&#123;</span>
AmazonSearch search = <span class="kw2">new</span> AmazonSearch<span class="br0">&#40;</span><span class="br0">&#41;</span>
search.<span class="me1">doSearch</span><span class="br0">&#40;</span><span class="st0">&#8220;Groovy and Grails&#8221;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span>

<span class="br0">&#125;</span></div>
</div>
</pre>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/05/18/amazon-associates-web-service-with-groovyws/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Why aren&#8217;t more IT workers telecommuting?</title>
		<link>http://www.spenceruresk.com/2008/04/27/why-arent-more-it-workers-telecommuting/</link>
		<comments>http://www.spenceruresk.com/2008/04/27/why-arent-more-it-workers-telecommuting/#comments</comments>
		<pubDate>Sun, 27 Apr 2008 21:14:08 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Economics</category>
	<category>Business</category>
	<category>Software Development</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/04/27/why-arent-more-it-workers-telecommuting/</guid>
		<description><![CDATA[With the skyrocketing cost of fuel and the increasing impact of fuel costs on American workers, I have to ask - Why aren&#8217;t more people telecommuting? My comments are specifically for IT-related jobs, since that is where my experience is, but I believe a fairly large number of other jobs could be done via telecommuting [...]]]></description>
			<content:encoded><![CDATA[<p>With the skyrocketing cost of fuel and the increasing impact of fuel costs on American workers, I have to ask - Why aren&#8217;t more people telecommuting? My comments are specifically for IT-related jobs, since that is where my experience is, but I believe a fairly large number of other jobs could be done via telecommuting as well.</p>
<p>To give you an idea of why I think telecommuting is feasible (and attractive), here is my typical day, which isn&#8217;t too terribly different from that of many other IT workers:<br />
- Get ready for work, throw my laptop into my backpack, and head out the door.</p>
<p>- Drive the 15 or so miles to work. Usually I am lucky in the morning and it only takes 30 min or so to make the drive.</p>
<p>- Unpack and dock my laptop, and get to work.</p>
<p>- Throughout the day, much of my interaction with my co-workers is done via IM and email. People are too spread out (different floors, different buildings, etc) and often too busy for real-time human interaction all the time.</p>
<p>- Work ends, throw my laptop back into my bag, drive the 15 or so miles home (this trip takes me 45 - 60 minutes).</p>
<p>So, each day I drive 30 miles and spend roughly 1.5 hours commuting to and from work. Over a week, that is 150 miles and 7.5 hours - almost a full workday! Thankfully, the new <a href="http://www.rideuta.com/projects/commuterRail/default.aspx">train</a> is starting to run next week, so some of this will be mitigated, but it is still a fair amount of time and money spent commuting. Add to this other problems that are common for many companies - lack of space, parking issues, and other facility issues.<br />
So, why not have employees telecommute a handful of days per week? Think about the benefits:</p>
<p><strong>Employees</strong></p>
<p>- Less time in traffic<br />
- Less spent on gas and maintenance<br />
- Ability to focus on your tasks for a few days (I get far more done on the rare days I work from home)<br />
<strong><br />
Employers</strong></p>
<p>- Happier employees<br />
- Less need for parking space<br />
- Less floor space needed for employees</p>
<p><strong>Society, the economy, and the environment</strong></p>
<p>- Less gas being used<br />
- Less pollution being created<br />
- Roads that are less congested</p>
<p>I understand as well as anyone the need for people to be at work in-person and to have face-to-face time with other employees. I don&#8217;t think this needs to be every day, though. In fact, I think many of us would benefit from less time available for meetings - people scheduling them would have to think hard about whether or not a full-blown meeting was necessary, or whether whatever they are trying to accomplish could be done with a few emails.<br />
If a large percentage of IT workers worked from home just 2 or 3 days per week, the impact could be quite large - think of all the time and energy savings. There is no good technical reason for not encouraging such policies - technology exists to allow this (many companies already have it in place and use it to a small extent), the nature of our jobs is very conducive to working off-site, and several companies (ie, RedHat), already do it to a large extent with great success.</p>
<p>One argument against telecommuting is that it makes it hard to keep people accountable. I&#8217;d argue that it is pretty easy to see who is getting their stuff done and who isn&#8217;t, regardless of where they are working from. If you are paying someone $100k per year to write code for you and don&#8217;t feel like you can trust them enough to let them work out of your sight for a few days, you have far bigger problems. It also kills me when companies have no problem outsourcing projects halfway around the world to people they don&#8217;t know (and can&#8217;t communicate with very well), but balk at letting employees work from home a few days per week.</p>
<p>I don&#8217;t see why more companies aren&#8217;t pushing this, why government at various levels isn&#8217;t pushing it, and why more employees aren&#8217;t clamoring for it. Yeah, it takes a little extra work, requires some trust on the part of the employer, and may cost a bit in initial setup (VPN, security, bigger pipes to handle the traffic, etc), but to me, it seems like it pays of well in the long run.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/04/27/why-arent-more-it-workers-telecommuting/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>iBrick - 2.0</title>
		<link>http://www.spenceruresk.com/2008/04/08/ibrick-20/</link>
		<comments>http://www.spenceruresk.com/2008/04/08/ibrick-20/#comments</comments>
		<pubDate>Tue, 08 Apr 2008 08:46:18 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Mobile Development</category>
	<category>Apple</category>
	<category>iPhone</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/04/08/ibrick-20/</guid>
		<description><![CDATA[It looks as though developers using the Apple iPhone 2.0 (Beta) OS (via the official development program) have been completely locked out of their phones within the last few hours, based on posts on Apple&#8217;s forums. To make matters worse, you apparently cannot restore the 1.1.4 firmware. Ouch.

]]></description>
			<content:encoded><![CDATA[<p>It looks as though developers using the Apple iPhone 2.0 (Beta) OS (via the official development program) have been completely locked out of their phones within the last few hours, based on posts on <a href="http://discussions.apple.com/thread.jspa?threadID=1476829&#038;tstart=0">Apple&#8217;s forums</a>. To make matters worse, you apparently cannot restore the 1.1.4 firmware. Ouch.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/04/08/ibrick-20/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>No debugging on the iPhone for a while</title>
		<link>http://www.spenceruresk.com/2008/03/21/no-debugging-on-the-iphone-for-a-while/</link>
		<comments>http://www.spenceruresk.com/2008/03/21/no-debugging-on-the-iphone-for-a-while/#comments</comments>
		<pubDate>Sat, 22 Mar 2008 02:44:30 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Mobile Development</category>
	<category>Apple</category>
	<category>iPhone</category>
	<category>Xcode</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/03/21/no-debugging-on-the-iphone-for-a-while/</guid>
		<description><![CDATA[I was pretty excited when I saw that you can debug your iPhone apps on your actual phone with Apple&#8217;s SDK. Not being one to bother with instructions, I downloaded the new version of Xcode and started hacking away on a sample iPhone app. When I went to try it out, I got this error: [...]]]></description>
			<content:encoded><![CDATA[<p>I was pretty excited when I saw that you can debug your iPhone apps on your actual phone with Apple&#8217;s SDK. Not being one to bother with instructions, I downloaded the new version of Xcode and started hacking away on a sample iPhone app. When I went to try it out, I got this error: &#8220;Codesign error: no certificate for identifier &#8220;iPhone Developer&#8221; was found in your keychain&#8221;.</p>
<p>Reading through the instructions, I found that I needed to be a registered iPhone developer - and pay $99 for the privilege. Not a big deal, but after I signed up (I wasn&#8217;t asked to pay), I was told I would be contacted when I could complete the registration and (presumably) get my certificate.</p>
<p>I don&#8217;t really mind paying $99, but having to wait around for them to let me in is kind of a let-down. Bummer.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/03/21/no-debugging-on-the-iphone-for-a-while/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>iPhone vs Android</title>
		<link>http://www.spenceruresk.com/2008/03/18/iphone-vs-android/</link>
		<comments>http://www.spenceruresk.com/2008/03/18/iphone-vs-android/#comments</comments>
		<pubDate>Tue, 18 Mar 2008 17:03:30 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Software Development</category>
	<category>Java</category>
	<category>OS X</category>
	<category>Mobile Development</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/03/18/iphone-vs-android/</guid>
		<description><![CDATA[2008 is shaping up to be a great year for mobile development. Google released its Android platform late last year, and Apple has released an early version of its SDK for the iPhone just a few days ago. I&#8217;m  not a full-time mobile developer, so I figure I&#8217;ll eventually have to settle on one [...]]]></description>
			<content:encoded><![CDATA[<p>2008 is shaping up to be a great year for mobile development. Google released its <a href="http://code.google.com/android/">Android</a> platform late last year, and Apple has released an early version of its <a href="http://developer.apple.com/iphone/program/">SDK</a> for the iPhone just a few days ago. I&#8217;m  not a full-time mobile developer, so I figure I&#8217;ll eventually have to settle on one or the other to target for my hobby apps. I&#8217;ve tried to take a look at some of the advantages and disadvantages to each platform.</p>
<p><strong>Development Platform</strong></p>
<p>One unfortunate aspect of the iPhone SDK is that it is limited to computers running OS X - no development on Windows or Linux. This isn&#8217;t a problem for me personally - I do most of my development on a Mac anyway - but I don&#8217;t really like vendor lock-in like that. Indeed, this is one of the biggest reasons I have stayed away from Microsoft&#8217;s .NET platform. Also, the iPhone SDK uses Objective-C and Android uses Java - so if you have experience with either language, you&#8217;ll have a leg up on the corresponding platform.</p>
<p><strong>Openness of platform</strong></p>
<p>I have to admit, the iPhone SDK is nowhere near as locked down as I expected it to be. I was expecting it to be locked down roughly on par with how AT&#038;T locks down JavaME development on their network, but was pleasantly surprised by how much you have access to. Still, it is hard to beat Android&#8217;s openness, and Android clearly wins in this category.</p>
<p><strong>Market</strong></p>
<p>This is one area where the iPhone clearly wins - there are already millions of them currently being used, whereas Android currently has 0 devices even available for purchase at this point. Apple&#8217;s distribution model for iPhone apps is very compelling as well - they handle sales, processing, and hosting and you get to keep 70% of the price. It remains to be seen what Google will do in these area, but if there is one thing Apple does really well, it is marketing. I was about ready to ignore development for the iPhone, but this single factor alone is making it worth a second look to me.</p>
<p>The real issue is going to be - who does Google team up with as a carrier, and how many phones are they able to sell? All the cool features in the world won&#8217;t mean much if you don&#8217;t have a very large market.</p>
<p><strong>Cost</strong></p>
<p>A lot has been said of the $99 cost to get into Apple&#8217;s iPhone developer program. It would be nice if this were free (like Android), but in reality, $99 isn&#8217;t too bad compared to the cost of getting certificates for JavaME apps. Plus, if you are selling apps, the $99 is a pretty cheap way to take advantage of Apple&#8217;s marketing and distribution services.</p>
<p><strong>Investment in the Platform</strong></p>
<p>It is clear that both platforms are being heavily invested in. Google is giving out $10 million in prizes, whereas Apple has partnered with VC firm Kleiner Perkins to offer $100 million in funding for iPhone apps.</p>
<p><strong>Features</strong></p>
<p>I would expect both platforms to be fairly similar here. Both platforms will support touch screens. Android apparently will support 3G out of the box, whereas the iPhone doesn&#8217;t currently. There is speculation that Apple will release a 3G enabled phone sometime this year, however.</p>
<p>Features are one area where Google&#8217;s platform can beat Apple&#8217;s - since there will likely be a wide variety of models available. Need more accurate location services? Get an Android-based phone with a built-in GPS.</p>
<p>The last issue is the ability of applications to run in the background. iPhone applications cannot do this, which rules out any sort of IM client, for example.</p>
<p><strong>Cool Factor </strong></p>
<p>Nobody does cool like Apple - the device itself is sleek and attractive. The visual effects are nicely done, and you can tell the level of attention paid to detail.</p>
<p>In conclusion, it is an exciting year for mobile development. Just last year, I was <a href="http://www.spenceruresk.com/2007/05/26/the-hidden-problem-with-j2me/">lamenting</a> the state of mobile development due to carriers locking down access to useful APIs. It now appears that the platform is being freed to a great degree, and we now have two excellent platforms to choose from.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/03/18/iphone-vs-android/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>More Leopard/Java 6 Reactions</title>
		<link>http://www.spenceruresk.com/2007/11/02/more-leopardjava-6-reactions/</link>
		<comments>http://www.spenceruresk.com/2007/11/02/more-leopardjava-6-reactions/#comments</comments>
		<pubDate>Sat, 03 Nov 2007 03:28:27 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Java</category>
	<category>OS X</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2007/11/02/more-leopardjava-6-reactions/</guid>
		<description><![CDATA[It has been interesting to see the various reactions to Java 6 not being included with OS X Leopard. Several people on Javalobby advocated boycotting Apple over this. I  don&#8217;t think a boycott is in order - in fact, I just bought a brand new iMac, even knowing Java 6 wasn&#8217;t on it :) Other [...]]]></description>
			<content:encoded><![CDATA[<p>It has been interesting to see the various reactions to Java 6 not being included with OS X Leopard. Several people on <a href="http://www.javalobby.org/java/forums/t102936.html">Javalobby</a> advocated boycotting Apple over this. I  don&#8217;t think a boycott is in order - in fact, I just bought a brand new iMac, even knowing Java 6 wasn&#8217;t on it :) Other people, such as notable Java expert (and Mac user) <a href="http://weblogs.java.net/blog/javaben/archive/2007/10/the_java_on_os.html">Ben Galbraith</a>, have characterized the Java community&#8217;s reaction as &#8220;whining&#8221;. I think this is unfair, and rather unfortunate.</p>
<p>The important thing to understand is why people who are both Java and Mac enthusiasts are upset. It isn&#8217;t because Java 6 was not included in Leopard, rather it is due to the complete lack of information regarding Java 6 on OS X. Do I need Java 6 right now? No. But I will need it in the future, and it would be nice to know what Apple&#8217;s plans are with Java before plunking down $6,000 for hardware. Is that unreasonable? Is that &#8220;whining&#8221;?</p>
<p>A lot of people have claimed &#8220;that is just how Apple works&#8221;, as though it were some cute habit that was merely annoying, and that we are silly for even worrying about it. Why is it that people accept that? I guarantee you, if Microsoft did something similar, they wouldn&#8217;t get the free pass a lot of people are giving Apple. Here is what I don&#8217;t get - Apple does pre-announce a lot of features they intend to add, and there is no competitive reason to be so secretive about its Java plans - why can&#8217;t they say something like &#8220;Yeah, Java 6 didn&#8217;t make it into Leopard, too bad. We are working on it, and will have it out within the next X months.&#8221; How hard would this be? It would mollify most critics. Yet the response so far has been silence. Deafening silence.</p>
<p>As my good friend <a href="http://swamp.homelinux.net/blog/">Mike Heath</a> astutely reminded me the other day, IBM too is quite often behind supporting new versions of Java (indeed, it was nearly 2 years after Java 5 came out that we were able to get a version of WebSphere that supported it), and this is probably even more inexcusable than Apple being behind. So, I don&#8217;t think it is fair to be hard on Apple for not releasing Java 6 for OS X yet, especially given the improvements they&#8217;ve made to Java 5. I do, however, think it is totally fair to wonder why they are saying absolutely nothing about it. It doesn&#8217;t make a bit of sense.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2007/11/02/more-leopardjava-6-reactions/feed/</wfw:commentRSS>
		</item>
	</channel>
</rss>
