<?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:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Stuff I've learned recently...</title>
	<atom:link href="http://kousenit.wordpress.com/feed" rel="self" type="application/rss+xml" />
	<link>http://kousenit.wordpress.com</link>
	<description>I teach this stuff.  I didn't say I could do it.</description>
	<pubDate>Fri, 18 Jul 2008 18:56:42 +0000</pubDate>
	<generator>http://wordpress.org/?v=MU</generator>
	<language>en</language>
			<item>
		<title>NetBeans 6.1 is a lot better than I thought</title>
		<link>http://kousenit.wordpress.com/2008/07/18/netbeans-61-is-a-lot-better-than-i-thought/</link>
		<comments>http://kousenit.wordpress.com/2008/07/18/netbeans-61-is-a-lot-better-than-i-thought/#comments</comments>
		<pubDate>Fri, 18 Jul 2008 18:56:42 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Teaching]]></category>

		<category><![CDATA[Web Services]]></category>

		<category><![CDATA[NetBeans]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=128</guid>
		<description><![CDATA[This week I&#8217;m in New Haven, CT, teaching a class that combines UML and Java Web Services (an odd combination to be sure).  The client wanted to use NetBeans as their primary IDE, and I always try to accommodate that if I can.
My last exposure to NetBeans was back in version 5.5, I think, when [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>This week I&#8217;m in New Haven, CT, teaching a class that combines UML and Java Web Services (an odd combination to be sure).  The client wanted to use <a href="http://www.netbeans.org/">NetBeans</a> as their primary IDE, and I always try to accommodate that if I can.</p>
<p>My last exposure to NetBeans was back in version 5.5, I think, when a couple of friends suggested I give it a whirl.  I&#8217;ve been an Eclipse user since version 1, so I&#8217;m very comfortable with that environment.  As part of giving a presentation at my local <a href="http://www.ctjava.org/">Java User&#8217;s Group</a>, I also got a license for <a href="http://www.jetbrains.com/idea/">IntelliJ&#8217;s IDEA</a>, so I&#8217;ve been playing with that off an on.  When I don&#8217;t want to use a heavy IDE, I generally stick with <a href="http://www.ultraedit.com/">UltraEdit</a>, which does a decent job, even with Groovy code.</p>
<p>Nevertheless, I downloaded and installed NetBeans 6.1.  I have to say that I&#8217;ve been very pleasantly surprised by the editor.  The <a href="http://www.netbeans.org/kb/trails/uml.html">UML support</a> is surprisingly good, including the capability to generate sequency diagrams from code.  But its <a href="http://www.netbeans.org/kb/trails/java-ee.html">JAX-WS and JAXB</a> support has been outstanding.  I&#8217;ve been using them with the embedded Glassfish server and really enjoyed it.</p>
<p>I&#8217;m in a bit of a rush (have to get back to class) or I&#8217;d say more.  What I can say, though, is that if the NetBeans group really does deliver on <a href="http://wiki.netbeans.org/NB65EngineeringPlan">Groovy and Grails support in NB 6.5</a>, as promised, I&#8217;m definitely going to try it.  I&#8217;m still mostly an Eclipse person (and the commercial <a href="http://www.myeclipseide.com">MyEclipse</a> tool as well).  I know it&#8217;s practically heresey to say so these days, but I&#8217;m still finding that IntelliJ slows me down a lot more than it speeds me up.  But this single week with NetBeans has been a revelation.  I can only hope the Groovy and Grails support when it comes out in October is as good as the rest of the IDE.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/128/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/128/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/128/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=128&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/07/18/netbeans-61-is-a-lot-better-than-i-thought/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
		<item>
		<title>Our last, best hope &#8230; for message digests?</title>
		<link>http://kousenit.wordpress.com/2008/06/26/our-last-best-hope-for-message-digests/</link>
		<comments>http://kousenit.wordpress.com/2008/06/26/our-last-best-hope-for-message-digests/#comments</comments>
		<pubDate>Thu, 26 Jun 2008 22:04:08 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Teaching]]></category>

		<category><![CDATA[babylon 5]]></category>

		<category><![CDATA[md5]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=126</guid>
		<description><![CDATA[So I&#8217;m teaching my course in Securing Java Web Applications (my third one in the last six weeks) and we got to a section that discussed the MD5 algorithm for generating message digests.
One of the students asked, &#8220;whatever happened to MD&#8217;s 1 through 4?&#8221;
I simply couldn&#8217;t resist saying, &#8220;MD&#8217;s 1, 2, and 3 were sabotaged [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>So I&#8217;m teaching my course in Securing Java Web Applications (my third one in the last six weeks) and we got to a section that discussed the MD5 algorithm for generating message digests.</p>
<p>One of the students asked, &#8220;whatever happened to MD&#8217;s 1 through 4?&#8221;</p>
<p>I simply couldn&#8217;t resist saying, &#8220;MD&#8217;s 1, 2, and 3 were sabotaged during construction.  MD4 vanished without a trace shortly after it came online.  Now we have MD5, our last, best hope for peaceful digests.&#8221;</p>
<p>To my pleasant surprise, about five different students <a href="http://en.wikipedia.org/wiki/Babylon_5">got the joke</a>.</p>
<p>(And yes, every time I see the abbreviation JMS I don&#8217;t think Java Message Service, I think <a href="http://en.wikipedia.org/wiki/J._Michael_Straczynski">J. Michael Straczynski</a>.)</p>
<p>We live for the One; we die for the One.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/126/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/126/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/126/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/126/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/126/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/126/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/126/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/126/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/126/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/126/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/126/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/126/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=126&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/06/26/our-last-best-hope-for-message-digests/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
		<item>
		<title>Never miss a ballgame</title>
		<link>http://kousenit.wordpress.com/2008/06/25/never-miss-a-ballgame/</link>
		<comments>http://kousenit.wordpress.com/2008/06/25/never-miss-a-ballgame/#comments</comments>
		<pubDate>Wed, 25 Jun 2008 04:34:37 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Baseball]]></category>

		<category><![CDATA[Travel]]></category>

		<category><![CDATA[asheville tourists]]></category>

		<category><![CDATA[hickory crawdads]]></category>

		<category><![CDATA[minor league baseball]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=125</guid>
		<description><![CDATA[As Tim Kurkjian famously said, &#8220;Never miss the opportunity to go to a baseball game.  You might see something you&#8217;ve never seen before.&#8221;
This week I&#8217;m in Asheville, NC.  I&#8217;m very busy with my Securing Java Web Applications class while other issues keep coming up, but the bottom line is that the Asheville Tourists (the class [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>As <a href="http://en.wikipedia.org/wiki/Tim_Kurkjian">Tim Kurkjian</a> famously said, &#8220;Never miss the opportunity to go to a baseball game.  You might see something you&#8217;ve never seen before.&#8221;</p>
<p>This week I&#8217;m in <a href="http://www.exploreasheville.com/index.aspx">Asheville, NC</a>.  I&#8217;m very busy with my <a href="http://capcourse.com/Courses/121/50/121_Outline_50.html">Securing Java Web Applications</a> class while other issues keep coming up, but the bottom line is that the <a href="http://asheville.tourists.milb.com/index.jsp?sid=t573">Asheville Tourists</a> (the class A affiliate of the Colorado Rockies) are nearby and are in town.  I was debating whether to go or not when I spoke to my wife on the phone.  As usual, she encouraged me to go.  She&#8217;s claims I&#8217;m always in a better mood after I&#8217;ve attended a ball game, so who can blame her?</p>
<p>Even better, minor league baseball team names in North Carolina are great.  I really liked the <a href="http://www.ironpigsbaseball.com/">Lehigh Valley Iron Pigs</a> when I was in Allentown a couple weeks ago, but NC has great names in abundance.  You&#8217;ve got the <a href="http://www.gsohoppers.com/index.asp">Greensboro Grasshoppers</a>, the <a href="http://www.warthogs.com/">Winston-Salem Warthogs</a>, the <a href="http://www.intimidatorsbaseball.com/">Kannapolis Intimidators</a>, the <a href="http://www.gomudcats.com/">Carolina Mudcats</a>, and even tonight&#8217;s opponent, the <a href="http://web.minorleaguebaseball.com/index.jsp?sid=t448">Hickory Crawdads</a>.  That doesn&#8217;t even mention the classic <a href="http://www.dbulls.com/">Durham Bulls</a>.  But honestly, how can you not go to a game between the Tourists (who have had that name since 1914!) and the Crawdads?  It&#8217;s just not possible.</p>
<p>So I did my usual practice, which is to show up at the box office about a half hour before game time, told them I needed only one ticket and asked for the best available seat in the house.  In Asheville, that turned out to be a special &#8220;Home Deck Suite&#8221; right behind the on-deck circle (probability of a foul ball: zero), which cost a fortune ($45, an insane amount for a minor league game) but included all you can eat on the menu, delivered for seven innings by a helpful staff person.</p>
<p>That&#8217;s right &#8212; all you can eat.  The guy kept coming back asking if I wanted more, and I kept doing massive rationalizations justifying horrible overeating in order to consume enough to make the ticket worthwhile.  Let&#8217;s say that I think I managed to do so (er, hot dogs, popcorn, cheese nachos, a giant pretzel, and an endless supply of sodas, but I showed some restraint &#8212; no crackerjacks, though I was tempted), which I&#8217;m already regretting and surely will regret more tomorrow.  I even got lucky and sat next to a charming couple who were in town on business and had tons of minor league baseball stories to tell.  The guy next to me also reminded me that the manager of the Tourists is good old Joe Mikulik, the immortal star of <a href="http://www.youtube.com/watch?v=gDx_6LzfZ5Y">this classic YouTube video</a> featuring a managerial meltdown that is topped only by <a href="http://www.youtube.com/watch?v=Ggy6WGUFaYs&amp;feature=related">this one by Phil Wellman</a>, and I saw Earl Weaver in his prime.</p>
<p>As for the game, <a href="http://web.minorleaguebaseball.com/milb/stats/stats.jsp?t=g_log&amp;gid=2008_06_24_hicafx_ashafx_1&amp;did=t573&amp;sid=t573">the Crawdads won 7 - 1</a>, but I definitely saw some things I&#8217;d never seen before:</p>
<ul>
<li>Hickory&#8217;s <a href="http://web.minorleaguebaseball.com/milb/stats/stats.jsp?n=Spain%20%203B&amp;pos=&amp;sid=t573&amp;t=p_pbp&amp;pid=452024">Bobby Spain</a> went 4 for 5 with a home run, but he was outdone by his teammate <a href="http://web.minorleaguebaseball.com/milb/stats/stats.jsp?n=Walker%20%20C&amp;pos=&amp;sid=t573&amp;t=p_pbp&amp;pid=446307">Andrew Walker</a>, who went 4 for 5 with two home runs.  They even went back-to-back in the top of the 2nd inning.  Is it too obscure a reference to think their slogan should be <a href="http://www.around-the-horn.com/?p=127">Walker and Spain and Pray for Rain</a>?</li>
<li>Hickory&#8217;s <a href="http://web.minorleaguebaseball.com/milb/stats/stats.jsp?n=Bishop%20(H%2C%204)&amp;pos=P&amp;sid=t573&amp;t=p_pbp&amp;pid=488707">Harrison Bishop</a> and <a href="http://web.minorleaguebaseball.com/milb/stats/stats.jsp?n=Boleska%20&amp;pos=P&amp;sid=t573&amp;t=p_pbp&amp;pid=446383">Tom Boleska</a> combined to strike out six batters in a row from the bottom of the sixth to the bottom of the eighth.  I was surprised when they took out Bishop after striking out four in a row, but then Boleska came in and struck out two more before the next guy grounded out weakly to second.</li>
<li>The two teams combined for a total of seven (!) errors (Hickory made 4 and still won), which is more than I&#8217;ve seen in some Little League games.</li>
<li>The catcher&#8217;s name on the Crawdads is <a href="http://web.minorleaguebaseball.com/milb/stats/stats.jsp?n=Davis%20%20C&amp;pos=&amp;sid=t573&amp;t=p_pbp&amp;pid=450604">Lars Davis</a>.  Yes, he&#8217;s the catcher.  Don&#8217;t they therefore, by law, HAVE to call him <a href="http://www.imdb.com/title/tt0094812/">Crash</a>?</li>
<li>The guy who sang the National Anthem was an excellent operatic singer.  Every anthem singer in Connecticut thinks they have to sing with a country twang or like they have vocal diarrhea (see <a href="http://www.christinaaguilera.com/">Aguilera, Christina</a>, or lament the sad, pathetic American Idolization of singing), but here I am in North Carolina and I get a trained voice with a fine instrument.  Go figure.</li>
</ul>
<p>The weather was great, the crowd was small (2872) but enthusiastic.  Asheville is the champion of the first half of the season of the Northern Division of the South Atlantic league (an odd but interesting achievement), so on the way out they were giving away general admission tickets to any future game.</p>
<p>That means I have a free ticket to the game tomorrow, even if it&#8217;s not for a very good seat and I still have work to do.  Still, you should never miss going to a ballgame&#8230;</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/125/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/125/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/125/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=125&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/06/25/never-miss-a-ballgame/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
		<item>
		<title>Minor league baseball rocks</title>
		<link>http://kousenit.wordpress.com/2008/06/18/minor-league-baseball-rocks/</link>
		<comments>http://kousenit.wordpress.com/2008/06/18/minor-league-baseball-rocks/#comments</comments>
		<pubDate>Wed, 18 Jun 2008 13:07:38 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Baseball]]></category>

		<category><![CDATA[Travel]]></category>

		<category><![CDATA[asheville tourists]]></category>

		<category><![CDATA[lehigh valley iron pigs]]></category>

		<category><![CDATA[minor league baseball]]></category>

		<category><![CDATA[round rock express]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=124</guid>
		<description><![CDATA[I&#8217;ve been traveling a lot lately.  Fortunately, this is baseball season, so sometimes I get a chance to visit a park I&#8217;ve never been to before.
Last week I was in Allentown, PA.  Actually, that&#8217;s not quite true &#8212; I was actually in Schnecksville, PA, a small suburb of Allentown.  It turns out that this year [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>I&#8217;ve been traveling a lot lately.  Fortunately, this is baseball season, so sometimes I get a chance to visit a park I&#8217;ve never been to before.</p>
<p>Last week I was in Allentown, PA.  Actually, that&#8217;s not quite true &#8212; I was actually in <a href="http://www.city-data.com/city/Schnecksville-Pennsylvania.html">Schnecksville, PA</a>, a small suburb of Allentown.  It turns out that this year Allentown has a new baseball team.  The <a href="http://www.ironpigsbaseball.com/">Lehigh Valley Iron Pigs</a> are playing their inaugural season as the AAA affiliate of the Philadelphia Phillies.</p>
<p>(Two years ago, as part of an extended weekend road trip, my son Xander and I did the Phillies circuit.  We got tickets to see the Phillies at <a href="http://philadelphia.phillies.mlb.com/phi/ballpark/index.jsp">Citizens Bank park</a> (a huge improvement over the old Veteran&#8217;s Stadium, but, then again, almost anything would be), then we saw the <a href="http://www.readingphillies.com/">Reading Phillies</a> (their AA affiliate), and finally swung around to see the Scranton/Wilkes-Barre Red Barons, who at the time were the Phillies AAA team.  Now that Scranton is the AAA team for the Yankees, we won&#8217;t be going back any time soon (I&#8217;d link to their web site, but hey, if you&#8217;re a Yankee fan, go find it yourself).  As a final aside, we were hoping to do a similar circuit for the Red Sox (Red Sox at <a href="http://boston.redsox.mlb.com/bos/ballpark/index.jsp">Fenway</a>, <a href="http://www.seadogs.com/">Portland Sea Dogs</a>, <a href="http://www.lowellspinners.com/">Lowell Spinners</a>), but couldn&#8217;t get tickets to any of them.  That&#8217;s right &#8212; the Single A Lowell Spinners were sold out, too.  Baseball is king in New England.)</p>
<p>I was teaching a private class last week, and the client was a major sponsor of the Iron Pigs.  That meant I was able to join a group of people in a good balcony section of <a href="http://www.ironpigsbaseball.com/cocacola/stadiuminfo/">Coca-Cola Park</a> (an awful name, but there it is).  The whole pig theme was obvious, from the kids hanging out on the freshly mowed lawn in left-center, which was called Pigs on a Blanket, to the Pig Pen in right-center field.  Their program was even called Pork Illustrated.</p>
<p>We had a lot of fun, even though the Iron Pigs <a href="http://web.minorleaguebaseball.com/milb/stats/stats.jsp?sid=milb&amp;t=g_log&amp;gid=2008_06_12_bufaaa_lhvaaa_1">lost 5-4</a>.  Still, the park was charming, we had excellent weather, and the people were friendly.  (Mostly &#8212; I did have an extended baseball discussion with a long suffering Cleveland Indians fan who hates all things Boston, which is probably understandable under the circumstances. ;))</p>
<p>This week I&#8217;m in Austin, TX.  Last night I drove out to Round Rock and got to see the <a href="http://www.roundrockexpress.com/">Round Rock Express</a>, the AA affiliate of the Houston Astros.  Yesterday the temperature peaked at 102, but there was a warm breeze and it cooled off a bit as the sun went down.  The stadium wasn&#8217;t terribly full, but the people who were there were quite enthusiastic.  The Express even <a href="http://web.minorleaguebaseball.com/milb/stats/stats.jsp?sid=milb&amp;t=g_log&amp;gid=2008_06_17_omaaaa_rreaaa_1">won 3-0</a> and hit two home runs.  Other than taking forever to find my rental car in the parking lot (a sign of traveling too much is that you forget what your rental car looks like), I had a great time.</p>
<p>I&#8217;ve now added baseball caps from the Iron Pigs and the Express to my collection.  I used to get T-shirts everywhere for my son Xander, but he told me he doesn&#8217;t want them any more.  Now that he&#8217;s 16, all he wears are T-shirts with various rock bands on them.  So be it.  Be sure, though, to check out his band&#8217;s excellent studio recording of their song &#8220;Don&#8217;t Tell Me&#8221; at <a href="http://myspace.com/thetension12">their MySpace page</a>.</p>
<p>Next week I&#8217;ll be in Asheville, NC, and it looks like the <a href="http://asheville.tourists.milb.com/index.jsp?sid=t573">Asheville Tourists</a> (the class A affiliate of the Colorado Rockies) will be in town.  Maybe I&#8217;ll be able to buy another hat. <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/124/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/124/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/124/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/124/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/124/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/124/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/124/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/124/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/124/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/124/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/124/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/124/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=124&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/06/18/minor-league-baseball-rocks/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
		<item>
		<title>Eight years and haven&#8217;t missed a day yet</title>
		<link>http://kousenit.wordpress.com/2008/06/16/eight-years-and-havent-missed-a-day-yet/</link>
		<comments>http://kousenit.wordpress.com/2008/06/16/eight-years-and-havent-missed-a-day-yet/#comments</comments>
		<pubDate>Mon, 16 Jun 2008 15:50:07 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Teaching]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=122</guid>
		<description><![CDATA[On May 31, 2000, I officially left my job at United Technologies and became a full-time technical trainer.  It&#8217;s now been eight years since that day.  While I don&#8217;t like to talk about personal things here very often, I thought that was worth a mention.  That, and the fact that in all [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>On May 31, 2000, I officially left my job at <a href="http://www.utrc.utc.com">United Technologies</a> and became a full-time technical trainer.  It&#8217;s now been eight years since that day.  While I don&#8217;t like to talk about personal things here very often, I thought that was worth a mention.  That, and the fact that in all the training classes I&#8217;ve taught since then (probably somewhere around 250, though that might be a bit low), <strong>I&#8217;ve never missed a day</strong>.</p>
<p>As Inigo Montoya said, &#8220;<a title="Inigo Montoya quotes" href="http://us.imdb.com/title/tt0093779/quotes">Let me &#8217;splain &#8212; no, it is too much.  Let me sum up</a>.&#8221;  After receiving my Ph.D. in Aerospace Engineering from <a href="http://www.princeton.edu">Princeton</a>, I took a job as a research scientist at United Technologies Research Center in East Hartford, CT.  I spent nearly 12 years there, mostly investigating the aerodynamics and <a href="http://ntrs.nasa.gov/search.jsp?N=4294723787">aeroacoustics of jet engines</a>.  That meant <a href="http://en.wikipedia.org/wiki/Aeroacoustics">lots of math</a> (pretty cool) and lots of Fortran (shudder).  Toward the end of my stay, I learned Java and switched to a different group at UTRC that specialized in <a href="http://en.wikipedia.org/wiki/Genetic_algorithms">Artificial Intelligence</a>.  Quickly realizing that twelve years of programming in Fortran hadn&#8217;t taught me anything about modern software development, I went back to school at night and got my MS in Computer Science from <a href="http://www.ewp.rpi.edu/hartford/">Rensselaer at Hartford</a>.</p>
<p>Just before graduation I reentered the job market.  This was in the Spring of 2000, just before the dot-com bubble burst completely.  In the end, I had to choose between a developer job, and a job teaching training courses.  One night at dinner with the family I said, &#8220;I&#8217;ve decided which job I want.&#8221;  My son Xander, who had just turned 8 years old, said, &#8220;did you take the one with more money, or the one you liked?&#8221;  I was very happy to say I took the one I liked, and became a member of the <a href="http://www.goldencg.com/">Golden Consulting Group</a>.</p>
<p>Five years later, in March of 2005, I formed <a href="http://www.kousenit.com">Kousen IT, Inc.</a>, and went out on my own.  I now look back and can honestly say that I&#8217;ve never been happier.  I spent years in jobs and in situations I intensely disliked.  It took me a long time to correct all that.  Now I&#8217;m finally in a job where</p>
<p>As for never missing a day of class, I simply can&#8217;t.  These aren&#8217;t like academic classes, where you see a single group of students for months at a time (though, come to think of it, I&#8217;ve never missed a day teaching an academic class, either :)).  People clear their work schedule for training classes.  The classes only last three to five days, too, so missing a day is a huge sacrifice.  No, I can&#8217;t miss a day if it&#8217;s physically possible to be there.  It&#8217;s more than a responsibility; it&#8217;s an obligation.</p>
<p>I freely admit, though, that keeping a perfect record going involves some luck.  I&#8217;ve certainly been sick enough to miss days.  Earlier this year I caught some stupid stomach bug that knocked me for a major loop.  I couldn&#8217;t get out of bed, much less make it to class.  I&#8217;m just glad it happened to hit me on a day I wasn&#8217;t scheduled to teach.</p>
<p>I&#8217;m sure that first missed day is coming.  Life simply isn&#8217;t always controllable like that.  Illnesses happen, and I received a reminder about a week ago that my parents are aging and no longer in the best of health.  As they say, stuff (or even life) happens.</p>
<p>Still, I wanted to take a moment to feel quietly pleased about the fact that I&#8217;ve made it this far.</p>
<p>Recent classes:</p>
<ul>
<li><a href="http://www.capcourse.com/162_Outline_30.html">EJB3</a> in Hampton, VA</li>
<li><a href="http://www.capcourse.com/121_Outline_50.html">Securing Java Web Applications</a> in Allentown, PA</li>
<li>Grails presentation at <a href="http://www.ctjava.org/">my local Java user&#8217;s group</a></li>
<li>My regular graduate class in Developing Enterprise Applications at Rensselaer</li>
</ul>
<p>Upcoming classes:</p>
<ul>
<li>OOAD/UML in Austin, TX</li>
<li>Java Web Security in Asheville, NC</li>
<li>Java Web Services in New Haven, CT</li>
<li>Java Web Security in Huntington Beach, CA</li>
</ul>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/122/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/122/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/122/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=122&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/06/16/eight-years-and-havent-missed-a-day-yet/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
		<item>
		<title>Silly GORM tricks, part III: SQL keywords as attributes</title>
		<link>http://kousenit.wordpress.com/2008/05/11/silly-gorm-tricks-part-iii-sql-keywords-as-attributes/</link>
		<comments>http://kousenit.wordpress.com/2008/05/11/silly-gorm-tricks-part-iii-sql-keywords-as-attributes/#comments</comments>
		<pubDate>Sun, 11 May 2008 20:45:36 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Grails]]></category>

		<category><![CDATA[dsl]]></category>

		<category><![CDATA[orm]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=121</guid>
		<description><![CDATA[I was writing a very simple Grails application and ran into a problem when I accidentally used a SQL keyword as a property name.  This post documents what happened, and how I (pretty easily) fixed it.
To illustrate the issue, consider a trivial Grails application called &#8220;messaging&#8221; with a single class called Message.


class Message {
 [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>I was writing a very simple Grails application and ran into a problem when I accidentally used a SQL keyword as a property name.  This post documents what happened, and how I (pretty easily) fixed it.</p>
<p>To illustrate the issue, consider a trivial Grails application called &#8220;<code>messaging</code>&#8221; with a single class called <code>Message</code>.</p>
<pre>
<code>
class Message {
  String from
  String to
  String text
}
</code>
</pre>
<p>This is supposed to represent a simple email message, with fields to represent the sender, the receiver, and the text of the message itself.  It seemed quite logical at the time to use the words <code>from</code>, <code>to</code>, and <code>text</code> for the fields, but that leads to problems.</p>
<p>I added a <code>MessageController</code> with dynamic scaffolding (i.e., <code>def scaffold = Message</code>) and started the server.  When I accessed the <code>MessageController</code> link, however, I got </p>
<p><code>org.hibernate.exception.SQLGrammarException: could not execute query</code></p>
<p>In order to see the actual problem, I modified my <code>DataSource.groovy</code> file to add &#8220;<code>loggingSql = true</code>&#8221; in the <code>dataSource</code> section.  After restarting the server, in the console window I saw that the exception was caused by a SQL command generated by the scaffolded <code>list</code> method in <code>MessageController</code>:</p>
<pre>
<code>
Hibernate:
    select
        this_.id as id0_0_,
        this_.version as version0_0_,
        this_.from as from0_0_,
        this_.text as text0_0_,
        this_.to as to0_0_
    from
        message this_ limit ?
</code>
</pre>
<p>This statement looks fine, and in fact there&#8217;s nothing wrong with it.  I couldn&#8217;t see the problem until I switched to MySQL so that I could browse the database independently.</p>
<p>(Switching to another database is covered many places in the Grails literature.  In short, it means adding the JDBC driver to the <code>messaging/lib</code> directory, creating the messaging database in MySQL, and changing the <code>driverClassName</code>, <code>url</code>, <code>username</code>, and <code>password</code> settings in <code>DataSource.groovy</code>.)</p>
<p>When I did that and checked the database with the MySQL client, I found the problem (or at least a symptom of it):<br />
<code><br />
mysql&gt; show tables;<br />
Empty set (0.00 sec)<br />
</code><br />
In other words, the problem was that the <code>message</code> table didn&#8217;t exist.  Somehow the SQL used to generate the table in the first place didn&#8217;t work.  </p>
<p>Logging the SQL as I did wasn&#8217;t sufficient to show me the CREATE TABLE statement.  If, however, I go into <code>Config.groovy</code> and change the value of <code>log4j.logger.org.hibernate</code> to <code>debug</code>, I see in the resulting console:</p>
<pre>
<code>
[1125] hbm2ddl.SchemaExport
    create table message (
        id bigint not null auto_increment,
        version bigint not null,
        from varchar(255) not null,
        text varchar(255) not null,
        to varchar(255) not null,
        primary key (id)
    )
</code>
</pre>
<p>followed immediately by<br />
<code><br />
[1125] hbm2ddl.SchemaExport Unsuccessful: create table message &#8230;<br />
[1125] hbm2ddl.SchemaExport You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near &#8216;from varchar(255) not null, text varchar(255) not null, to varchar(255) not null&#8217; at line 1<br />
</code></p>
<p>The problem is that the word &#8220;<code>from</code>&#8221; is a SQL keyword.  MySQL got upset when I tried to use it in the <code>create table</code> statement, as shown above.</p>
<p>How can I fix this?  I could change the name of the <code>from</code> property, to, say, <code>sender</code>.  Since Grails 1.0, however, GORM now has the ability to do custom ORM mappings, which feels like a cleaner way to solve the problem.  Therefore, I added the following closure to my class:</p>
<pre>
<code>
static mapping = {
  from column: 'sender'
}
</code>
</pre>
<p>Now the generated create statement is:</p>
<pre>
<code>
[1157] hbm2ddl.SchemaExport
    create table message (
        id bigint not null auto_increment,
        version bigint not null,
        sender varchar(255) not null,
        text varchar(255) not null,
        to varchar(255) not null,
        primary key (id)
    )
</code>
</pre>
<p>and the new error is<br />
<code><br />
[1157] hbm2ddl.SchemaExport You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near &#8216;to varchar(255) not null, primary key (id))&#8217; at line 1<br />
</code><br />
So apparently the word &#8220;<code>to</code>&#8221; is also a problem.  I therefore modified the <code>mapping</code> closure to include it as well:</p>
<pre>
<code>
static mapping = {
  from column: 'sender'
  to column: 'receiver'
}
</code>
</pre>
<p>Now it all works as it should.  The lesson appears to be either that I should keep a list of SQL keywords handy, or simply that the custom ORM DSL is a Good Thing(TM), and so are the logging settings. <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/121/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/121/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/121/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/121/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/121/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/121/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/121/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/121/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/121/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/121/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/121/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/121/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=121&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/05/11/silly-gorm-tricks-part-iii-sql-keywords-as-attributes/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
		<item>
		<title>Silly GORM tricks, part II: dependent variables</title>
		<link>http://kousenit.wordpress.com/2008/04/29/silly-gorm-tricks-part-ii-dependent-variables/</link>
		<comments>http://kousenit.wordpress.com/2008/04/29/silly-gorm-tricks-part-ii-dependent-variables/#comments</comments>
		<pubDate>Tue, 29 Apr 2008 14:24:57 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Grails]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=120</guid>
		<description><![CDATA[This post discusses a relatively simple topic in GORM: how to use dependent variables in a domain class.  It&#8217;s simple in the sense that it&#8217;s been discussed on the mailing list, but I haven&#8217;t seen it documented anywhere so I thought I&#8217;d do so here.
I started with a simple two-class domain model that I [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>This post discusses a relatively simple topic in GORM: how to use dependent variables in a domain class.  It&#8217;s simple in the sense that it&#8217;s been discussed on the mailing list, but I haven&#8217;t seen it documented anywhere so I thought I&#8217;d do so here.</p>
<p>I started with a simple two-class domain model that I discussed in <a href="http://kousenit.wordpress.com/2008/04/22/silly-gorm-tricks-part-i-lists/">my last GORM post</a>.</p>
<pre>
<code>class Quest {
    String name
    static hasMany = [tasks:Task]
    String toString() { name }
}</code>
</pre>
<pre>
<code>class Task {
    String name
    static belongsTo = [quest:Quest]
    String toString() { name }
}</code>
</pre>
<p>As before, there is a one-to-many relationship between quests and tasks.  A quest has many tasks, and the <code>belongsTo</code> setting implies a cascade-all relationship, so inserting, updating, or deleting a quest does the same for all of its associated tasks.</p>
<p>In <code>Bootstrap.groovy</code>, I also have:</p>
<pre>
<code>def init = { servletContext -&gt;
         new Quest(name:'Seek the grail')
            .addToTasks(name:'Join King Arthur')
            .addToTasks(name:'Defeat Knights Who Say Ni')
            .addToTasks(name:'Fight Killer Rabbit')
            .save()
}</code></pre>
<p>which shows how the classes are intended to work together.</p>
<p>The first change I want to make is to give tasks a start date and end date.  My first attempt is to just add properties with those names, of type <code>java.util.Date</code>.</p>
<pre>
<code>class Task {
  String name
  Date start
  Date end
  // ... rest as before ...
}</code></pre>
<p>This leads to a minor problem.  If I start up the server, I don&#8217;t see any quests or tasks.  The reason is that my bootstrap code tries to create tasks without start and end dates, which violates the database schema restriction.  My generated schema marks both <code>start</code> and <code>end</code> columns as &#8220;not null&#8221;.</p>
<p>There are many ways to fix that.  I can either assign both <code>start</code> and <code>end</code> properties for each task in my bootstrap code, or add a constraint in Task that both can be <code>nullable</code>, or do what I did here, which is to give them default values.</p>
<pre>
<code>class Task {
  String name
  Date start = new Date()
  Date end = new Date() + 1
  // ... rest as before ...
}</code>
</pre>
<p>I do have a constraint in mind, actually.  I&#8217;d like to ensure that the <code>end</code> date is after the <code>start</code> date.  That requires a custom validator, which is also pretty easy to implement:</p>
<pre>
<code>class Task {
  // ...
  static constraints = {
    name(blank:false)
    start()
    end(validator: {  value, task -&gt;
       value &gt;= task.start
    })
  }
}</code>
</pre>
<p>That works fine.  </p>
<p>Now for the dependent variable.  My tasks all have a <code>start</code> and an <code>end</code>, so implicitly they have a duration.  I could add the <code>duration</code> variable to my Task class, but I don&#8217;t want to save it in the database.  It&#8217;s dependent on the values of <code>start</code> and <code>end</code>.  I also don&#8217;t want to be able to set it from the gui.</p>
<p>Here&#8217;s the result:</p>
<pre>
<code>class Task {
  String name
  Date start
  Date end

  int getDuration() { (start..end).size() }
  void setDuration(int value) {}

  static transients = ['duration']

  // ... rest as before ...
}</code>
</pre>
<p>This computes the <code>duration</code> from the <code>start</code> and <code>end</code> dates by returning the number of days between them.  It relies on the fact that Groovy modifies <code>java.util.Date</code> to have the methods <code>next()</code> and <code>previous()</code>, and since <code>Date</code> implements <code>Comparable</code>, it can then be used in a range, as shown.</p>
<p>(As an aside, this implementation is probably pretty inefficient.  If the number of days between start and end was substantial, I think this implementation executes the <code>next()</code> method over and over until it reaches the end.  I thought about trying to subtract the two dates, but interestingly enough the <code>Date</code> class only has <code>plus()</code> and <code>minus()</code> methods that take <code>int</code> values, not other Dates.  I considered adding a category that implemented those methods, but haven&#8217;t tried it yet.  I&#8217;d like to look in the Groovy source code for the <code>plus()</code> and <code>minus()</code> implementations, but I couldn&#8217;t find it.  I did find something similar in <code>org.codehaus.groovy.runtime.DefaultGroovyMethods</code>, but I&#8217;m not sure that&#8217;s the same thing.  Sigh.  Still a lot to learn&#8230;)</p>
<p>By putting <code>'duration'</code> in the <code>transients</code> closure, I ensure that it isn&#8217;t saved in the database.</p>
<p>The <code>getDuration</code> method is pretty intuitive, but adding set method as a no-op is somewhat annoying.  If I leave it out, then Groovy will generate a setter that can modify the duration.  As an alternative, according to <a href="http://www.manning.com/koenig/">GinA</a> I can also supply my own backing field and mark it as final:</p>
<pre>
<code>class Task {
  // ...
  final int duration

  int getDuration() { (start..end).size() }
  // ...
}</code>
</pre>
<p>Just to be sure, I added the following test to my <code>TaskTests</code>:</p>
<pre>
<code>void testSetDuration() {
    Task t = new Task(name:'Join King Arthur')
    shouldFail(ReadOnlyPropertyException) {
        t.duration = 10
    }
   q.addToTasks(t).save()
}</code>
</pre>
<p>That passed without a problem.</p>
<p>Interestingly, the dynamic scaffold still generates a modifiable input text field for duration, both in the create and edit views.  I can put my own value in it and submit the form without a problem.  The result does not get saved, which is correct, but I don&#8217;t see an exception thrown anywhere in the console.  If I generate the static scaffolding, I know that in <code>Task.save</code> there is a line like</p>
<p><code>t.properties = params</code></p>
<p>which is how the form parameters are transfered to the object.  Presumably the internal logic knows enough to avoid trying to invoke a setter on a final field.  Of course, as soon as I generate the static scaffolding, I usually just delete that row in the GSP form.</p>
<p>There&#8217;s one final (no pun intended) issue with the dynamic scaffolding.  The generated list view puts its properties in <code>&lt;g:sortableColumn&gt;</code> tags.  This holds true for the duration, as well.  Normally, when I click on the column header, the result is sorted, ascending or descending, by that property.  If I click on the <code>duration</code> column header, however, I get an &#8220;<code>org.hibernate.QueryException: could not resolve property: duration of: Task</code>&#8220;.</p>
<p>It turns out that the <a href="http://grails.org/doc/1.0.x/">User Guide</a> has a &#8220;Show Source&#8221; link for every tag.  When I clicked on that link for the <code>sortableColumn</code> tag, I saw near the top:</p>
<pre>
<code>if(!attrs.property)
  throwTagError("Tag [sortableColumn] is missing required attribute [property]")
</code>
</pre>
<p>The error I got in the console is &#8220;could not resolve property&#8221;, but it&#8217;s possible this is the source of that issue.  I&#8217;m not sure.  The only other source (again, no pun intended) of the problem I could see was the execution of the <code>list</code> action at the bottom.  That would imply that Grails is generating the Hibernate query and we&#8217;re failing at that point, which would be consistent with the error reported above.</p>
<p>At any rate, the duration property now works in the domain class.  I can always modify the views to ensure I don&#8217;t try to set it.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/120/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/120/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/120/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/120/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/120/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/120/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/120/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/120/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/120/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/120/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/120/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/120/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=120&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/04/29/silly-gorm-tricks-part-ii-dependent-variables/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
		<item>
		<title>Silly GORM tricks, part I: Lists</title>
		<link>http://kousenit.wordpress.com/2008/04/22/silly-gorm-tricks-part-i-lists/</link>
		<comments>http://kousenit.wordpress.com/2008/04/22/silly-gorm-tricks-part-i-lists/#comments</comments>
		<pubDate>Wed, 23 Apr 2008 03:52:30 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Grails]]></category>

		<category><![CDATA[GORM]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=119</guid>
		<description><![CDATA[In GORM, when one class has a hasMany relationship with another, a java.util.Set is injected into the class.  Sometimes, though, I want to use a List instead in order to maintain ordering.   The Grails reference documents (see section 5.2.4 specifically) discuss how to do that, but there are other issues that I [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>In <a href="http://docs.codehaus.org/display/GRAILS/GORM">GORM</a>, when one class has a <code>hasMany</code> relationship with another, a <code>java.util.Set</code> is injected into the class.  Sometimes, though, I want to use a <code>List</code> instead in order to maintain ordering.   The <a href="http://grails.org/doc/1.0.x/">Grails reference documents</a> (see section 5.2.4 specifically) discuss how to do that, but there are other issues that I needed to solve in order to make this work.</p>
<p>Consider an application that demonstrates the issue involved.  It has only two domain classes, <code>Quest</code> and <code>Task</code>.  A <code>Quest</code> consists of many <code>Task</code>s.</p>
<pre>
<code>
class Quest {
    String name

    static hasMany = [tasks:Task]

    String toString() { name }
}

class Task {
    String name

    static belongsTo = [quest:Quest]

    String toString() { name }
}
</code>
</pre>
<p>I&#8217;m using a bi-directional one-to-many association here, mostly because the dynamic scaffolding works well with it (not the best reason, of course, but it makes it easy to illustrate the point).  The <code>hasMany</code> assignment means that the <code>Quest</code> class will have a <code>Set</code> injected into it called <code>tasks</code>, and the <code>belongsTo</code> relationship means that all the cascade relationships (save, update, and delete) will work, too.</p>
<p>Before I take advantage of that in my boostrap code, though, I used the dynamic scaffolding just to make sure I could add quests and tasks through the normal views.<br />
<code><br />
class QuestController { def scaffold = Quest }</p>
<p>class TaskController { def scaffold = Task }<br />
</code><br />
As it happens, everything does work as advertised.  A simple integration test that demonstrates it is shown below, which works.</p>
<pre>
<code>
void testAddTasks() {
    Quest q = new Quest(name:'Seek the grail')
    q.addToTasks(name:'Join King Arthur')
        .addToTasks(name:'Defeat Knights Who Say Ni')
        .addToTasks(name:'Fight Killer Rabbit')
        .save()
    assertEquals 3, Task.count()
}
</code>
</pre>
<p>Everything so far is standard stuff.  One of the defining characteristics of a <code>Set</code>, however, is that it does not support ordering.  If I want ordering, there&#8217;s a chrysalis stage I can go through on the way to a <code>List</code>, which is to use a <code>SortedSet</code> (assuming <code>Task</code> implements the <code>Comparable</code> interface).</p>
<pre>
<code>
class Quest {
    String name
    SortedSet tasks

    static hasMany = [tasks:Task]

    String toString() { name }
}

class Task implements Comparable {
    String name

    static belongsTo = [quest:Quest]

    String toString() { name }

    int compareTo(Object o) {
        return name.compareTo(o.name)
    }
}
</code>
</pre>
<p>The dynamic scaffolding still works, too.  I can add a task, as long as there is a quest available to add it to.  The tasks are sorted by name, as they should be.  I added the above quest and tasks to my bootstrap code, too, so they were available as soon as my server started.</p>
<p>Incidentally, there&#8217;s a down side to using a <code>SortedSet</code> that I hadn&#8217;t realized right away.  When I first wrote my application, I added a degree of difficulty to my tasks and tried sorting by them.</p>
<pre>
<code>
class Task implements Comparable {
    String name
    Integer difficulty

    // ...

    int compareTo(Object o) {
        return difficulty - o.difficulty
    }
}
</code>
</pre>
<p>That sorts tasks by difficulty all right, but there&#8217;s another consequence.  I can only add a single task of a given difficulty to a particular quest!  I can&#8217;t have two tasks both with the same difficulty.  A <code>SortedSet</code> may be sorted, but it&#8217;s still a set. <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>So now I move on to using a <code>List</code>.  As the reference documentation says, to do that, just declare tasks to be a reference of type <code>List</code>.</p>
<pre>
<code>
class Quest {
    String name
    List tasks

    // ...

    static hasMany = [tasks:Task]
}
</code>
</pre>
<p>Now there&#8217;s trouble.  The server starts, and the bootstrap code works, because it adds tasks to an existing quest before saving them.  The dynamic scaffolding has a serious problem, though.  When I go to the tasks list and try to add a new task, everything is fine until I try to save the new task.</p>
<p>If I try to add a new task through the &#8220;Create Task&#8221; page, I get an exception: &#8220;<code>org.hibernate.PropertyValueException: not-null property references a null or transient value</code>&#8220;.</p>
<p>The reason is addressed in the reference documentation.  First, changing to a list means that the database table for tasks now has an index column.  Second, as the documentation says, you can&#8217;t save a task by itself any more &#8212; you have to add it to a quest first.  It&#8217;s okay to say:<br />
<code><br />
def t = new Task(&#8217;Answer the bridgekeeper&#8217;)<br />
</code><br />
but I can&#8217;t save it by itself, or that index column will be a problem.  I have to add the task to a quest first before saving.<br />
<code><br />
Quest.get(1).addToTasks(t).save()<br />
</code><br />
That works.  Otherwise I get a <code>null</code> in that index column, which throws an exception and down goes the server.</p>
<p>So, knowing that, how do I fix the system?</p>
<p>Well, I definitely have to abandon the dynamic scaffolding.  The built-in <code>save</code> method isn&#8217;t going to work, because it saves the task independently of the quest.  So, it&#8217;s time to generate the real controllers.</p>
<p>After generating the task controller and views, the <code>save</code> method looks like:</p>
<pre>
<code>
def save = {
    def task = new Task(params)
    if(!task.hasErrors() &amp;&amp; task.save()) {
        flash.message = "Task ${task.id} created"
        redirect(action:show,id:task.id)
    }
    else {
        render(view:'create',model:[task:task])
    }
}
</code>
</pre>
<p>I need to add the task to a quest and then save the quest.  Fortunately, one of the parameters in the request is the id of the quest, under <code>params.quest.id</code>.  That means my first try is to change the above code to this:</p>
<pre>
<code>
def save = {
    def task = new Task(params)
    def q = Quest.get(params.quest.id)
    q.addToTasks(task)
    if (!task.hasErrors() &amp;&amp; q.save()) {
        // ... etc ...
}
</code>
</pre>
<p>Unfortunately, this doesn&#8217;t work either.  When I fill in the page to make a new task and try to save it, I get a <code>NullPointerException</code> due to the fact that the task still has a null id.</p>
<p>This, I believe, turns out to be a Hibernate problem.  Hibernate doesn&#8217;t do the save when I ask it to, but rather is waiting until the &#8220;right moment&#8221; to do the commit.  Unfortunately, I need that commit right away.</p>
<p>Fortunately, there&#8217;s an answer to that, too.  The <code>save</code> method takes a <code>flush</code> parameter which can be set to <code>true</code>.</p>
<p>Therefore, I changed the above code to:</p>
<pre>
<code>
def save = {
    def task = new Task(params)
    def q = Quest.get(params.quest.id)
    q.addToTasks(task)
    if (!task.hasErrors() &amp;&amp; q.save(flush:true)) {
        // ... etc ...
}
</code>
</pre>
<p>Now, at long last, it all works.  The key was to add the task to the quest and save the quest with flush set to true.</p>
<p>It&#8217;s possible that there are alternative solutions, but this one worked for me.  If you know of better alternatives, please let me know.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/119/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/119/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/119/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=119&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/04/22/silly-gorm-tricks-part-i-lists/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
		<item>
		<title>assert != assertEquals (duh)</title>
		<link>http://kousenit.wordpress.com/2008/04/04/assert-assertequals-duh/</link>
		<comments>http://kousenit.wordpress.com/2008/04/04/assert-assertequals-duh/#comments</comments>
		<pubDate>Sat, 05 Apr 2008 03:57:53 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=118</guid>
		<description><![CDATA[It&#8217;s probably not great for my reputation to show how I made a very silly error, but since I did it so consistently I thought showing it might help somebody avoid it.
My Groovy course materials consist of far more scripts than classes.  That&#8217;s probably not surprising, given that teaching Groovy involves writing lots and [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>It&#8217;s probably not great for my reputation to show how I made a very silly error, but since I did it so consistently I thought showing it might help somebody avoid it.</p>
<p>My Groovy course materials consist of far more scripts than classes.  That&#8217;s probably not surprising, given that teaching Groovy involves writing lots and lots of quick-and-dirty examples.  The problem with scripts, though, is that they&#8217;re not as easy to test as classes.  With classes, I can create a class that extends <code>GroovyTestCase</code>, put in my tests and go.  With scripts, though, the same process would require either executing the script from a Groovy class and checking the binding properties, or simply using assert statements.</p>
<p>In general, I chose the latter.  In my scripts, I tried to complete each with at least one assert call that I could use later to validate the script.</p>
<p>Sounds like a reasonable approach, right?  Sure, until you start going too quickly.  What&#8217;s wrong with the following code?</p>
<pre>
<code>
// inject demo
def strings = ["Hello","World"]
int totalLength = strings.inject(0) { len, s -&gt;
    len += s.size()
}
assert 10, totalLength
</code></pre>
<p>The code is intended to be a trivial illustration of the <code>inject</code> method for lists.  The result is supposed to be the sum total of the lengths of all the strings in the list.  Ignoring that there are many other ways to solve that problem, the difficulty here isn&#8217;t the inefficiency of the algorithm.  No, it&#8217;s a trap that as a long-time Java developer I found very easy to fall into.</p>
<p>The problem is with my <code>assert</code> statement.  The intention is to assert that the total length of the strings in the list is 10.  Sure enough, executing this code has no errors.  That&#8217;s not a big surprise (for me), because at first I started with a <code>println</code> statement to see what the value should be, and then I replaced <code>println</code> with an assertion.</p>
<p>Unfortunately, though, my assertion didn&#8217;t prove anything about the script.  That becomes obvious if I add another line to the program:<br />
<code><br />
assert 50000, totalLength<br />
</code><br />
which passes just as easily.</p>
<p>What&#8217;s wrong?  I&#8217;m using assert as though it was a two-parameter method, like <code>assertEquals</code> in <code>GroovyTestCase</code>.  </p>
<p>What I&#8217;m trying to do is to specify the right answer followed by the actual test.  What I&#8217;m actually doing is asserting that the first argument (a literal number) is true, and supplying an error message to print if not.  By the Groovy truth, any non-zero number is always true, so my <code>totalLength</code> never needs to be converted to a string and printed as the the error message.</p>
<p>What I really want to use, of course, is<br />
<code><br />
assert 10 == total, &#8220;total should be 10&#8243;<br />
</code><br />
I think this is an easy trap for Java developers to fall into, because they&#8217;re not accustomed to the Groovy truth.  In Java, only a real boolean expression can be true or false, not just a number.</p>
<p>What&#8217;s truly embarrassing is how many of my scripts were just asserting that a non-zero value was true, which always works.  </p>
<p>Once I realized my mistake (because somebody pointed out one of my bad examples), I had to go back and fix all of my tests.  They&#8217;re better now. <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/118/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/118/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/118/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=118&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/04/04/assert-assertequals-duh/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
		<item>
		<title>Some notes about the Windows installer for Grails</title>
		<link>http://kousenit.wordpress.com/2008/03/26/some-notes-about-the-windows-installer-for-grails/</link>
		<comments>http://kousenit.wordpress.com/2008/03/26/some-notes-about-the-windows-installer-for-grails/#comments</comments>
		<pubDate>Wed, 26 Mar 2008 20:21:57 +0000</pubDate>
		<dc:creator>Ken Kousen</dc:creator>
		
		<category><![CDATA[Grails]]></category>

		<guid isPermaLink="false">http://kousenit.wordpress.com/?p=117</guid>
		<description><![CDATA[This isn&#8217;t really a problem, but I don&#8217;t think it&#8217;s documented anywhere, so I thought I&#8217;d record it here.
(And by the way, if your reaction to my Windows-based comments is going to be &#8220;why not use something other than Windows,&#8221; my answer is (1) at least one of my machines is always running Windows, but [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>This isn&#8217;t really a problem, but I don&#8217;t think it&#8217;s documented anywhere, so I thought I&#8217;d record it here.</p>
<p>(And by the way, if your reaction to my Windows-based comments is going to be &#8220;why not use something other than Windows,&#8221; my answer is (1) at least one of my machines is always running Windows, but more importantly (2) my clients overwhelmingly use Windows in their training rooms, so I can&#8217;t get away from it even if I wanted to.)</p>
<p>Like Groovy, <a href="http://grails.org/Download">the Grails downloads page</a> includes a special installer for Windows.  You don&#8217;t have to use it &#8212; it&#8217;s still fine to just download the zip file, unpack it, set the GRAILS_HOME variable and go on, but if you do decide to use the Windows installer you should know that a few details have changed.</p>
<p>First of all, when the installer runs, it creates a different directory structure than that found in the regular zip file.  The installer creates a structure like:</p>
<p>c:\grails-1.0.2\<br />
bin\<br />
gbin\<br />
grails\<br />
&#8230; other files ..</p>
<p>which means the GRAILS_HOME variable needs to point to &#8220;c:\grails-1.0.2\grails&#8221; rather than &#8220;c:\grails-1.0.2&#8243; as the User Guide says.  That also means that if you want to put Grails in your path for all command prompts, you need the &#8220;bin&#8221; directory under &#8220;grails&#8221;, not the one under &#8220;grails-1.0.2&#8243;.  Personally, I assigned GRAILS_HOME to &#8220;c:\grails-1.0.2\grails&#8221; and put &#8220;%GRAILS_HOME%\bin&#8221; in my path, just be sure.</p>
<p>This also comes up if you&#8217;re using <a href="http://www.jetbrains.net/confluence/display/GRVY/Groovy+Home">the JetGroovy plug-in for IntelliJ IDEA</a>.  The plug-in requires you to specify where the root of the Grails distribution is, which again is the &#8220;grails&#8221; subdirectory.</p>
<p>In principle, a lot of this isn&#8217;t even necessary.  The installer creates a desktop shortcut called &#8220;Grails Environment&#8221; which is a configured command prompt.  When I fire it up on my machine and check the path, I see that the directories</p>
<p>c:\jdk1.6.0\bin<br />
C:\GRAILS~1.2\grails\ant\bin<br />
C:\GRAILS~1.2\grails\bin<br />
C:\GRAILS~1.2\GRAILS\..\gbin</p>
<p>have all been prepended (i.e., they appear at the beginning, rather than the end) to my path.  The first one is very likely just my &#8220;%JAVA_HOME%\bin&#8221;, which was already in there, but again that&#8217;s not really a problem.</p>
<p>The other interesting characteristic about the &#8220;Grails Environment&#8221; window is that inside it, you don&#8217;t need to type the word &#8220;grails&#8221; in front of each command.  You can just type &#8220;create-domain-class myclass&#8221; or whatever, and it works automatically.  The Grails command line interface is already running.</p>
<p>For the create-* commands to work correctly, of course, you need to be in the root of your Grails application.  The environment prompt looks like this:</p>
<p>[C:\grails-1.0.2]<br />
grails:\&gt;</p>
<p>at it starts, which is in the root of the Grails distribution.  I needed to change directories to my own application, so after a couple of &#8220;cd&#8221;s I wound up with</p>
<p>[C:\grails_apps\myapp]<br />
grails:\&gt;</p>
<p>The environment supports all the normal DOS commands, like &#8220;dir&#8221; or &#8220;cd&#8221;.</p>
<p>Incidentally, there&#8217;s no problem firing up more than one instance of the &#8220;Grails Environment&#8221;.  It creates a separate command window for each case.</p>
<p>There has also been a change to the documentation.  In earlier versions, the User Guide (an excellent resource, getting better all the time) was stored in HTML form, and was basically a copy of the documentation found <a href="http://grails.org/doc/1.0.x/">here</a>.  Now, using the installer, the documentation has been bundled inside a Windows help file, which has the file extension *.chm.</p>
<p>Finally, the installer adds entries under &#8220;Start-&gt;All Programs-&gt;Grails 1.0.2&#8243;.  Those entries are:</p>
<p>API Documentation  (a link to the included JavaDocs for Grails)<br />
Grails Environment (discussed above)<br />
Grails References (a link to the Windows help file)<br />
Grails Web site (a link to http:\\grails.org)<br />
Uninstall Grails 1.0.2 (which does what it says)</p>
<p>As with most things in Grails, it&#8217;s very forgiving.  You can use it, or not.  If you prefer the older (or should I say, &#8220;classic&#8221;?) style, just download the zipped distribution and go from there.  If you want the installer to do that extra work for you, that&#8217;s fine too.  I think, though, that including a README file of some kind containing all this information might be helpful.</p>
<p>Still, I tend to like these sorts of installers.  I spend more time running training classes than I do on my own systems doing development, so set-up is an ongoing challenge for me.  I&#8217;m tempted to tell the person setting up a training room to just download and run the Windows installer and they&#8217;re done.  I may do that for my upcoming Grails class, but I haven&#8217;t quite decided yet.</p>
<p>By the way, Groovy also comes with a Windows installer.  I really like that one.  It creates the same directory structure that the zip file contains, but it also offers to create a GROOVY_HOME variable and add its &#8220;bin&#8221; directory to either your path or the system path, installs a native environment (whatever that is, but it sounded good), and downloads and installs optional components like Scriptom and the Graphics environment.  Using that one is a no-brainer for me, though I&#8217;ve found it to be a bit slow.</p>
<p>I hope this helps someone.  The creator of the installer is Chanwit Kaewkasi, who is active on the Grails users list.  He was kind enough to answer my questions about it there.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/117/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/117/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/117/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&blog=186706&post=117&subd=kousenit&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://kousenit.wordpress.com/2008/03/26/some-notes-about-the-windows-installer-for-grails/feed/</wfw:commentRss>
	
		<media:content url="http://a.wordpress.com/avatar/kousenit-128.jpg" medium="image">
			<media:title type="html">kousenit</media:title>
		</media:content>
	</item>
	</channel>
</rss>