<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Matt Stine&#039;s Blog &#187; grails</title>
	<atom:link href="http://mattstine.com/category/grails/feed/" rel="self" type="application/rss+xml" />
	<link>http://mattstine.com</link>
	<description>Thoughts on Java, Groovy, Grails, Agile Development, etc. etc. etc.</description>
	<lastBuildDate>Tue, 17 May 2011 17:02:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='mattstine.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Matt Stine&#039;s Blog &#187; grails</title>
		<link>http://mattstine.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://mattstine.com/osd.xml" title="Matt Stine&#039;s Blog" />
	<atom:link rel='hub' href='http://mattstine.com/?pushpress=hub'/>
		<item>
		<title>Securing Grails Plugin Artifacts with Filters</title>
		<link>http://mattstine.com/2009/11/10/securing-grails-plugin-artifacts-with-filters/</link>
		<comments>http://mattstine.com/2009/11/10/securing-grails-plugin-artifacts-with-filters/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 18:50:11 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=278</guid>
		<description><![CDATA[So you&#8217;ve just installed the handy dandy Spring Security plugin (http://grails.org/plugin/acegi), which makes it incredibly easy to secure entire Grails controllers and/or controller actions with annotations, such as the following: This is enabled by turning on controller annotations in your SecurityConfig.groovy file: So all is now good in our project. We can secure either controllers [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=278&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>So you&#8217;ve just installed the handy dandy Spring Security plugin (http://grails.org/plugin/acegi), which makes it incredibly easy to secure entire Grails controllers and/or controller actions with annotations, such as the following:</p>
<p>This is enabled by turning on controller annotations in your SecurityConfig.groovy file:</p>
<p>So all is now good in our project. We can secure either controllers or actions with annotations, enabling us to declaratively setup security side-by-side with the code that we&#8217;re securing in a very straightforward manner. You can continue developing your Grails applications with glee, fully assured that security is no longer an issue. But wait, one day you decide to install one of the many useful Grails plugins that add controller artifacts to your application. Lo and behold, you have no way to secure those controllers! Of course, you could descend into $USER_HOME/.grails/$GRAILS_VERSION/projects/projectName/plugins/pluginX and hack the source code for your individual instance of the plugin. This ought to work, but you&#8217;re now rather constrained in that every time you update the plugin you&#8217;ll need to remember to go make this manual change. That doesn&#8217;t sound very agile at all, does it? OK, so how about forking the plugin? This is a little bit better, but now you have the burden of merging changes from the global plugin repository to yours every time a new release happens. This is better, but still a bit cumbersome. How about becoming a committer and adding it to the global source? Of course not. Not everyone will want to secure their plugins the same way you do, and you&#8217;ve just introduced a rather unnecessary dependency on the Spring Security plugin. I say all this in an attempt to paint a grim picture. In reality, we&#8217;re actually in very good shape. Grails Filters to the rescue!</p>
<p>All that you need to do is create a Grails filter that will match requests to the plugin artifact in question and then delegate to Spring Security for authorization. If they are authorized, you simply return true. If not, you can direct them to your login screen. It&#8217;s this simple:</p>
<p>As you can see here, I&#8217;ve secured both the Blurb plugin and the Settings plugin in this manner by requiring that the logged in user be in the ROLE_ADMIN role. Now as Glen Smith would say, that&#8217;s a snack!</p>
<p><em><strong>Update:</strong> <a href="http://burtbeckwith.com/blog/">Burt Beckwith</a> enlightened me to an approach that will get this done without the use of filters that will also direct you to the requested URL after login rather than the main page. Unfortunately I&#8217;ve never been able to track this down before. Just add the following to SecurityConfig.groovy:</em></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/278/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/278/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/278/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/278/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/278/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/278/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/278/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/278/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/278/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/278/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/278/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/278/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/278/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/278/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=278&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2009/11/10/securing-grails-plugin-artifacts-with-filters/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>
	</item>
		<item>
		<title>Deploying Grails to Morph AppSpace: #CommunityOne 2009 Lightning Talk</title>
		<link>http://mattstine.com/2009/06/01/deploying-grails-to-morph-appspace-communityone-2009-lightning-talk/</link>
		<comments>http://mattstine.com/2009/06/01/deploying-grails-to-morph-appspace-communityone-2009-lightning-talk/#comments</comments>
		<pubDate>Tue, 02 Jun 2009 04:56:06 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[cloud]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[javaone2009]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=174</guid>
		<description><![CDATA[I gave two lightning talks at CommunityOne today, the first of which described deploying Grails applications to Morph AppSpace. For the uninitiated, Grails is a Ruby on Rails inspired full stack web development framework which brings &#8220;convention over configuration&#8221; and &#8220;DRY&#8221; into the Java web development arena. Unlike Rails, it is not an effort from [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=174&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I gave two lightning talks at <a href="http://developers.sun.com/events/communityone/2009/west/index.jsp">CommunityOne</a> today, the first of which described deploying <a href="http://grails.org">Grails</a> applications to <a href="http://mor.ph/products_appspace">Morph AppSpace</a>.</p>
<p>For the uninitiated, Grails is a Ruby on Rails inspired full stack web development framework which brings &#8220;convention over configuration&#8221; and &#8220;DRY&#8221; into the Java web development arena. Unlike Rails, it is not an effort from scratch, but rather stands on the shoulders of proven giants in the Java world like the Spring framework and Hibernate. It does this using Groovy, the popular dynamic scripting language for the JVM, as a sort of &#8220;DSL for web development.&#8221; Find it at <a href="http://grails.org">http://grails.org</a>.</p>
<p>Morph AppSpace on the other hand is a fully-configured and managed environment for hosting web applications, and currently supports Java, Grails, Rails, and PHP applications. It is a &#8220;platform as a service&#8221; (PaaS) provider that abstracts away the details of Amazon EC2 and S3 technologies. Systems architecture, backups, monitoring, failover, scalability &#8211; all of this is handled by Morph. You simply develop and deploy your application &#8211; Morph does the rest. Find it at <a href="http://mor.ph/products_appspace">http://mor.ph/products_appspace</a>.</p>
<p>So to get going, visit <a href="http://mor.ph">http://mor.ph</a> and sign up for a free developer account. Create yourself a Java application subscription, and pick your choice of database (MySQL or PostgreSQL). Create the database, and then download two very important files into the root directory of your Grails project: deployment.properties, which contains the metadata describing your application to the Morph AppSpace platform, and morph_deployer.jar, which contains the client API to the platform.</p>
<p>Next you&#8217;ll need to install the <a href="http://grails.org/plugin/morph-deploy">Grails morph-deploy plugin</a>. If you&#8217;re using Grails 1.1, you&#8217;ll need to checkout <a href="https://svn.codehaus.org/grails-plugins/grails-morph-deploy/trunk/">the trunk version from SVN</a>, as the version in the plugin repository is not 1.1 ready. Install this plugin locally by running &#8220;grails install-plugin $PATH_TO_PLUGIN.&#8221; Next, you&#8217;ll need to edit DataSource.groovy to contain the following:</p>
<pre class="brush: groovy">
production {
        dataSource {
            driverClassName = 'com.mysql.jdbc.Driver'
            dbCreate = "update"
            jndiName = "java:comp/env/jdbc/morph-ds"
            dialect = 'org.hibernate.dialect.MySQLDialect'
        }
}
</pre>
<p>Finally, run &#8220;grails war&#8221; to build the war file, and &#8220;grails deploy&#8221; to upload your application to the platform. Once the upload is complete, visit the management interface and check the logs to see that you&#8217;ve successfully deployed. Once it&#8217;s finished, click on the link to your application. Happy Grails on the cloud!</p>
<p>Here&#8217;s the screencast from my talk. Enjoy!</p>
<span style="text-align:center; display: block;"><a href="http://mattstine.com/2009/06/01/deploying-grails-to-morph-appspace-communityone-2009-lightning-talk/"><img src="http://img.youtube.com/vi/JYPJ26-1YTM/2.jpg" alt="" /></a></span>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/174/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=174&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2009/06/01/deploying-grails-to-morph-appspace-communityone-2009-lightning-talk/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>
	</item>
		<item>
		<title>Grails PayPal Plugin Update</title>
		<link>http://mattstine.com/2009/05/11/grails-paypal-plugin-update/</link>
		<comments>http://mattstine.com/2009/05/11/grails-paypal-plugin-update/#comments</comments>
		<pubDate>Mon, 11 May 2009 21:16:48 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[grails]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=166</guid>
		<description><![CDATA[Since I last posted on my fork of the Grails PayPal Plugin, I&#8217;ve been invited to be a committer on the Grails Plugins project at the Codehaus. I&#8217;ll be incorporating my changes into the SVN repository there and updating the documentation on the main Grails Plugins website. Look for these updates coming soon!!!<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=166&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Since I last posted on <a href="http://www.mattstine.com/2009/05/02/ive-forked-the-grails-paypal-plugin/">my fork of the Grails PayPal Plugin</a>, I&#8217;ve been invited to be a committer on the <a href="http://xircles.codehaus.org/projects/grails-plugins">Grails Plugins project at the Codehaus</a>. I&#8217;ll be incorporating my changes into the SVN repository there and updating the documentation on the main Grails Plugins website. Look for these updates coming soon!!!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/166/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=166&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2009/05/11/grails-paypal-plugin-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>
	</item>
		<item>
		<title>I&#8217;ve &#8220;forked&#8221; the Grails PayPal Plugin&#8230;</title>
		<link>http://mattstine.com/2009/05/02/ive-forked-the-grails-paypal-plugin/</link>
		<comments>http://mattstine.com/2009/05/02/ive-forked-the-grails-paypal-plugin/#comments</comments>
		<pubDate>Sat, 02 May 2009 05:59:46 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[CodeProject]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=158</guid>
		<description><![CDATA[I&#8217;m currently completing the finishing touches on a new e-commerce site for my wife&#8217;s stationary business. We decided a long time ago to use PayPal for all of the payment processing since we&#8217;ve had a great experience using it for our eBay selling. About a year ago Graeme Rocher polished off the last release of [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=158&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m currently completing the finishing touches on a new e-commerce site for my wife&#8217;s stationary business. We decided a long time ago to use <a href="http://www.paypal.com">PayPal</a> for all of the payment processing since we&#8217;ve had a great experience using it for our eBay selling. About a year ago Graeme Rocher polished off the last release of a <a href="http://grails.org/plugin/paypal">PayPal plugin</a> that is available in <a href="http://grails.org/plugin/home">the Grails Plugin repository</a>. It really is a very nice plugin, yet I had a couple of problems with it:</p>
<ul>
<li>It is only capable of handling payments for one item transactions via &#8220;Buy Now&#8221; buttons. I want to upload an entire shopping cart full of multiple items.</li>
<li>It currently won&#8217;t handle shipping addresses. The site I&#8217;m building allows the user to maintain a list of shipping addresses, and I&#8217;d want to send the address information they choose along to PayPal.</li>
<li>Minor issue: needed to upgrade the plugin to Grails 1.1.</li>
</ul>
<p>So, I decided this evening to fork the plugin. I want to leverage all of the great work that has been done thus far (especially with the IPN processing part &#8211; superb stuff), but I have to add in these two functions and do the version upgrade. Interestingly enough I couldn&#8217;t get the tests to run out of the box after the upgrade. No good developer likes to modify code without a stable running test suite, right? So what I ended up doing was creating a new Grails 1.1 plugin project and copying the original artifacts over. Once this was done all of the tests ran perfectly.</p>
<p>So, at this point I&#8217;ve added function #1. You can now redirect to the &#8220;uploadCart&#8221; action. It assumes that you have already constructed a Payment object (now containing PaymentItems) and saved it, and then passed the transactionId along. I did this so that folks with multiple different ways of handling shopping carts could have some degree of flexibility &#8211; the onus is on you to map your cart to your Payment object correctly. The original functions implemented by Graeme are backward compatible, assuming only one PaymentItem in the Payment. I&#8217;ve run all of the original tests and also did some manual functional testing by running the plugin app against my own PayPal Sandbox account. So far so good. Look for more updates as this evolves. Once I get something I&#8217;m totally happy with I&#8217;ll see about getting it pushed back into the main plugin repo.</p>
<p>Want to take a closer look? Visit <a href="http://github.com/mstine/grails-paypal-plugin/tree/master">http://github.com/mstine/grails-paypal-plugin/tree/master</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/158/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/158/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/158/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/158/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/158/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/158/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/158/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/158/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/158/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/158/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/158/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/158/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/158/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/158/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=158&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2009/05/02/ive-forked-the-grails-paypal-plugin/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>
	</item>
		<item>
		<title>Grails, Prototype, Script.aculo.us &#8211; Persistent Grid Sorting Goodness</title>
		<link>http://mattstine.com/2009/04/25/grails-prototype-scriptaculous-persistent-grid-sorting-goodness/</link>
		<comments>http://mattstine.com/2009/04/25/grails-prototype-scriptaculous-persistent-grid-sorting-goodness/#comments</comments>
		<pubDate>Sat, 25 Apr 2009 05:14:40 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[ajax]]></category>
		<category><![CDATA[CodeProject]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[scriptaculous]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=139</guid>
		<description><![CDATA[Ever wanted to do drag-n-drop sorting of a grid of images on a page and persist it? Here&#8217;s my solution using Grails, Prototype, and Script.aculo.us. Basically what prompted this was the need for my wife to be able to sort the various product images that she had on a screen at any given time in [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=139&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Ever wanted to do drag-n-drop sorting of a grid of images on a page and persist it? Here&#8217;s my solution using Grails, Prototype, and Script.aculo.us.</p>
<p>Basically what prompted this was the need for my wife to be able to sort the various product images that she had on a screen at any given time in any way that she pleased, and it had to be easy to work with. What follows is by no means a complete solution to this problem, but it represents where I am in the development process and may be useful to you, my hapless reader.</p>
<p>Here&#8217;s some GSP code which basically lays out a grid of product images, 3 wide by <em>n</em> deep:</p>
<pre class="brush: xml">
&lt;div id="productThumbContainer"&gt;
  &lt;g:set var="rowIndex" value="${0}"/&gt;
&lt;g:each in="${products}" var="product" status="index"&gt;
  &lt;g:if test="${index % 3 == 0}"&gt;
    &lt;div id="productRow${rowIndex}" class="span-20 last product-row"&gt;
  &lt;/g:if&gt;
  &lt;div id="product_${product.id}" class="span-6 product &lt;g:if test="${(index % 3 == 2) || ((products.size() - index) == 1)}"&gt;last&lt;/g:if&gt;&lt;g:else&gt;append-1&lt;/g:else&gt;"&gt;
    &lt;img src="${resource(dir: grailsApplication.config.store.productImages.webPath, file: product?.thumbnailImage?.name)}" width="230" class="productImage"&gt;
    &lt;h3&gt;&lt;g:link controller="product" action="show" id="${product.id}"&gt;${product.name}&lt;/g:link&gt;&lt;/h3&gt;
  &lt;/div&gt;
  &lt;g:if test="${(index % 3 == 2) || ((products.size() - index) == 1)}"&gt;
    &lt;/div&gt;
    &lt;g:set var="rowIndex" value="${rowIndex + 1}"/&gt;
  &lt;/g:if&gt;
&lt;/g:each&gt;
&lt;/div&gt;
</pre>
<p>Now here&#8217;s where the magic happens:</p>
<pre class="brush: js">
document.observe('dom:loaded', function() {
      var productRows = $$('.product-row');

      var options = {
        constraint: false,
        overlap: 'horizontal',
        containment: productRows,
        dropOnEmpty: true,
        tag: 'div',
        onUpdate: updateRows
      };

      productRows.each(function(item) {
        Sortable.create(item, options);
      });

      $('persistOrderingButton').observe('click', function(event) {
          var sortString = '';
          productRows.each(function(row) {
              sortString += '&amp;';
              sortString += Sortable.serialize(row);
          });
          &lt;g:remoteFunction action="sortProducts" params="sortString" update="ajaxMessage" onSuccess="\$('ajaxMessage').show()"/&gt;
      });
});
</pre>
<p>What we&#8217;ve got here is, failure to communicate&#8230;oops, wrong synapse there&#8230;what we&#8217;ve got here is a Prototype selector that grabs everything with the class &#8220;.product-row.&#8221; It then takes these and creates a Scriptaculous Sortable for each of them, providing the object-literal &#8220;options.&#8221; Notice the &#8220;containment&#8221; option which allows you to drag products back and forth between the various rows.</p>
<p>Delving deeper into the magic is the callback function &#8220;updateRows.&#8221; This guy is my favorite Javascript creation in quite some time:</p>
<pre class="brush: js">
function updateRows(list) {
      var children = list.childElements();

      if (children.size() &lt; 3) {

        //If I&#039;m the last row, who cares!
        if (list.next() != null) {
          var prevRow = list.previous();

          if (prevRow != null) {
            var lastChild = prevRow.childElements()[prevRow.childElements().size() - 1].remove();
            list.insert({top:lastChild});
            updateRows(prevRow);
          } else {
            var lastRow = list.up().childElements()[list.up().childElements().size() - 1];
            var lastChild = lastRow.childElements()[lastRow.childElements().size() - 1].remove();
            list.insert({top:lastChild});
            updateRows(lastRow);
          }
        }
      } else if (children.size() == 3) {
        //Do nothing...gets me out of the recursion I hope!
      } else {
        var nextRow = list.next();
        var lastChild = children[children.size() - 1].remove();

        if (nextRow != null) {
          nextRow.insert({top:lastChild});
          updateRows(nextRow);
        } else {
          var topRow = list.up().childElements()[0];
          topRow.insert({top:lastChild});
          updateRows(topRow);
        }
      }

      var i = 0;
      Sortable.sequence(list).each(function(item) {
        var productId = &#039;product_&#039; + item;
        if (i &lt; 2) {
          $(productId).removeClassName(&#039;last&#039;);
          $(productId).removeClassName(&#039;append-1&#039;);
          $(productId).addClassName(&#039;append-1&#039;);
        } else {
          $(productId).removeClassName(&#039;last&#039;);
          $(productId).removeClassName(&#039;append-1&#039;);
          $(productId).addClassName(&#039;last&#039;);
        }
        i++;
      });
}
</pre>
<p>This function is organized around the fact that the only valid state for a grid of n-rows will be n-1 rows of 3 products, followed by one row of 1 &lt;= numProducts &lt;= 3. In most cases, if you drag a product from one row to another, you are violating that rule by creating a row with 2 products and a row with 4 products. This function solves the problem by recursively shifting the products down until reaching a stable state again.</p>
<p>There&#039;s a bit of noise there at the bottom of the function. I&#039;m using Blueprint CSS to do the layout for this application and I need to shift the various Blueprint classes around once everything is settled.</p>
<p>Finally, here&#039;s the persistence of the data when we click save:</p>
<pre class="brush: groovy">
def sortProducts = {
    TreeMap rowMap = new TreeMap()

    params.each {key, value -&gt;
      def matcher = key =~ /productRow(.*)\[\]/
      if (matcher.matches()) {
        def rowId = matcher[0][1]
        rowMap[rowId] = value
      }
    }

    def productIds = []
    rowMap.values().each { row -&gt;
      row.each {
        productIds &lt;&lt; it.toLong()
      }
    }

    shoppingService.saveSortOrder(productIds)

    render(&quot;Product sort order saved!&quot;)
}
</pre>
<p>and the logic from shoppingService.saveSortOrder():</p>
<pre class="brush: groovy">
def saveSortOrder(def productIds) {
    def productsToSort = Product.findAllByIdInList(productIds)

    def productMap = [:]
    def sortIndexList = []

    productsToSort.each {
      productMap[it.id] = it
      sortIndexList &lt;&lt; it.sortIndex
    }

    sortIndexList.sort()
    sortIndexList = sortIndexList.reverse()

    productIds.each {
      productMap[it].sortIndex = sortIndexList.pop()
    }

    productsToSort.each {
      it.save()
    }
}
</pre>
<p>You might wonder why this is so complex. What I haven&#8217;t fully described is the way products are organized into a hierarchy of various categories. When you&#8217;re sorting a screen, you&#8217;re only sorting a subset of the products that are in that particular category. However, the sort order is maintained across the entire product set in the database. So, this logic basically just shifts around the existing sort indicies, placing them in their new relative order.</p>
<p>Anyway, I don&#8217;t know how generally applicable this code is, but I had fun writing it and I hope you can get some use out of it. Cheers!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/139/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/139/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/139/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/139/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/139/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/139/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/139/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/139/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/139/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/139/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/139/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/139/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/139/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/139/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=139&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2009/04/25/grails-prototype-scriptaculous-persistent-grid-sorting-goodness/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>
	</item>
		<item>
		<title>LOTY Time Again: Scala or Clojure?!?!</title>
		<link>http://mattstine.com/2009/04/02/loty-time-again-scala-or-clojure/</link>
		<comments>http://mattstine.com/2009/04/02/loty-time-again-scala-or-clojure/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 20:21:21 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[CodeProject]]></category>
		<category><![CDATA[dynamiclanguages]]></category>
		<category><![CDATA[goals]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=113</guid>
		<description><![CDATA[In 2007 I established several professional development goals (and later reported my progress on these), one of which was to learn Groovy and Grails. This goal stemmed from the continually referenced idea from The Pragmatic Programmer to &#8220;learn a new language every year.&#8221; This idea has become so ubiquitous that it even has it&#8217;s own [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=113&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In 2007 <a href="http://www.mattstine.com/2007/07/10/my-professional-development-goals-for-2007-2008/">I established several professional development goals</a> (<a href="http://www.mattstine.com/2008/01/02/mid-year-review-my-professional-development-goals-for-2007-2008/">and later reported my progress on these</a>), one of which was to learn Groovy and Grails. This goal stemmed from the continually referenced idea from <em>The Pragmatic Programmer</em> to &#8220;learn a new language every year.&#8221; This idea has become so ubiquitous that it even has it&#8217;s own four-letter acronym, LOTY (Language of the Year).</p>
<p>Since establishing and reporting on these goals, I&#8217;ve had several things get in the way of fully realizing all of them. However, I can safely say that in the last two years I have mastered enough Groovy and Grails that they no longer fit in the LOTY category. At this point they&#8217;re really not showing my anything that is causing any paradigm shifts for me. They&#8217;re comfortable. When I learn a new feature, it just seems to make sense, and nothing surprises me anymore. Languages like these aren&#8217;t good LOTY candidates because one of the purposes of learning a LOTY is to challenge and change your ideas about programming. Groovy doesn&#8217;t do this for me anymore. It&#8217;s time to move on (not to say that I&#8217;m dropping Groovy and Grails as a tool &#8211; I&#8217;m using them more now than ever &#8211; they&#8217;re just not a learning tool for me anymore).</p>
<p>So, at this point I want to delve into a language that attempts to tackle the concurrent/multicore programming challenge. I&#8217;d like to stay on the JVM because I appreciate the benefits that it brings as a platform, so for now Erlang is out. The two leading candidates in the JVM/concurrent/multicore arena seem to be <a href="http://www.scala-lang.org/">Scala</a> and <a href="http://clojure.org/">Clojure</a>. An added benefit of both of these languages is that they support the functional paradigm, something I haven&#8217;t really played with since my computer science education days and a very interesting language named Haskell.</p>
<p>Scala is a multiparadigm language, supporting both object-oriented and functional constructs. It is statically typed, yet offers very nice type inference. Clojure, on the other hand, is a functional Lisp derivative with almost no OO constructs that is dynamically typed. Both are designed to enable concurrent programming. Which one do I choose? I open the floor for comments.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/113/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/113/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/113/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/113/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/113/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/113/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/113/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/113/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/113/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/113/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/113/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/113/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/113/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/113/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=113&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2009/04/02/loty-time-again-scala-or-clojure/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>
	</item>
		<item>
		<title>Deploying Grails with Groovy</title>
		<link>http://mattstine.com/2009/03/29/deploying-grails-with-groovy/</link>
		<comments>http://mattstine.com/2009/03/29/deploying-grails-with-groovy/#comments</comments>
		<pubDate>Sun, 29 Mar 2009 08:38:09 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[CodeProject]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=89</guid>
		<description><![CDATA[Interesting title, eh? Maybe this one will make it through Glen&#8217;s filter at GroovyBlogs.org. On to the meat. I&#8217;ve been steadily working on a couple of Grails applications, one being the website for the Memphis JUG, and another being the e-commerce site for my wife&#8217;s soon to be launched designer stationery business. Just like your [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=89&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Interesting title, eh? Maybe this one will make it through Glen&#8217;s filter at <a href="http://groovyblogs.org">GroovyBlogs.org</a>.</p>
<p>On to the meat. I&#8217;ve been steadily working on a couple of Grails applications, one being the website for the <a href="http://www.memphisjug.org">Memphis JUG</a>, and another being the e-commerce site for my wife&#8217;s soon to be launched designer stationery business. Just like your average Grails developer, I&#8217;ve been happily coding away at 127.0.0.1 using the good old development Jetty+MySQL stack. Well, in the last week or so it&#8217;s come time to actually deploy both of these applications into production. I started out last weekend with the Memphis JUG site. My first approach was to build the WAR file locally and then &#8220;scp&#8221; it up to the server.</p>
<p>YMMV, but the upload speed on my DSL connection is horrible! After doing this three or four times in one night, waiting 15-20 minutes for the WAR to upload each time (Grails WAR&#8217;s are rather thick when carrying all of the dependencies along), I decided to myself, &#8220;There must be a better way to do this.&#8221;</p>
<p>Fast forward a week and here I sit working on the first &#8220;pre-production&#8221; release of my wife&#8217;s store site. With quite a bit of time on my hands during these &#8220;dark and early&#8221; hours (a story for a later entry), I decided it was time for the experiment.</p>
<p>Each of these projects is hosted at GitHub, so the process that I mapped out in my mind looked like this:</p>
<ol>
<li>Check out the latest code from GitHub</li>
<li>Run &#8220;grails war&#8221;</li>
<li>Stop the Tomcat service (my hosting provider sets up Tomcat to run as a service)</li>
<li>Delete the remnants of the previous deployment from Tomcat&#8217;s deployment directory</li>
<li>Copy the new WAR file to Tomcat&#8217;s deployment directory</li>
<li>Start the Tomcat service</li>
</ol>
<p>By the way, I forgot to mention that before doing all of this I moved the production data source definition from being locally defined to being a JNDI lookup within Tomcat. This posed its own challenge, which I&#8217;ll blog about a bit later.</p>
<p>Anyway, back to the deployment. I though this would be an excellent opportunity to take <a href="http://groovy.codehaus.org/Using+Ant+from+Groovy">Groovy&#8217;s Antbuilder</a> out for a spin. Here&#8217;s an example of what I put together:</p>
<pre class="brush: groovy">
#!/usr/bin/env groovy

def ant = new AntBuilder()

//Update the codebase from GitHub
ant.exec(executable:'git', dir: "${PROJECT_DIR}") {
        arg(value:'pull')
}

//Generate the WAR file using Ant
ant.ant(dir:'"${PROJECT_DIR}"', target: 'war')

//Stop Tomcat
ant.exec(executable:'service') {
        arg(line:'tomcat6 stop')
}

//Delete the old webapp contents from Tomcat's deploy directory
ant.delete(includeemptydirs:'true', verbose:'true') {
        fileset(dir:"${CONTEXT_ROOT_DIR}", includes:'**/*')
}

//Copy the new WAR file to Tomcat's deploy directory
ant.copy(file:"${WAR_FILE}", tofile:"${CONTEXT_ROOT_DIR}/ROOT.war")

//Start Tomcat
ant.exec(executable:'service') {
        arg(line:'tomcat6 start')
}
</pre>
<p>As you can see, I have a few undefined Groovy constants in there. Let&#8217;s just say I didn&#8217;t want to expose ALL of the details of my server.</p>
<p>At any rate, it&#8217;s pretty simple. One word of warning &#8211; if you&#8217;re using Ehcache, make sure to add it to your ivy.xml dependencies, or the Ant build won&#8217;t bring it in like running &#8220;grails war&#8221; will. I hope someone finds this simple script useful. Enjoy!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/89/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/89/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/89/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/89/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/89/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/89/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/89/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/89/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/89/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/89/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/89/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/89/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/89/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/89/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=89&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2009/03/29/deploying-grails-with-groovy/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>
	</item>
		<item>
		<title>Need a Textile engine? Look no further than Plextile!</title>
		<link>http://mattstine.com/2009/03/26/need-a-textile-engine-look-no-further-than-plextile/</link>
		<comments>http://mattstine.com/2009/03/26/need-a-textile-engine-look-no-further-than-plextile/#comments</comments>
		<pubDate>Thu, 26 Mar 2009 21:23:46 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[CodeProject]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[textile]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=81</guid>
		<description><![CDATA[In finishing up the first release of JUG Nexus, the open source engine (http://github.com/mstine/jug-nexus/tree/master) behind the new Memphis JUG website, I needed to put a good Textile engine in place. I really don&#8217;t care for writing actual HTML in a content management system, and JUG Nexus being a lightweight CMS, I wanted a lightweight markup [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=81&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In finishing up the first release of JUG Nexus, the open source engine (<a href="http://github.com/mstine/jug-nexus/tree/master">http://github.com/mstine/jug-nexus/tree/master</a>) behind the new Memphis JUG website, I needed to put a good <a href="http://www.textism.com/tools/textile/">Textile</a> engine in place. I really don&#8217;t care for writing actual HTML in a content management system, and JUG Nexus being a lightweight CMS, I wanted a lightweight markup syntax for entering the details of upcoming JUG meetings. Textile is exactly that, and is also used for entering content into the very useful <a href="http://jugevents.org">JUGEvents</a> system produced by <a href="http://www.jugpadova.it/">JUG Padova</a> for the Java User Group community at large. I tried out several different engines, and none of them seemed to be very robust when it came to edge cases in the markup. For example, if I want to produce a hyperlink to a website, the textile format is the following:</p>
<p><code><br />
"Linked Text":http://www.site.com<br />
</code></p>
<p>This syntax will result in the following HTML:</p>
<pre class="brush: xml">
&lt;a href="http://www.site.com"&gt;Linked Text&lt;/a&gt;
</pre>
<p>Unfortunately, if you have a bang (!) in your &#8220;Linked Text,&#8221; most of the Textile engines that I used would not recognize it as an HTML link. Plextile does!</p>
<p>The only drawback, however minimal, to using Plextile is that it does not come with a pre-packaged JAR file. You have to take the compiled code and JAR it yourself. Now, for free, I&#8217;ll include how I integrated Plextile with Grails. Grails has a very nice codec feature that provides a facility to register encoders and decoders of textual data as methods on any object. Grails searches for classes following the convention <code>XCodec</code> and dynamically registers <code>encodeAsX</code> and <code>decodeX</code> methods on <code>java.lang.Object</code> so that any data can be encoded and decoded. Enter the <code>TextileCodec</code>:</p>
<pre class="brush: groovy">
import com.plink.plextile.TextParser

class TextileCodec {

   static encode = {str -&gt;
      new TextParser().parseTextile(str, true)
   }

}
</pre>
<p>Believe it or not, that&#8217;s it! Here&#8217;s the GSP template for rendering a JUG meeting:</p>
<pre class="brush: xml">
&lt;div class="post"&gt;
  &lt;h2&gt;${event.title}&lt;br/&gt;&lt;br/&gt;&lt;g:formatDate format="EEEE, MMMM dd, yyyy" date="${event.startTime}"/&gt;&lt;br/&gt;&lt;g:formatDate format="h:mm" date="${event.startTime}"/&gt;-&lt;g:formatDate format="h:mm a" date="${event.endTime}"/&gt;&lt;br/&gt;&lt;g:if test="${!event.archived}"&gt;&lt;a href="http://jugevents.org/jugevents/event/${event.jugEventsId}"&gt;Click HERE to register!&lt;/a&gt;&lt;/g:if&gt;&lt;/h2&gt;
  &lt;div class="entry"&gt;
    &lt;h2 class="title"&gt;Speaker/Topic:&lt;/h2&gt;
    &lt;p&gt;${event.description.encodeAsTextile()}&lt;/p&gt;
    &lt;h2 class="title"&gt;Location/Directions:&lt;/h2&gt;
    &lt;p&gt;${event.location}&lt;/p&gt;
    &lt;p&gt;${event.directions.encodeAsTextile()}&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
</pre>
<p>Enjoy!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/81/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=81&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2009/03/26/need-a-textile-engine-look-no-further-than-plextile/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>
	</item>
		<item>
		<title>Grails 1.0 Released!</title>
		<link>http://mattstine.com/2008/02/05/grails-10-released/</link>
		<comments>http://mattstine.com/2008/02/05/grails-10-released/#comments</comments>
		<pubDate>Tue, 05 Feb 2008 15:48:00 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=59</guid>
		<description><![CDATA[Grails, by far my favorite of the JVM dynamic language frameworks, was released this morning, with a snazzy, new, &#8220;Web 2.0 style&#8221; website to boot. Congratulations Graeme and company on all of your hard work!<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=59&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://grails.org/Home">Grails</a>, by far my favorite of the JVM dynamic language frameworks, was released this morning, with a snazzy, new, &#8220;Web 2.0 style&#8221; website to boot. Congratulations Graeme and company on all of your hard work!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/mattstine.wordpress.com/59/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/mattstine.wordpress.com/59/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/59/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=59&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2008/02/05/grails-10-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>
	</item>
		<item>
		<title>And then it was over&#8230;</title>
		<link>http://mattstine.com/2007/05/11/and-then-it-was-over/</link>
		<comments>http://mattstine.com/2007/05/11/and-then-it-was-over/#comments</comments>
		<pubDate>Sat, 12 May 2007 03:57:00 +0000</pubDate>
		<dc:creator>mattstine</dc:creator>
				<category><![CDATA[DSL]]></category>
		<category><![CDATA[EJB3]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://www.mattstine.com/?p=33</guid>
		<description><![CDATA[I really enjoyed &#8220;The Toy Show&#8221; this morning. James Gosling went through a flurry of different demos from around the &#8220;cool&#8221; Java world. I was especially impressed with Project Wonderland (http://lg3d-wonderland.dev.java.net/), a virtual workplace environment, and with the real-time robotics demos. Unfortunately I was so sucked in that I didn&#8217;t get any good photos. If [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=33&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://picasaweb.google.com/matt.stine/SanFranciscoJavaOne2007/photo#5063512122879158706"><img src="http://lh4.google.com/image/matt.stine/RkU1crgYqbI/AAAAAAAAAOI/fn4ypOF5zkQ/s288/DSCN1138.JPG" /></a></p>
<p>I really enjoyed &#8220;The Toy Show&#8221; this morning. James Gosling went through a flurry of different demos from around the &#8220;cool&#8221; Java world. I was especially impressed with Project Wonderland (http://lg3d-wonderland.dev.java.net/), a virtual workplace environment, and with the real-time robotics demos. Unfortunately I was so sucked in that I didn&#8217;t get any good photos.</p>
<p>If anything you could call this my day on the back end. I attended four sessions, two of which were focused on that.</p>
<p>- Comparing the Developer Experience of Java EE 5.0, Ruby on Rails, and Grails: Lessons Learned from Developing One Application<br />- Implementing Java EE Applications Using Enterprise JavaBeans (EJB) 3 Technology: Real-World Tips, Tricks, and New Design Patterns<br />- The Top 10 Ways to Botch Enterprise Java Technology-Based Application Scalability and Reliability<br />- Exploting JRuby: Building Domain-Specific Languages for the Java Virtual Machine</p>
<p>I scheduled the first session because I thought it was be a good way to tie together all that I had learned about Grails and Rails and then compare it to my existing Java EE knowledge. As it turns out, the speaker believed that given tool support, the development experience wasn&#8217;t all that different between the three. He then gave some performance comparisons, but I wasn&#8217;t all that sure the analysis was very sound. Java EE came out way on top. I hadn&#8217;t heard that it outperformed the others by quite as much as he showed. He made a rather dubious statement when he said that Grails and Rails weren&#8217;t protected by standards. Groovy is a JSR and Grails just sits on top of it. If that isn&#8217;t standard protection, then what is?</p>
<p>The EJB tips, tricks, and patterns session was quite nice. I learned a few nuances of the platform. The patterns part was the best. They first went through some of the design patterns from the EJB 2.x days and identified which ones were obsolete and which ones were still useful. They then provided several new design patterns. Unfortunately the slides for this talk were not yet available and I just don&#8217;t feel like combing through my handwritten notes. Definitely check this one out online when it is posted.</p>
<p>Cameron Purdy&#8217;s &#8220;Top 10&#8243; talk was both humorous and thought-provoking. I&#8217;ll never do justice to it. Check it out when the video comes available.</p>
<p>The final session of the conference for me addressed a burning question I had in my mind since Monday &#8211; what in the world is a DSL? I heard it thrown around in the Grails and Ruby talks at Java University, but nobody ever defined the acronym. Domain Specific Language &#8211; that what it is! I mainly attended this talk because I thought there might be applications for DSL&#8217;s in our work at St. Jude. A DSL is a custom language designed for a specific purpose. Ruby&#8217;s Rake language for instrumenting application builds is an example. Rob Harrop gave an impressive demo of how he built two DSL&#8217;s, one providing a simpler API for JMX, and another for corporate action entitlement calculations. While I can&#8217;t think of a direct application for DSL&#8217;s yet, I&#8217;m not tossing out the possibility.</p>
<p>JavaOne was a great conference for me. If I didn&#8217;t hate to leave my family for this long, I&#8217;d love to attend every year. It&#8217;s definitely drinking from a fire hydrant.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/mattstine.wordpress.com/33/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/mattstine.wordpress.com/33/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mattstine.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mattstine.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mattstine.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mattstine.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mattstine.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mattstine.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mattstine.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mattstine.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mattstine.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mattstine.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mattstine.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mattstine.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mattstine.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mattstine.wordpress.com/33/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mattstine.com&amp;blog=58954&amp;post=33&amp;subd=mattstine&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mattstine.com/2007/05/11/and-then-it-was-over/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1eaa45fee6a2b0c4b479b2982a4274f4?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mattstine</media:title>
		</media:content>

		<media:content url="http://lh4.google.com/image/matt.stine/RkU1crgYqbI/AAAAAAAAAOI/fn4ypOF5zkQ/s288/DSCN1138.JPG" medium="image" />
	</item>
	</channel>
</rss>
