<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;C04NQHc6eip7ImA9WhRbEkQ.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670</id><updated>2012-02-03T11:59:51.912-06:00</updated><category term="pci pa/dss hints tips audit" /><category term="scala" /><category term="Book review SQL Antipatterns" /><category term="shutterfly holiday cards" /><category term="java" /><category term="clojure" /><category term="Groovy HTTPBuilder RESTClient" /><category term="grails groovy databinding" /><category term="Groovy html MarkupBuilder" /><category term="JMS ExceptionListener Java" /><category term="Book review Gradle Groovy" /><category term="concurrency" /><category term="Groovy" /><category term="Grails Groovy Spring databinding" /><category term="Gradle groovy nonversioned jars" /><category term="Groovy sockets serversocket client" /><category term="Grails AJAX groovy" /><category term="Groovy CliBuilder ConfigSlurper" /><category term="book review" /><category term="webstart web start jnlp javaws_vm_args" /><category term="blogger template" /><category term="Groovy gotcha databasemetadata array initialization" /><category term="Groovy GString SQL" /><category term="Groovy Binding script" /><category term="Ant" /><category term="Web Start JNLP code signing certificates Groovy" /><category term="initial" /><category term="Groovy Java Ant Validator" /><title>Scratching my programming itch</title><subtitle type="html">Hints and tips learned while scratching my programming itch.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://programmingitch.blogspot.com/" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ScratchingMyProgrammingItch" /><feedburner:info uri="scratchingmyprogrammingitch" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;Ak4BR309cCp7ImA9WhRUGUo.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-8435450208431433389</id><published>2012-01-30T21:02:00.002-06:00</published><updated>2012-01-30T21:02:36.368-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-30T21:02:36.368-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="book review" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><category scheme="http://www.blogger.com/atom/ns#" term="Groovy" /><category scheme="http://www.blogger.com/atom/ns#" term="scala" /><category scheme="http://www.blogger.com/atom/ns#" term="concurrency" /><title>Book Review: Programming Concurrency on the JVM</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/df3cDkmpRi9BHcDRrCKWE9A8vTk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/df3cDkmpRi9BHcDRrCKWE9A8vTk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/df3cDkmpRi9BHcDRrCKWE9A8vTk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/df3cDkmpRi9BHcDRrCKWE9A8vTk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-V999R5VE8d0/TxOoIcBwgQI/AAAAAAAAAac/sxOUDJM2T6c/s1600/concurrency.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-V999R5VE8d0/TxOoIcBwgQI/AAAAAAAAAac/sxOUDJM2T6c/s320/concurrency.jpg" width="260" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Overview&lt;/b&gt;&lt;br /&gt;
Programming concurrency is a tough task to get right, just ask Venkat, he'll tell you so! &amp;nbsp;I attended a presentation by Dr. Venkat Subramaniam on this very subject, Concurrency on the JVM, at my local Java user group a couple months ago and he really caught my attention. &amp;nbsp;The presentation was a condensed version of the book, and needless to say, I bought the book to help fill in all the details. &lt;br /&gt;
&lt;br /&gt;
Not only is Venkat a 'subject matter expert', &amp;nbsp;but his presentation kept everyone engaged and laughing!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Contents:&lt;/b&gt;&lt;br /&gt;
The book is broken down in 5 parts, with 10 chapters total, at just over 250 pages. &amp;nbsp;The main sections of the book are:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;Strategies for Concurrency&lt;/i&gt; - this discusses the impact of multi-core machines and the three design approaches that are discussed throughout the rest of the book, &lt;i&gt;Shared Mutability&lt;/i&gt;, &lt;i&gt;Isolated Mutability&lt;/i&gt; and &lt;i&gt;Pure Immutability.&lt;/i&gt;&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;&lt;i&gt;Modern Java/JDK Concurrency - &lt;/i&gt;covers the Java 1.5+ concurrency features and talks about how to use the newer concurrency classes, like ExecutorService, CountDownLatch, Locks and Fork/Join to solve concurrency problems.&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;&lt;i&gt;Software Transactional Memory - &lt;/i&gt;covers Software Transactional Memory (STM), popularized by Clojure, which places access to memory within transactions. &amp;nbsp;STM is one option for getting away from the 'Synchronize and Suffer' model as Venkat call it. &amp;nbsp;The intention is to make threaded code more deterministic. &amp;nbsp; Using the JDK concurrency tools, there is no way to be sure you code is correct because it doesn't always fail when/where you need it to. &amp;nbsp; By putting the memory access inside transactions, the transaction manager helps resolve the conflicts without explicit locking.&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;&lt;i&gt;Actor-based Concurrency - &lt;/i&gt;covers actor design approaches as another option for concurrency design without using synchronization. &amp;nbsp;This section exercises actors from the Akka library from Scala, Actors from the Groovy library GPars, and mixing Actors and STM as a possible solution.&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;&lt;i&gt;Epilogue - &lt;/i&gt;is a short recap of the topics presented previously and points out the scenarios when each of the solutions would be appropriate.&lt;/li&gt;
&lt;/ul&gt;
The book lays out a couple example problems and then develops solutions for these problems across a range of JVM languages (Java, Groovy, Scala, Clojure and JRuby). &amp;nbsp; The examples are short and concise, &amp;nbsp;&amp;nbsp;enough to help you to get started prototyping against your own concurrency issues.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;
This is a good book to get you started on some of these &lt;b&gt;newer&lt;/b&gt;&amp;nbsp;concurrency concepts and libraries. &amp;nbsp;It was&amp;nbsp;an easy read, and I completed the reading fairly quickly, as opposed to the&amp;nbsp;"Java Concurrency in Practice" book, which I started and stopped twice and still have not completed yet! &lt;br /&gt;
&lt;br /&gt;
I would recommend this book to anyone looking to improve their programming skills in the concurrency area. &amp;nbsp;The book provides you with some alternatives to the old standby of '
Synchronize&amp;nbsp;and Suffer' model.&lt;br /&gt;
My last recommendation, if you get the opportunity, attend one of Venkat's presentations, you won't be sorry!&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-8435450208431433389?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/LHN9ug-vR1E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/8435450208431433389/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2012/01/book-review-programming-concurrency-on.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/8435450208431433389?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/8435450208431433389?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/LHN9ug-vR1E/book-review-programming-concurrency-on.html" title="Book Review: Programming Concurrency on the JVM" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-V999R5VE8d0/TxOoIcBwgQI/AAAAAAAAAac/sxOUDJM2T6c/s72-c/concurrency.jpg" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2012/01/book-review-programming-concurrency-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUAR38yeyp7ImA9WhRUEE4.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-1223999122839282905</id><published>2012-01-19T22:03:00.001-06:00</published><updated>2012-01-19T22:04:06.193-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-19T22:04:06.193-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groovy Binding script" /><title>Passing parameters into Groovy script using Binding class</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/68Dhk6fDgfro_Lff90dlMkJsoUQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/68Dhk6fDgfro_Lff90dlMkJsoUQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/68Dhk6fDgfro_Lff90dlMkJsoUQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/68Dhk6fDgfro_Lff90dlMkJsoUQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;I recently saw a question posted on the Groovy/Grails group on LinkedIn asking about ways to pass in parameters to a Groovy script. &amp;nbsp;There were several responses pointing to the &lt;a href="http://groovy.codehaus.org/gapi/groovy/util/CliBuilder.html"&gt;CliBuilder&lt;/a&gt; class which is certainly one way to handle the problem. &amp;nbsp; I had just finished reading an article by &lt;a href="http://kousenit.wordpress.com/"&gt;Ken Kousen&lt;/a&gt; in the November issue of &lt;a href="http://groovymag.com/"&gt;GroovyMag&amp;nbsp;&lt;/a&gt;&amp;nbsp;where Ken mentioned another option: using the Binding class.&lt;br /&gt;
&lt;br /&gt;
The example below shows a couple ways of setting variables in the binding, getting the variable values from the binding and how to capture standard output from the script. &amp;nbsp;The one tricky part is the question "&lt;a href="http://groovy.codehaus.org/Scoping+and+the+Semantics+of+%22def%22"&gt;When is something in the Binding and when not?&lt;/a&gt;" &amp;nbsp;The answer is: when it's not defined, it is in the binding! &amp;nbsp;In the example below, variable &lt;b&gt;c&lt;/b&gt; is placed in the binding, but since it is def'd in the script, the value for that variable comes from the local variable rather than the binding.&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;// setup binding
def binding = new Binding()
binding.a = 1
binding.setVariable('b', 2)
binding.c = 3
println binding.variables

// setup to capture standard out
def content = new StringWriter()
binding.out = new PrintWriter(content)

// evaluate the script
def ret = new GroovyShell(binding).evaluate('''
def c = 9
println 'a='+a
println 'b='+b
println 'c='+c 
retVal = a+b+c
a=3
b=2
c=1
''')

// validate the values
assert binding.a == 3
assert binding.getVariable('b') == 2
assert binding.c == 3 // binding does NOT apply to def'd variable
assert binding.retVal == 12 // local def of c applied NOT the binding!

println 'retVal='+binding.retVal
println binding.variables
println content.toString()
&lt;/pre&gt;
Output
&lt;br /&gt;
&lt;pre class="brush:plain"&gt;[a:1, b:2, c:3]
retVal=12
[a:3, b:2, c:3, out:java.io.PrintWriter@1e0799a, retVal:12]
a=1
b=2
c=9
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Hope this helps!
&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-1223999122839282905?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/GJqTkHU4Hyc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/1223999122839282905/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2012/01/passing-parameters-into-groovy-script.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/1223999122839282905?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/1223999122839282905?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/GJqTkHU4Hyc/passing-parameters-into-groovy-script.html" title="Passing parameters into Groovy script using Binding class" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2012/01/passing-parameters-into-groovy-script.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cHQ3c5fSp7ImA9WhRVGEs.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-3243788947347655605</id><published>2012-01-17T22:30:00.001-06:00</published><updated>2012-01-17T22:30:32.925-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-17T22:30:32.925-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Book review SQL Antipatterns" /><title>Book Review: SQL Antipatterns Avoiding the Pitfalls of Database Programming</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/pYwC6h8Tg9VY-9Wv4GMpPX1oTf4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pYwC6h8Tg9VY-9Wv4GMpPX1oTf4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/pYwC6h8Tg9VY-9Wv4GMpPX1oTf4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pYwC6h8Tg9VY-9Wv4GMpPX1oTf4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-pmIBBDZjDAA/TxOYhn1iqjI/AAAAAAAAAaU/0W_1Oi9kPtU/s1600/sql_antipatterns.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://1.bp.blogspot.com/-pmIBBDZjDAA/TxOYhn1iqjI/AAAAAAAAAaU/0W_1Oi9kPtU/s200/sql_antipatterns.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Overview&lt;/b&gt;&lt;br /&gt;
This is book for software developers that are either new to database programming (SQL) or those that may not have had any formal database education and may have learned &lt;i&gt;'on-the-job&lt;/i&gt;'. &lt;br /&gt;
&lt;br /&gt;
The book is bit longer, approximately 300 pages, than some of the other titles I've read from &lt;i&gt;The Pragmatic Programmers&lt;/i&gt; shelf, but it is a very easy read. &amp;nbsp;The chapters all follow a similar format: &lt;i&gt;Object&lt;/i&gt;, &lt;i&gt;Antipattern&lt;/i&gt;, &lt;i&gt;How to Recognize the Antipattern, Legitimate Uses of the Antipattern &lt;/i&gt;and &lt;i&gt;Solution.&lt;/i&gt;&amp;nbsp; Each chapter the author leads you through a problem that needs correcting within the scope of the database. &amp;nbsp; Next the antipattern is laid out for you and the author shows the disadvantages of using the antipattern. &amp;nbsp; Tips are provided to help identify the antipattern and he also suggests some possible legitimate uses of the antipattern. &amp;nbsp;Finally, the author describes better solutions to the problem presented; ones without the disadvantages discussed previously and solutions that are considered 'best practices' and that will provide better database performance.&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;Contents&lt;/b&gt;&lt;br /&gt;
The book is broken down into 4 main sections:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Logical Database Design Antipatterns - planning database tables, columns and relationships&lt;/li&gt;
&lt;li&gt;Physical Database Design Antipatterns - defining tables, indexes and choosing &amp;nbsp;datatypes&lt;/li&gt;
&lt;li&gt;Query Antipatterns - SQL command usage, for example, &lt;i&gt;SELECT&lt;/i&gt;, &lt;i&gt;UPDATE &lt;/i&gt;and &lt;i&gt;DELETE&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Application Development Antipatterns - correct usage within the scope of a language&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Some of that antipatterns described may make you laugh and wonder, "Who the heck would do something like that?" while others you may have run into previously and some might even hit very close to home from your work or personal projects.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
There is also an appendix that covers the &lt;i&gt;Rules of Normalization. &amp;nbsp;&lt;/i&gt;I&amp;nbsp;had heard of terms like&amp;nbsp;&lt;i&gt;Normalization, First Normal Form,&amp;nbsp;&lt;/i&gt;and&amp;nbsp;&lt;i&gt;Second&amp;nbsp;Normal Form &lt;/i&gt;before, but never actually read any explanations. The appendix includes discussions on normalization and first normal form through fifth normal form with examples to help clarify the topics.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;
This is a very good book for software developers just starting to 'cut their teeth' with databases and SQL. &amp;nbsp;It also serves as a good refresher for those with a bit more database experience. &amp;nbsp;In my case, I fall into the later scenario. &amp;nbsp;You can view it as a book of short stories, showing what &lt;b&gt;not &lt;/b&gt;to do in these cases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-3243788947347655605?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/Y4vZJRJdw0Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/3243788947347655605/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2012/01/book-review-sql-antipatterns-avoiding.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/3243788947347655605?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/3243788947347655605?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/Y4vZJRJdw0Y/book-review-sql-antipatterns-avoiding.html" title="Book Review: SQL Antipatterns Avoiding the Pitfalls of Database Programming" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-pmIBBDZjDAA/TxOYhn1iqjI/AAAAAAAAAaU/0W_1Oi9kPtU/s72-c/sql_antipatterns.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2012/01/book-review-sql-antipatterns-avoiding.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEHQ3s7fyp7ImA9WhdaFkg.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-7910933935640915590</id><published>2011-10-26T13:27:00.001-05:00</published><updated>2011-10-26T13:27:12.507-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-26T13:27:12.507-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Web Start JNLP code signing certificates Groovy" /><title>Jars signed with mutliple code signing certificates?</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/AvlKcx9lEgKO_-apm6uS9BC51hE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AvlKcx9lEgKO_-apm6uS9BC51hE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/AvlKcx9lEgKO_-apm6uS9BC51hE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AvlKcx9lEgKO_-apm6uS9BC51hE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;span class="Apple-style-span"&gt;For anyone that has built and maintained &lt;a href="http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136112.html"&gt;Web Start&lt;/a&gt; applications, you have probably been through this issue before. &amp;nbsp; Your QA group or worse yet, a customer, calls to tell you that they cannot start your application because the download failed because "&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: white; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px;"&gt;jar resources in jnlp are not signed by the same certificate&lt;/span&gt;&lt;span class="Apple-style-span"&gt;".&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
If want your Web Start application to have full access permissions, then you need to sign all the jars that get downloaded. &amp;nbsp;This generally presents the opportunity to encounter one of the following errors:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;None of the jars are signed. &amp;nbsp;Most likely a build issue and generally only happens once, (I hope!)&lt;/li&gt;
&lt;li&gt;Single jar &lt;x&gt; is not signed. &amp;nbsp;Again, most likely either a build or process error.&lt;/x&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/430755/jar-resources-in-jnlp-are-not-signed-by-the-same-certificate"&gt;Not all jars signed with the same certificate&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
The first two are easy to resolve. &amp;nbsp;The last is a bit of a pain because Web Start doesn't bother to tell you exactly which jars where signed with different code signing certificates. &amp;nbsp;Now, it's time to make some educated guesses as to what changed recently and look at the most likely/usual suspects. &amp;nbsp; Another option is to get the list of download jars from the JNLP document and figure out which certificates(s) each jar has been signed with.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
We have been through this at work once or twice and so I finally decided to make it easier for the next time this happens. &amp;nbsp; The approach I took was to read all the jars in a deployment folder, open them and look for the signature files inside the jar file. &amp;nbsp; For the results, I created a map keyed by the jar name and the value being a list of the signature file names (*.RSA, where the * represents our code signing certificate alias). &amp;nbsp;Keeping a list in the map allows for cases where a jar may have multiple signature files, which was encountered when we switched over code signing certificates. &amp;nbsp;Writing this in Java would be possible, &lt;b&gt;but why write so much code&lt;/b&gt;? &lt;b&gt;Why not write a script in Groovy&lt;/b&gt;, it would be some much shorter and concise.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;b&gt;Groovy Script&lt;/b&gt;&lt;/div&gt;
&lt;pre class="brush:groovy"&gt;def dir = new File("C:\\MyDeployment\\jboss\\myserver\\deploy\\myserver.ear")
def jars = dir.list( { d, f-&amp;gt; f ==~ /.*.jar/ } as FilenameFilter)
def map = [:]
jars.each() {
   def zipFile = new java.util.zip.ZipFile(new File(dir, it)) 
   zipFile.entries().each { zipEntry -&amp;gt;
      if (zipEntry.name.endsWith('.RSA')) {
          if (map.containsKey(it)) {
             def list = map[it]
             list &amp;lt;&amp;lt; zipEntry.name
          } else {
             map[it] = [zipEntry.name]
          }
      }
   }  
}
map.each{ println it}
&lt;/pre&gt;
&lt;pre class="brush:groovy"&gt;
&lt;/pre&gt;
&lt;b&gt;&lt;i&gt;Hope this helps!
&lt;/i&gt;&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-7910933935640915590?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/IUyJq1m2yaw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/7910933935640915590/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2011/10/jars-signed-with-mutliple-code-signing.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/7910933935640915590?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/7910933935640915590?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/IUyJq1m2yaw/jars-signed-with-mutliple-code-signing.html" title="Jars signed with mutliple code signing certificates?" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2011/10/jars-signed-with-mutliple-code-signing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEDRnY7cCp7ImA9WhdUE04.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-1474717991318796275</id><published>2011-09-29T16:11:00.000-05:00</published><updated>2011-09-29T16:11:17.808-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-29T16:11:17.808-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="pci pa/dss hints tips audit" /><title>Lessons learned from recent PA/DSS audit</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/q3zPjpdC4_9CKB-EF9X0J1xsqbU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/q3zPjpdC4_9CKB-EF9X0J1xsqbU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/q3zPjpdC4_9CKB-EF9X0J1xsqbU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/q3zPjpdC4_9CKB-EF9X0J1xsqbU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;The following are some tips/hints and lessons learned during our recent PA/DSS audit. &amp;nbsp; Everyone's mileage will vary.&amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
Our application runs on both Windows and Linux.&amp;nbsp;&amp;nbsp; We support JBoss and Weblogic for the application server.&amp;nbsp; We support Oracle, SQL Server and&amp;nbsp; MySQL for the database.&amp;nbsp; We have three client applications which are all WebStart clients, so this is NOT a web application.&amp;nbsp; Our EJBs are EJB 2.1 Session Beans.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;Hints&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Determine exact software stacks needed including all software levels, build levels and whatever else you need.&amp;nbsp; Collect all of this in one safe place.&lt;/li&gt;
&lt;li&gt;Get the hardware ready and any scripts that may be needed to use those devices.&amp;nbsp; Our application is a POS, so we had a collection of pin pads that we were required to test with during the audit.&lt;/li&gt;
&lt;li&gt;Get any utility software needed&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Ghost for Win* images (or Win 7 provides a Backup/Restore feature)&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;We ran into some problems with Windows Server 2008 and had to use one of the&amp;nbsp; &lt;a href="http://www.acronis.com/"&gt;Acronis &lt;/a&gt;tools to create the backup image.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;PartImage for Linux images&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.dban.org/"&gt;Darik's Boot and Nuke &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;anything else you might need&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Wipe the hard drives before loading any software, including the OS, using Darik's Boot and Nuke to be absolutely sure that the drive does contain anything that might match a credit/debit card number.&lt;/li&gt;
&lt;li&gt;Install the OS and any 'base' software, which isn't the software to be verified by the audit&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Keep the partition sizes as small as possible without causing disk output problems.&amp;nbsp; The larger the disk, the longer the forensic scans will take to run.&lt;/li&gt;
&lt;li&gt;On Windows - you can have a page file, just don't allow it to grow and shrink.&amp;nbsp;&amp;nbsp; Set the min and max file size to the same value.&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Problem here is that if card holder data is written to the page file then later the page file size is shrunk, some of that card holder data MAY be inside freespace, which is NOT cleaned up by the OS.&amp;nbsp;&amp;nbsp; This can cause some instances of card holder data to be found during a forensic scan and NO ONE wants card holder data found during the scans.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;On Window - you should also set the Windows Update setting to be Notification because you don't want Windows Updates being applied to a machine during the audit.&lt;/li&gt;
&lt;li&gt; Our auditor also recommended we turn off the Windows Restore points.&amp;nbsp; Again, you don't want Windows doing any extra work that could impact the audit results.&lt;/li&gt;
&lt;ul&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;li&gt;Take images of all boxes.&amp;nbsp; These may be needed to reset a machine back to a 'clean' state for ad additional set of tests.&lt;/li&gt;
&lt;li&gt;Talk to each of your authorization providers&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;let them know when your audit is scheduled and ensure you will have connectivity to their test servers&lt;/li&gt;
&lt;li&gt;Verify that each provider can supply 'magic authorization values' that will help your trigger the following responses:&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;approvals&lt;/li&gt;
&lt;li&gt;declines&lt;/li&gt;
&lt;li&gt;referrals&lt;/li&gt;
&lt;li&gt;timeouts&lt;/li&gt;
&lt;li&gt;void&lt;/li&gt;
&lt;li&gt;split tenders&lt;/li&gt;
&lt;li&gt;partial auths&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;If any of the authorization providers encrypt their communications, then you may need to ensure you have whatever is needed for that. &amp;nbsp; We needed to download and install the&lt;a href="http://download.oracle.com/javase/1,5.0/docs/guide/security/jce/JCERefGuide.html"&gt; JCE &lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you support multiple authorization providers, you will have to run tests against each provider so be ready to do whatever it takes to switch your application from one provider to the next.&lt;/li&gt;
&lt;ul&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;li&gt;Practice taking images and restoring images on all boxes&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;The Linux tools are not as user friendly as the Windows tools, so you need to be ready and able to make and restore your images in a timely manner.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Now you can install your software and you should be ready for the audit.&lt;/li&gt;
&lt;li&gt;If you do any testing before the auditor arrives, be ready to restore the machines back to a 'clean' state because you don't want to take a chance that your early testing wrote any card holder data somewhere on the hard drive.&lt;/li&gt;
&lt;li&gt;Our auditor previously used &lt;a href="http://x-ways.net/winhex/"&gt;WinHex &lt;/a&gt;to do the forensic scans.&amp;nbsp; We used the evaluation version to try and double-check ourselves.&amp;nbsp; The problem with that version is that it is slow and can only scan for one card number at a time.&amp;nbsp; This time the auditor had a new set of software for the scans and unfortunately I didn't get the name of the package, although I know it was a purchased product.&lt;/li&gt;
&lt;/ul&gt;
Good luck - hope this helps! &lt;br /&gt;
&lt;ul&gt;
&lt;/ul&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-1474717991318796275?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/UsWzNMBiMSo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/1474717991318796275/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2011/09/lessons-learned-from-recent-padss-audit.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/1474717991318796275?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/1474717991318796275?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/UsWzNMBiMSo/lessons-learned-from-recent-padss-audit.html" title="Lessons learned from recent PA/DSS audit" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2011/09/lessons-learned-from-recent-padss-audit.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMBSHc5fyp7ImA9WhdSEUQ.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-3108571967228729039</id><published>2011-07-20T12:56:00.002-05:00</published><updated>2011-07-20T14:34:19.927-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-20T14:34:19.927-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Book review Gradle Groovy" /><title>Book Review: Building and Testing with Gradle</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/j8HvgdUPb1pHHESKeht8ZqL1XaA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/j8HvgdUPb1pHHESKeht8ZqL1XaA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/j8HvgdUPb1pHHESKeht8ZqL1XaA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/j8HvgdUPb1pHHESKeht8ZqL1XaA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-hEzief4kBQo/TicVdM50t7I/AAAAAAAAAZU/Y0Y2NOdJiXM/s1600/gradlebook.gif" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-hEzief4kBQo/TicVdM50t7I/AAAAAAAAAZU/Y0Y2NOdJiXM/s1600/gradlebook.gif" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Overview&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Gradle is one of the new "cool kids on the block". &amp;nbsp;It &amp;nbsp;is quickly gaining momentum as projects like Hibernate and Spring migrate their build processes over to Gradle. &amp;nbsp; Gradle can be considered the 3rd generation of Java build tools, with Ant and Maven representing the earlier generations.&lt;br /&gt;
&lt;br /&gt;
Gradle is built on top of Groovy, which provides the ability to define a Domain Specific Language (DSL). &amp;nbsp;In this case, the Gradle DSL provides a language tailored to the task of building code. &amp;nbsp;If the DSL does not provide exactly what you need, then you can extend the DSL using plug-ins. &amp;nbsp;It is possible to learn Gradle without knowing Groovy, but some initial knowledge of Groovy is beneficial.&lt;br /&gt;
&lt;br /&gt;
This &lt;a href="http://oreilly.com/catalog/0636920019909/"&gt;book &lt;/a&gt;is short (89 pages) . &amp;nbsp;It brings back memories of the O'Reilly "A Developer's Notebook" series.&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Contents&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;b&gt;Chapter 1, Hello Gradle&lt;/b&gt;&amp;nbsp; This chapter leads the reader thru the installation and configuration of Gradle and demonstrates the ubiquitous Hello World (build file) example.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Chapter 2, Gradle Tasks&lt;/b&gt;&amp;nbsp; This is the &amp;nbsp;best chapter in the book. &amp;nbsp;It drives home the concepts associated with a 'task' and how the tasks can be configured and customized. &amp;nbsp; &amp;nbsp;The most helpful &amp;nbsp;suggestion in the book is found in this chapter. &amp;nbsp;The &amp;nbsp;recommendation is that you read the &lt;a href="http://www.gradle.org/current/docs/dsl/index.html"&gt;Gradle DSL documentation&lt;/a&gt;. &amp;nbsp;I had previously read the Gradle Users Guide but was still a bit fuzzy on what &amp;nbsp;the properties and methods were and how they were used. . &amp;nbsp; Reading the DSL documentation provides the full picture. &amp;nbsp;It also &amp;nbsp;helps drive home &amp;nbsp;that you are working with a programming language/DSL and not a set of XML tags like Ant and Maven.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Chapter 3, Ant and Gradle&amp;nbsp;&lt;/b&gt;&amp;nbsp;This chapter compares and contrasts Ant and Gradle. &amp;nbsp;It also demonstrates that Gradle can run Ant tasks by importing an Ant build.xml or by using the Ant Builder that is part of the Groovy distribution.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Chapter 4, Maven and Gradle&lt;/b&gt;&amp;nbsp; This &amp;nbsp;is the longest chapter in the book comprising &amp;nbsp;about 25% of the book. &amp;nbsp;Like all of the Gradle documentation, this book re-assures the reader that any previous investment in Maven or Ivy will not be lost in a move to Gradle. &amp;nbsp; Gradle provides support for Ivy, Maven's Central repository and a local repository.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Chapter 5, Testing with Gradle&lt;/b&gt;&amp;nbsp; This chapter is a &amp;nbsp;good overview of using &amp;nbsp;JUnit , TestNG, Spock, Geb and EasyB. &amp;nbsp;Coverage of testing is a bit light given the title of this book.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Chapter 6, &amp;nbsp;Multiproject Builds&lt;/b&gt;&amp;nbsp; This chapter &amp;nbsp;does a nice job of taking a sample project and showing three different approaches to creating the project build structure. &amp;nbsp;The approaches shown are one master build file, project-specific build files and a hybrid approach. &amp;nbsp;While the sample projects are very small, they provide the reader a starting point to converting their own multiproject builds.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;This is an excellent book for getting started with Gradle. &amp;nbsp; There are plenty of working examples provided in the source code download package. &amp;nbsp; The authors do a very good job of explaining the concepts and presenting alternative ways of expressing the same options within the DSL.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;One minor issue is that matching up the downloaded source examples to the examples in the printed chapters is a bit of an exercise because they are not organized in a folder structure by chapter like many other books.&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp;&lt;/div&gt;&lt;div&gt;Initially the slim size of the book worried me as to it's ability to provide a depth of coverage of Gradle, but the authors stated in the Preface that "Future volumes will cover the Gradle plug-in ecosystem, how to extend Gradle with your own business logic and even more advanced topics." &amp;nbsp; &amp;nbsp;Sounds good to me, bring it on Tim and Matthew!&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-weight: bold;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-3108571967228729039?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/uVbJcLKW-Oo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/3108571967228729039/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2011/07/book-review-building-and-testing-with.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/3108571967228729039?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/3108571967228729039?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/uVbJcLKW-Oo/book-review-building-and-testing-with.html" title="Book Review: Building and Testing with Gradle" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-hEzief4kBQo/TicVdM50t7I/AAAAAAAAAZU/Y0Y2NOdJiXM/s72-c/gradlebook.gif" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2011/07/book-review-building-and-testing-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkEDQnk_fip7ImA9WhdTFkw.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-5976834143520873704</id><published>2011-07-13T23:44:00.000-05:00</published><updated>2011-07-13T23:44:33.746-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-13T23:44:33.746-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Gradle groovy nonversioned jars" /><title>Gradle dependencies with jars that have no version number</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Mc9YMmGXM2GVMUo0ahBCyHF8Px4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Mc9YMmGXM2GVMUo0ahBCyHF8Px4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Mc9YMmGXM2GVMUo0ahBCyHF8Px4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Mc9YMmGXM2GVMUo0ahBCyHF8Px4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;I have seen presentations and read blogs and articles on &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt;.  It sounds pretty good. &amp;nbsp;Gradle is gathering momentum as some of the major players in the open source community (&lt;a href="http://java.dzone.com/polls/switch-gradle-good-move"&gt;Hibernate&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="http://forum.springsource.org/showthread.php?94976-Spring-Security-now-built-with-Gradle"&gt;Spring Security&lt;/a&gt;&amp;nbsp;to name a few) have switched their builds over to using Gradle. &amp;nbsp;I figured it is time to give it a try.&lt;br /&gt;
&lt;br /&gt;
The project I work on is fairly old, pre-Maven I suspect. &amp;nbsp;The project is a multi-layer, multi-component Java project built using Ant. &amp;nbsp;The project does not use Maven or Ivy. &amp;nbsp;The project includes a folder that contains all of our dependent jars. These jars are committed to SVN and included as part of the project when it is checked out. This way we have all the dependencies we need to build the project. &amp;nbsp;We have quite a few dependent jars that do &lt;b&gt;not &lt;/b&gt;have version numbers in the jar name. &amp;nbsp;Examples include a copy of junit.jar and log4j.jar. &amp;nbsp;This all existed before I started working on the project, so I have no idea how it got that way - it just is. &amp;nbsp;And since it's not really broken, we haven't attempted to fix it!&lt;br /&gt;
&lt;br /&gt;
Not having version numbers in the jars is a minor inconvienence. &amp;nbsp;If you read the Gradle User Guide chapter on &lt;a href="http://www.gradle.org/current/docs/userguide/userguide_single.html#dependency_management"&gt;Dependency Management&lt;/a&gt;, they seems to push dependency management for jars with version numbers. &amp;nbsp;Most of the examples shown in the documentation and elsewhere declare the dependencies as seen in Example 34.1 in Dependency Management chapter. &amp;nbsp;Great, but what do I do if I don't have version numbered jars in my dependencies? &amp;nbsp;I did not believe the Gradle guys would leave me hanging... &amp;nbsp;And they didn't! &lt;br /&gt;
&lt;br /&gt;
I really wanted to figure out how to setup my classpath to include these jars without version numbers. &amp;nbsp;I figured out how to do this and started writing this blog. &amp;nbsp; Then as I re-read the Dependency Management chapter, I saw a clue that I must have blown right by the first time I read it. &amp;nbsp;The clue is in &lt;a href="http://www.gradle.org/current/docs/userguide/userguide_single.html#sec:how_to_declare_your_dependencies"&gt;Section 34.3.5 File dependencies&lt;/a&gt;. &amp;nbsp;You can use the &lt;a href="http://www.gradle.org/current/docs/javadoc/org/gradle/api/file/FileTree.html"&gt;FileTree&amp;nbsp;&lt;/a&gt;&amp;nbsp;to help define the classpath to include these non-versioned jars.&lt;br /&gt;
&lt;br /&gt;
I created a small project called GradleTest that did not use the standard Java plugin conventions for the source and resource files and has dependencies in the "libs" folder, none of which have version numbers in the jar names.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-AxYLiYeASZ4/Th5r_YDoJKI/AAAAAAAAAZE/kn1FMXimo0I/s1600/gradle_project_structure.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://3.bp.blogspot.com/-AxYLiYeASZ4/Th5r_YDoJKI/AAAAAAAAAZE/kn1FMXimo0I/s400/gradle_project_structure.PNG" width="367" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;I created two different options, which both seem to work. &amp;nbsp;The first is shown below. &amp;nbsp;This option handles the dependencies more specifically, assigning just the jars that are needed for either compile or runtime.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;apply plugin: 'java'

sourceCompatibility = 1.6
version = '1.0'

sourceSets {
    main {
        java {
            srcDir 'src'
        }
        resources {
            srcDir 'resources'
        }
        compileClasspath += fileTree(dir: './libs', includes: ['**/log4j.jar'])
        runtimeClasspath = classes + sourceSets.main.classes + fileTree(dir: './libs', includes: ['**/log4j.jar'])
        
    }
    test {
        java {
            srcDir 'test'
        }
        resources {
            srcDir 'testresources'
        }
        compileClasspath += fileTree(dir: './libs', includes: ['**/junit.jar'])
        runtimeClasspath += classes + fileTree(dir: './libs', includes: ['**/junit.jar', '**/log4j.jar']) 
        
    }
}

sourceSets.main.classesDir = new File("./build/classes")
sourceSets.test.classesDir = new File("./build/classes")
&lt;/pre&gt;&lt;br /&gt;
The second option looks very similiar to the first option, &amp;nbsp;but uses the &lt;b&gt;dependencies &lt;/b&gt;definition and it cheats by assigning all the jars in the "libs" folder to both the compile and runtime classpath, rather than just exactly what is needed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;apply plugin: 'java'

sourceCompatibility = 1.6
version = '1.0'

sourceSets {
    main {
        java {
            srcDir 'src'
        }
        resources {
            srcDir 'resources'
        }
        
    }
    test {
        java {
            srcDir 'test'
        }
        resources {
            srcDir 'testresources'
        }
        
    }
}

sourceSets.main.classesDir = new File("./build/classes")
sourceSets.test.classesDir = new File("./build/classes")

configurations {
    compile {
        description = 'compile classpath'
        transitive = true
    }
    runtime {
        extendsFrom compile
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    runtime fileTree(dir: 'libs', include: '*.jar')

}

&lt;/pre&gt;I am sure there are other, &amp;nbsp;possibly better or cleaner alternatives. &amp;nbsp;Please feel free to share improvements or other alternatives. &amp;nbsp; Hope this helps....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-5976834143520873704?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/A5stZETgDMg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/5976834143520873704/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2011/07/gradle-dependencies-with-jars-that-have.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5976834143520873704?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5976834143520873704?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/A5stZETgDMg/gradle-dependencies-with-jars-that-have.html" title="Gradle dependencies with jars that have no version number" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-AxYLiYeASZ4/Th5r_YDoJKI/AAAAAAAAAZE/kn1FMXimo0I/s72-c/gradle_project_structure.PNG" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2011/07/gradle-dependencies-with-jars-that-have.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkUCQXo4eyp7ImA9WhZWGU0.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-5858472154336806623</id><published>2011-05-19T22:06:00.001-05:00</published><updated>2011-05-20T09:04:20.433-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-20T09:04:20.433-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groovy gotcha databasemetadata array initialization" /><title>Groovy vs Java difference provides a WTF moment</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Fkt1F0niuMlf3D8_6dOr37AbLs4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Fkt1F0niuMlf3D8_6dOr37AbLs4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Fkt1F0niuMlf3D8_6dOr37AbLs4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Fkt1F0niuMlf3D8_6dOr37AbLs4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;We all (should) know that not ALL Java is valid Groovy, but if you don't spend you day working in Groovy, then sometimes you forget these differences.&amp;nbsp;&amp;nbsp; These 'gotchas' are &lt;a href="http://groovy.codehaus.org/Differences+from+Java"&gt;documented here&lt;/a&gt; but who reads this stuff, right?&amp;nbsp; :-)&lt;br /&gt;
&lt;br /&gt;
I wanted to get &lt;a href="http://download.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html"&gt;DatabaseMetadata &lt;/a&gt;for a database, specifically a list of table names, so I started with a copy of Java code that already did the same thing.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;Class.forName(jdbcDriver);
Connection con = DriverManager.getConnection(jdbcURL, "root", "root");
DatabaseMetaData dbmd = con.getMetaData();
String[] tableTypes = { "TABLE" };
ResultSet allTables = dbmd.getTables(null, null, null, tableTypes);
System.out.println("processing tables...");
while (allTables.next()) {
    String table_name = allTables.getString("TABLE_NAME");
    System.out.println("processing table"+table_name);
}
&lt;/pre&gt;&lt;br /&gt;
Should be simple, right - drop the semi-colons and look for other opportunities to shorten the code using Groovy. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;def db = Sql.newInstance('jdbc:mysql://127.0.0.1:3306/mydb', 'root', 'root', 'com.mysql.jdbc.Driver')
def metaData = db.getConnection().getMetaData()
println("Driver Name: " + metaData.getDriverName())
println("Database Product: " + metaData.getDatabaseProductName())
println("Driver Name: "+ metaData.getDriverName())
println("Driver Version: "+ metaData.getDriverVersion())
String[] tableTypes = { "TABLE" }
ResultSet allTables = metaData.getTables(null, null, null, tableTypes)
while (allTables.next()) {
    String table_name = allTables.getString("TABLE_NAME")
    println "processing table "+table_name
}
&lt;/pre&gt;&lt;br /&gt;
And it &lt;b&gt;almost &lt;/b&gt;worked! &amp;nbsp; The thing that threw me was that not only does the code compile, but it also returns correct values for some of the methods in the DatabaseMetadata, but when it came time to iterate across the table names, there were none. &amp;nbsp;Come on, I just ran almost the exact code in Java and it spit out all the table names in my database. &amp;nbsp;What the heck did I mess up this time?&lt;br /&gt;
&lt;br /&gt;
My error was the 3rd bullet on the list of gotchas from above - how NOT to initialize an array in Groovy...&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;String[] tableTypesJava = { "TABLE" }
String[] tableTypesGroovy = [ "TABLE" ]
println tableTypesJava.class
println tableTypesGroovy.class
assertEquals(tableTypesGroovy, tableTypesJava)  // this will fail!
&lt;/pre&gt;&lt;br /&gt;
Both variables say they are String[] but tableTypesJava is really closure when compiled in Groovy!  The fix to the Groovy code is to use the brackets when initializing the array and not the braces - basically the &lt;b&gt;tableTypesGroovy &lt;/b&gt;from above.  Guess it's time to RTFM...&lt;br /&gt;
&lt;br /&gt;
Hope this helps!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-5858472154336806623?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/Jdri0bcc1NU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/5858472154336806623/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2011/05/groovy-vs-java-difference-provides-wtf.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5858472154336806623?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5858472154336806623?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/Jdri0bcc1NU/groovy-vs-java-difference-provides-wtf.html" title="Groovy vs Java difference provides a WTF moment" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>5</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2011/05/groovy-vs-java-difference-provides-wtf.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IFRXs8cSp7ImA9Wx9VFU8.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-8296285648114948943</id><published>2011-01-31T21:02:00.001-06:00</published><updated>2011-01-31T21:05:14.579-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-31T21:05:14.579-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Grails AJAX groovy" /><title>Grails AJAX Examples</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/K2s80H-981Nxvv7pRfqBmbYYFEk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/K2s80H-981Nxvv7pRfqBmbYYFEk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/K2s80H-981Nxvv7pRfqBmbYYFEk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/K2s80H-981Nxvv7pRfqBmbYYFEk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;Early on, newcomers to Grails encounter a lack of working samples accompanying the framework.&amp;nbsp; Good places for examples and documentation include the &lt;a href="http://www.grails.org/doc/latest/"&gt;Grails documentation&lt;/a&gt; and bloggers.&lt;br /&gt;
&lt;br /&gt;
Ajax is one of the features with built-in support by Grails. &amp;nbsp; Once people get their "head around" the Grails basics, they generally want to move onto more interesting features like Ajax.&amp;nbsp; This usually requires scouring the web, looking for examples and/or reading the documentation fairly closely.&amp;nbsp;&amp;nbsp; I went through this process and figured that others might benefit from a set of short working ajax examples in Grails.&amp;nbsp; I have created a small application that demonstrates some of the Ajax features and provide the application for download to anyone interested. (see bottom for download information)&lt;br /&gt;
&lt;br /&gt;
The example application uses each of the following:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;FormRemote&lt;/li&gt;
&lt;li&gt;RemoteLink&lt;/li&gt;
&lt;li&gt;SubmitToRemote&lt;/li&gt;
&lt;li&gt;RemoteFunction&lt;/li&gt;
&lt;li&gt;RemoteField&lt;/li&gt;
&lt;/ul&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;&amp;nbsp;General Steps&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Pick your javascript library - prototype used in my example. Also shown is some Ajax event registration.&lt;/li&gt;
&lt;/ul&gt;&lt;pre class="brush:xml"&gt;&lt;g:javascript library="prototype"&gt;&lt;/g:javascript&gt;
&lt;g:javascript&gt;
     function showSpinner(visible) {
         $('spinner').style.display = visible ? "inline" : "none";
     }
     Ajax.Responders.register({
     onLoading: function() {
           showSpinner(true);
     },
     onComplete: function() {
     if(!Ajax.activeRequestCount) showSpinner(false);
     }
   });
&lt;/g:javascript&gt;
&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Update your controller with any code needed - below is my entire BookController&lt;/li&gt;
&lt;pre class="brush:groovy"&gt;package ajax

class BookController {

     def scaffold = true
  
  def showEditAjax = {
   render (view:'editAjax', model:[bookInstance:Book.get(params.id)])
  }
  
  def showListSelect = {
   render (view:'listSelect', model:[bookInstanceList:Book.list()])
  }
  
  def showTitleSearch = {
   render (view:'titleSearchAjax')
  }
  
  def showRemoteLink = {
   render (view:'remoteLink', model:[bookInstanceList:Book.list()])
  }
  
  def showDetails = {
   render(template:'bookDetails', model:[bookInstance:Book.get(params.id)])
  }
  
  def showSearch = {
   render (view:'searchAjax')
  }
  
  def String wrapSearchParm(value) {
   '%'+value+'%'
  }
  
  def searchTitle = {
   def list = Book.findAllByTitleIlike(wrapSearchParm(params.searchvalue))
   render(template:'searchResults', model:[searchresults:list])
  }
  
  def search = {
   def list
   if (params.publisher &amp;amp;&amp;amp; params.title)
    list = Book.findAllByTitleIlikeAndPublisherIlike(wrapSearchParm(params.title), wrapSearchParm(params.publisher))
   else if (params.publisher)
    list = Book.findAllByPublisherIlike(wrapSearchParm(params.publisher))
      else if (params.title)
       list = Book.findAllByTitleIlike(wrapSearchParm(params.title))
   
   render(template:'searchResults', model:[searchresults:list])
  }
  
  def listByPublisher = {
   def list
   if (params.filter.equals("All"))
    list = Book.list()
    else
      list = Book.findAllByPublisher(params.filter)
   
   render(template:'searchResults', model:[searchresults:list])
  }
  
 def update = {
  def bookInstance = Book.get( params.id )
  if(bookInstance) {
   bookInstance.properties = params
   if(!bookInstance.hasErrors() &amp;amp;&amp;amp; bookInstance.save()) {
    render "
&lt;h3&gt;Book ${params.title} updated with Ajax using FormRemote&lt;/h3&gt;"
   }
   else {
    render(view:'edit',model:[bookInstance:bookInstance])
   }
  }
  else {
   flash.message = "Book not found with id ${params.id}"
   redirect(action:edit,id:params.id)
  }
   
  }
  
}

&lt;/pre&gt;&lt;li&gt;Create/update view(s) - See screen shots below and/or download the application&lt;/li&gt;
&lt;/ul&gt;&lt;ol&gt;&lt;/ol&gt;Most of the examples are fairly straight forward and should not need a lot of explanation. &amp;nbsp;They may not be great 'real world' examples but the intention is to provide a working example for someone to start from.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;FormRemote&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: inherit;"&gt;The &lt;a href="http://grails.org/doc/latest/ref/Tags/formRemote.html"&gt;formRemote&lt;/a&gt; taglib creates a form tag that uses a remote uri to execute an ajax call.&amp;nbsp; In this case, I have slightly modified the default generated edit.gsp to change the form tag to a formRemote tag and added a div to show the edit results.&amp;nbsp;&amp;nbsp; The screen shot below shows the result of first clicking the Form Remote navigation menu button, changing the number of pages in the 'Grails in Action' book and pressing the Update button at the bottom of the screen.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_JAJdxIvTyzE/TUY9fUG8qKI/AAAAAAAAAXs/jJhmoCqCYdE/s1600/formremote.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="402" src="http://3.bp.blogspot.com/_JAJdxIvTyzE/TUY9fUG8qKI/AAAAAAAAAXs/jJhmoCqCYdE/s640/formremote.PNG" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;RemoteLink&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: inherit;"&gt;The &lt;a href="http://grails.org/doc/latest/ref/Tags/remoteLink.html"&gt;RemoteLink&lt;/a&gt; tag creates a link that calls a remote function when clicked.&amp;nbsp; In the example application,&amp;nbsp; I display a list of book titles and the title is a link.&amp;nbsp; Clicking on the title shows the book details at the bottom of the screen.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class="brush:xml"&gt;&lt;g:each in="${bookInstanceList}" status="i" var="bookInstance"&gt;
    &lt;g:remotelink action="showDetails" id="${bookInstance.id}" oncomplete="showSpinner(false);" onloading="showSpinner(true);" update="bookDetails"&gt;${fieldValue(bean: bookInstance, field: "title")}&lt;/g:remotelink&gt;    
&lt;/g:each&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_JAJdxIvTyzE/TUD1M_zCTII/AAAAAAAAAXo/96Y7CWtW9qE/s1600/remoteLink.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="428" src="http://2.bp.blogspot.com/_JAJdxIvTyzE/TUD1M_zCTII/AAAAAAAAAXo/96Y7CWtW9qE/s640/remoteLink.PNG" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;SubmitToRemote&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: small; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma,Verdana,Arial; font-size: 15px;"&gt;The &lt;a href="http://grails.org/doc/latest/ref/Tags/submitToRemote.html"&gt;submitToRemote&lt;/a&gt; tag creates a button that submits the surrounding form as a remote Ajax call serializing the fields into parameters.&amp;nbsp; In the example application, I created search fields for Title and Publisher.&amp;nbsp; The search button was created using the SubmitToRemote taglib to submit the search parameters using Ajax. &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre;"&gt;    &lt;/span&gt;&lt;br /&gt;
&lt;pre class="brush:xml"&gt;&lt;g:form action="search"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr class="prop"&gt;             &lt;td class="name" valign="top"&gt;Title:&lt;/td&gt;             &lt;td class="value" valign="top"&gt;&lt;input name="title" type="text" value="${title}" /&gt;&lt;/td&gt;          &lt;/tr&gt;
&lt;tr class="prop"&gt;             &lt;td class="name" valign="top"&gt;Publisher:&lt;/td&gt;             &lt;td class="value" valign="top"&gt;&lt;input name="publisher" type="text" value="${publisher}" /&gt;&lt;/td&gt;          &lt;/tr&gt;
&lt;/tbody&gt;      &lt;/table&gt;&lt;g:submittoremote oncomplete="showSpinner(false)" onloading="showSpinner(true)" update="searchresults" url="[controller:'book', action:'search']" value="Search"&gt;
&lt;/g:submittoremote&gt;&lt;/g:form&gt;&lt;/pre&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_JAJdxIvTyzE/TUD1LwFWoDI/AAAAAAAAAXc/NysUGX8J5iI/s1600/submitToRemote.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="428" src="http://2.bp.blogspot.com/_JAJdxIvTyzE/TUD1LwFWoDI/AAAAAAAAAXc/NysUGX8J5iI/s640/submitToRemote.PNG" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;RemoteFunction&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: inherit;"&gt;The example application uses the &lt;a href="http://grails.org/doc/latest/ref/Tags/remoteFunction.html"&gt;RemoteFunction&lt;/a&gt; taglib to create a remote javascript function that is assigned to the onChange DOM event.&amp;nbsp; When the user selects or changes the value in the Publisher dropdown list, the remote function is called and the bottom half of the screen displays books published by the selected Publisher.&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_JAJdxIvTyzE/TUD1Mrp-kHI/AAAAAAAAAXk/yV4e2_0DGUQ/s1600/remoteFunction.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="428" src="http://1.bp.blogspot.com/_JAJdxIvTyzE/TUD1Mrp-kHI/AAAAAAAAAXk/yV4e2_0DGUQ/s640/remoteFunction.PNG" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;RemoteField&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: inherit;"&gt;The example application uses the &lt;a href="http://grails.org/doc/latest/ref/Tags/remoteField.html"&gt;RemoteField&lt;/a&gt; taglib to create a dynamic search for Book titles, similar to Google Instant.&amp;nbsp; Search results are returned the screen as you type values in the Title Search field.&amp;nbsp;&amp;nbsp; The controller code in this case,&amp;nbsp; wraps the search parameter with the wild card character (%) to search the database and returns all matches to be displayed.&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:xml"&gt;&lt;div id="searchbox"&gt;Title Search: 
&lt;g:remotefield name="search" oncomplete="showSpinner(false);" onloading="showSpinner(true);" paramname="searchvalue" update="searchresults" url="[controller:'book', action:'searchTitle']"&gt;
&lt;/g:remotefield&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_JAJdxIvTyzE/TUD1MUvRXQI/AAAAAAAAAXg/RA5gKvflA34/s1600/remoteField.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="428" src="http://1.bp.blogspot.com/_JAJdxIvTyzE/TUD1MUvRXQI/AAAAAAAAAXg/RA5gKvflA34/s640/remoteField.PNG" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Problems Encountered&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;I ran into problems trying to get the spinner to show correctly until I found this&amp;nbsp;&lt;a href="http://stackoverflow.com/questions/759049/how-to-use-onloading-event-in-grails-remotefunction"&gt;entry on StackOverflow&lt;/a&gt;&amp;nbsp;that showed how to register the Ajax events. &amp;nbsp;When running locally on the same box, this happens very fast so you really need to keep and eye on the upper right corner of the screen if you want to see the spinner.&lt;/li&gt;
&lt;li&gt;I also ran into problems with the RemoteFunction due to syntax problems. &amp;nbsp;Being used to the taglibs, &amp;nbsp;I was setting the update parameter using update="mydiv" when the syntax should have been update:"mydiv". &amp;nbsp;This did not flag as an error. &amp;nbsp;The controller was called, it just never updated the target div!&lt;/li&gt;
&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Downloads&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;a href="http://sites.google.com/site/mikesgroovystuff/home/downloads"&gt;Download a zip from here&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="git://github.com/mikemil/AjaxExamples.git"&gt;Get a copy from Github &lt;/a&gt;- this is my first crack at creating&amp;nbsp; a repo at Github, so if I did it wrong, please let me know.&lt;/li&gt;
&lt;/ul&gt;It was fun putting this together. &amp;nbsp; Hope it helps some of you!&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-8296285648114948943?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/p8fyXoaiVBo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/8296285648114948943/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2011/01/grails-ajax-examples.html#comment-form" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/8296285648114948943?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/8296285648114948943?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/p8fyXoaiVBo/grails-ajax-examples.html" title="Grails AJAX Examples" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_JAJdxIvTyzE/TUY9fUG8qKI/AAAAAAAAAXs/jJhmoCqCYdE/s72-c/formremote.PNG" height="72" width="72" /><thr:total>8</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2011/01/grails-ajax-examples.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcMR346fip7ImA9Wx9TE0w.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-4649220514750253376</id><published>2010-11-20T22:18:00.000-06:00</published><updated>2010-11-20T22:18:06.016-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-20T22:18:06.016-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="shutterfly holiday cards" /><title>Shutterfly Holiday Collection</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/5RRLMcoVg7WhED5wOpVo_ejya2Q/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5RRLMcoVg7WhED5wOpVo_ejya2Q/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/5RRLMcoVg7WhED5wOpVo_ejya2Q/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5RRLMcoVg7WhED5wOpVo_ejya2Q/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="ecxMsoNormal"&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Times New Roman';"&gt;We have used  Shutterfly to create family albums and mouse pads in the past.&amp;nbsp; I  have found the quality of the albums from Shutterfly is great.&amp;nbsp; The  album pictures are clear and sharp.&amp;nbsp; Based on our past experiences  and quality of products that we’ve received, we’re excited about using&amp;nbsp;Shutterfly for our Christmas cards this year.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Times New Roman';"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Times New Roman';"&gt;I  have found the Shutterfly Christmas card &lt;a href="http://www.shutterfly.com/cards-stationery/christmas-cards"&gt;selection &lt;/a&gt;is tremendous.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Times New Roman';"&gt;&amp;nbsp;In particular, my  family was pleased at the number of religious photo cards that are  available.&amp;nbsp; We particularly like the following photo  cards: &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Times New Roman';"&gt;&lt;a href="http://www.shutterfly.com/cards-stationery/cards-stationery/rejoice-lord-king-religious-christmas-5x7-folded-card?sortType=1&amp;amp;fa=8&amp;amp;storeNode=60217"&gt;&amp;nbsp;&lt;/a&gt;&lt;a href="http://www.shutterfly.com/cards-stationery/cards-stationery/rejoice-lord-king-religious-christmas-5x7-folded-card?sortType=1&amp;amp;fa=8&amp;amp;storeNode=60217"&gt;here&amp;nbsp;&lt;/a&gt;and &amp;nbsp;&lt;a href="http://www.shutterfly.com/cards-stationery/cards-stationery/faith-hope-family-religious-christmas-card-5x7-flat?sortType=1&amp;amp;fa=8&amp;amp;storeNode=60217"&gt;here&amp;nbsp;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Times New Roman';"&gt;.&amp;nbsp;&amp;nbsp; The cards in the links  above allow us to include four to five pictures of our family so that we don’t  have to agonize of picking the one best picture!&amp;nbsp; Our plan is to  use one of these photo cards for the dual purpose of spreading the message of  the season, as we believe it, and to share pictures of our family with loved  ones and friends.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Times New Roman';"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Times New Roman';"&gt;Enjoy the selection from Shutterfly and Happy Holidays!!!&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-family: 'Times New Roman';"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-4649220514750253376?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/Abb4ZiFjxOc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/4649220514750253376/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2010/11/shutterfly-holiday-collection.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/4649220514750253376?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/4649220514750253376?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/Abb4ZiFjxOc/shutterfly-holiday-collection.html" title="Shutterfly Holiday Collection" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2010/11/shutterfly-holiday-collection.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IDSHgzeSp7ImA9Wx5UFk8.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-2652373781198326043</id><published>2010-10-20T21:52:00.000-05:00</published><updated>2010-10-20T21:52:59.681-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-20T21:52:59.681-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groovy GString SQL" /><title>Be careful using GStrings for SQL</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/glMXyQLir_SK-skONSFMoUdynP4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/glMXyQLir_SK-skONSFMoUdynP4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/glMXyQLir_SK-skONSFMoUdynP4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/glMXyQLir_SK-skONSFMoUdynP4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;If you are like me, you love the ease with which you can create Groovy scripts to manipulate your databases.  Gone are the days of writing utility classes to make these changes, thanks to Groovy and the &lt;a href="http://groovy.codehaus.org/gapi/"&gt;SQL &lt;/a&gt;package.  But if you aren't careful, you can run into a couple of strange errors if you use the GStrings.&lt;br /&gt;
&lt;br /&gt;
For the below example, I have a table named LOCATION in my 'test' database that has two columns: location_id and location_name.  The example below works fine and you notice that I am not using any variables in the SQL statement &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;import groovy.sql.Sql

db = Sql.newInstance('jdbc:mysql://127.0.0.1:3306/test', 'root', 'root', 'com.mysql.jdbc.Driver')

def sqlStatement = """select * from location where location_id &gt; 3"""

db.eachRow (sqlStatement){ 
   println it
}

println "Done!"
&lt;/pre&gt;&lt;br /&gt;
Next, try making the SQL a bit more dynamic by specifying the table name, column name and key value as variables within the GString and watch what happens.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;import groovy.sql.Sql

db = Sql.newInstance('jdbc:mysql://127.0.0.1:3306/test', 'root', 'root', 'com.mysql.jdbc.Driver')

def tableName = 'location'
def columnName = 'location_id'
def key = 3
def sqlStatement = """select * from $tableName where $columnName &gt; $key"""

db.eachRow (sqlStatement){ 
   println it
}

println "Done!"
&lt;/pre&gt;&lt;br /&gt;
&lt;pre class="brush:plain"&gt;WARNING: Failed to execute: select * from ? where ? &gt; ? because: 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 ''location' where 'location_id' &gt; 3' at line 1
&lt;/pre&gt;&lt;br /&gt;
The quick fix I found was to call the toString() method on the GString and this resolves the problem. I found a line in "&lt;a href="http://www.manning.com/koenig/"&gt;Groovy In Action&lt;/a&gt;" which helps explain the problem:  &lt;blockquote&gt;&lt;b&gt;The special use of GStrings as SQL statements limits the use of placeholders to places where a question mark would otherwise be allowed in a prepared statement.&lt;/b&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;import groovy.sql.Sql

db = Sql.newInstance('jdbc:mysql://127.0.0.1:3306/test', 'root', 'root', 'com.mysql.jdbc.Driver')

def tableName = 'location'
def columnName = 'location_id'
def key = 3
def sqlStatement = """select * from $tableName where $columnName &gt; $key""".toString()

db.eachRow (sqlStatement){ 
   println it
}

println "Done!"
&lt;/pre&gt;&lt;br /&gt;
Keep this in mind the next time you use the Groovy SQL class!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-2652373781198326043?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/hlhMoYzhFOk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/2652373781198326043/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2010/10/be-careful-using-gstrings-for-sql.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/2652373781198326043?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/2652373781198326043?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/hlhMoYzhFOk/be-careful-using-gstrings-for-sql.html" title="Be careful using GStrings for SQL" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>5</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2010/10/be-careful-using-gstrings-for-sql.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMGRnszfip7ImA9Wx5TFU8.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-1157349083011530536</id><published>2010-07-30T16:13:00.000-05:00</published><updated>2010-07-30T16:13:47.586-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-30T16:13:47.586-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Ant" /><title>Get value from SQL into an Ant property</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/3DJGwLw0xeuW1HljiN6vwuYsovA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3DJGwLw0xeuW1HljiN6vwuYsovA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/3DJGwLw0xeuW1HljiN6vwuYsovA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3DJGwLw0xeuW1HljiN6vwuYsovA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;Recently I had to adjust some of our JMS configuration and needed make sure we set the ServerPeerID configuration value to a unique value among our servers.  We have a unique server number in our database so I figured that I would just use that value.  In order to do this, I needed to get the database value into an Ant property, which is then used to generate the configuration file, which includes the ServerPeerID.  Below is the Ant task and steps I used to do this.&lt;br /&gt;
&lt;br /&gt;
Steps:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Define where the SQL results will be written&lt;/li&gt;
&lt;li&gt;Make sure the file does not already exist&lt;/li&gt;
&lt;li&gt;SQL task to get the result&lt;/li&gt;
&lt;li&gt;Load the file back into a property&lt;br /&gt;
&lt;/li&gt;
Use the propertyregex task to strip out just the unique number  &lt;/ol&gt;&lt;br /&gt;
&lt;strong&gt;Warning:&lt;/strong&gt; The syntax highlighter appears to be reformatting my XML and not allowing the self closing tags.  Probably my problem but you should be able to get the idea from the &lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&lt;pre class="brush:xml"&gt;&lt;target name="setstorenumber"&gt;
   &lt;property name="sql.output.file" value="storenumber.txt"&gt;
   &lt;delete file="${sql.output.file}" quiet="true"&gt;
   &lt;sql driver="${store.database.driver}" output="${sql.output.file}" password="root" print="true" showheaders="false" url="your_database_url_goes_here" userid="root"&gt;
      &lt;classpath refid="jboss.classpath"&gt;
      SELECT PREF_VALUE FROM PREFERENCE WHERE PREFERENCE_ID = 71;                
    &lt;/classpath&gt;
     
    &lt;loadfile property="store.number" srcfile="${sql.output.file}"&gt;
    &lt;propertyregex input="${store.number}" property="server.peer.id" 
     regexp="(\d*).*" select="\1"&gt;
&lt;/propertyregex&gt;&lt;/loadfile&gt;&lt;/sql&gt;&lt;/delete&gt;&lt;/property&gt;&lt;/target&gt;&lt;b&gt;
&lt;/b&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-1157349083011530536?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/TpRSfJ4hEPg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/1157349083011530536/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2010/07/get-value-from-sql-into-ant-property.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/1157349083011530536?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/1157349083011530536?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/TpRSfJ4hEPg/get-value-from-sql-into-ant-property.html" title="Get value from SQL into an Ant property" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2010/07/get-value-from-sql-into-ant-property.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0IMQH04cCp7ImA9WxFRFUw.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-3218373276333837058</id><published>2010-04-28T23:31:00.002-05:00</published><updated>2010-04-28T23:33:01.338-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-28T23:33:01.338-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groovy sockets serversocket client" /><title>Groovy Sockets example</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/iqouunWGOE-63uJo0vIB6w_z96o/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iqouunWGOE-63uJo0vIB6w_z96o/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/iqouunWGOE-63uJo0vIB6w_z96o/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iqouunWGOE-63uJo0vIB6w_z96o/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;I found several &lt;a href="http://pleac.sourceforge.net/pleac_groovy/sockets.html"&gt;sites&lt;/a&gt; and blogs with Groovy socket examples but none that showed a matched pair of the server and the client sending data back and forth.  Collecting bits from different sources, I put together the following server and client scripts using Groovy.  &lt;br /&gt;
&lt;br /&gt;
The sample works by sending a line of data as a request; thus the server calls readLine() and the client sends a new line character at the end of the input.   The server echos the request back to the client along with a timestamp.  For those that skip reading the documentation, ServerSocket's &lt;a href="http://groovy.codehaus.org/groovy-jdk/java/net/ServerSocket.html"&gt;accept&lt;/a&gt; method "Accepts a connection and passes the resulting Socket to the closure which runs in a new Thread." so this server creates a new thread for each request.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Groovy Socket server&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;import java.net.ServerSocket
def server = new ServerSocket(4444)

while(true) {
    server.accept { socket -&gt;
        println "processing new connection..." 
        socket.withStreams { input, output -&gt;
            def reader = input.newReader()
            def buffer = reader.readLine()
            println "server received: $buffer"
            now = new Date()
            output &lt;&lt; "echo-response($now): " + buffer + "\n"
        }
        println "processing/thread complete."
    }
}
&lt;/pre&gt;
&lt;b&gt;Groovy Socket client&lt;/b&gt;

&lt;pre class="brush:groovy"&gt;s = new Socket("localhost", 4444);
s.withStreams { input, output -&gt;
  output &lt;&lt; "echo testing ...\n"
  buffer = input.newReader().readLine()
  println "response = $buffer"
}
&lt;/pre&gt;
&lt;br /&gt;
Give it try!  Hope this helps...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-3218373276333837058?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/tho7r8P7M3M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/3218373276333837058/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2010/04/groovy-sockets-example.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/3218373276333837058?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/3218373276333837058?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/tho7r8P7M3M/groovy-sockets-example.html" title="Groovy Sockets example" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2010/04/groovy-sockets-example.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUDSHg7cSp7ImA9WxFREU4.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-5798737773477506620</id><published>2010-04-24T14:44:00.000-05:00</published><updated>2010-04-24T14:44:39.609-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-24T14:44:39.609-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="webstart web start jnlp javaws_vm_args" /><title>Trouble connecting to Web Start client?</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/3EOP-LpwdQYaXujAIPOl1lWBGxQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3EOP-LpwdQYaXujAIPOl1lWBGxQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/3EOP-LpwdQYaXujAIPOl1lWBGxQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3EOP-LpwdQYaXujAIPOl1lWBGxQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;Do you have problems getting either the debugger or JConsole attached or connected to your Web Start client?&amp;nbsp; We worked around this for way too long until we finally found the trick: environment variable JAVAWS_VM_ARGS.&lt;br /&gt;
&lt;br /&gt;
JNLP allows for&lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/faq.html#203"&gt; vm args to be passed to the Java runtime&lt;/a&gt; but there is a limited set of arguments that are allowed to be passed on.&amp;nbsp; Anything not in that list of secure properties is ignored.&amp;nbsp; You can find the list of secure properties in the &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/syntax.html"&gt;Developers Guide.&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
As I said ealier, if you want to attach a debugger or JConsole to you Web Start application, then you need to use the JAVAWS_VM_ARGS parameter.&amp;nbsp;&amp;nbsp; For example, if I want to attached to my web start client for debugging purposes then I can do the following:&lt;br /&gt;
&lt;br /&gt;
set &lt;span class="searchTerm"&gt;JAVAWS&lt;/span&gt;_&lt;span class="searchTerm"&gt;VM&lt;/span&gt;_&lt;span class="searchTerm"&gt;ARGS&lt;/span&gt;=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
in my environment, start the client and then attach to the process using port 5005.&amp;nbsp; The same goes for attaching to JConsole, set the properties you need in JAVAWS_VM_ARGS, so com.sun.management.jmxremote.* should all be set inside JAVAWS_VM_ARGS.&lt;br /&gt;
&lt;br /&gt;
Hope this help!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-5798737773477506620?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/ZleWz9sOzuY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/5798737773477506620/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2010/04/trouble-connecting-to-web-start-client.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5798737773477506620?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5798737773477506620?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/ZleWz9sOzuY/trouble-connecting-to-web-start-client.html" title="Trouble connecting to Web Start client?" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2010/04/trouble-connecting-to-web-start-client.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QGQXw9cSp7ImA9WxBRFUo.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-6596005734302980688</id><published>2010-01-03T22:28:00.000-06:00</published><updated>2010-01-03T22:28:40.269-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-03T22:28:40.269-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groovy html MarkupBuilder" /><title>Ant task ported to Groovy - Part 3</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/GyDvh8XeM23M1A5r99zVy0GRgwg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GyDvh8XeM23M1A5r99zVy0GRgwg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/GyDvh8XeM23M1A5r99zVy0GRgwg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GyDvh8XeM23M1A5r99zVy0GRgwg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;Welcome to the final posting of this series where I have been porting one of my Ant tasks from Java to Groovy.&amp;nbsp; If you haven't read &lt;a href="http://programmingitch.blogspot.com/2009/12/java-ant-task-ported-to-groovy-part-1.html"&gt;part 1&lt;/a&gt; or &lt;a href="http://programmingitch.blogspot.com/2009/12/ant-task-ported-to-groovy-part-2.html"&gt;part 2&lt;/a&gt;, then you might want to take a quick pass through those before reading this posting.&amp;nbsp; In this posting, I will show the following:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;FileValidator class ported to Groovy&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Using HTML Builder to generate the HTML report&amp;nbsp; &lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Full listings of the scripts &amp;amp; classes created&lt;/li&gt;
&lt;/ul&gt;&lt;b&gt;FileValidator ported to Groovy&lt;/b&gt;&lt;br /&gt;
One of the last tasks left to do is to port the &lt;i&gt;FileValidator &lt;/i&gt;class from Java over to Groovy.&amp;nbsp; The &lt;i&gt;FileValidator&lt;/i&gt; class is created in the process() method of the &lt;i&gt;Validator &lt;/i&gt;class and called for every file to be validated.&amp;nbsp; This is another example of where the Groovy code is a lot shorter and more concise than the Java code.&amp;nbsp;&amp;nbsp; The &lt;i&gt;FileValidator &lt;/i&gt;class handles the iteration thru a file, line by line, checking each regular expression checking for a potential error condition.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;

/**
 * File validator runs a list of regular expressions against the file
 * attempting to validate the file.  Errors are kept in a list and
 * then the caller can get the list of errors and log them - right
 * now the ant task will log them. 
 *
 */
public class FileValidator {

    private List regExDescriptors;
    private File file;
    private List errors;
    
    /**
     * Default constructor
     * @param list List of RegExDescriptors used to validate a file
     * @param file File to be validated
     */
    public FileValidator(List list, File file) {
        regExDescriptors = new ArrayList(list);
        this.file = file;
        errors = new ArrayList();
    }
    
    public List getErrors() {
        return errors;
    }
    
    public void validate() {
      // see if we should exclude this file  
      processExcludes();
      
      // Run the regEx(s) against the file to check for problems
      BufferedReader in = null;
      try {
          in = new BufferedReader(new FileReader(file));
          String str;
          int lineNumber = 1;
          while ((str = in.readLine()) != null) {
              for (Iterator iter = regExDescriptors.iterator(); iter.hasNext();) {
                  RegExDescriptor validator = (RegExDescriptor) iter.next();
                  Matcher matcher = validator.getMatcher(str);
                  if (matcher.find()) {
                   errors.add( validator.getDescription() + " on line " + lineNumber);
                  }
              }
              lineNumber++;
          }
      } catch (IOException e) {
          e.printStackTrace();
      } finally {
          if (in != null)
              try {
                  in.close();
              } catch (IOException e) {
              }
      }  
    }

    private void processExcludes()
    {
        String fullName;
        try
        {
            fullName = file.getCanonicalPath();
        }
        catch (IOException e)
        {
            fullName = file.getName();
            e.printStackTrace();
        }
        for (Iterator iter = regExDescriptors.iterator(); iter.hasNext();)
        {
            RegExDescriptor descriptor = (RegExDescriptor) iter.next();
            if (descriptor.excludeFile(fullName))
            {
                iter.remove();
            }
        }
    }    
}&amp;nbsp;&lt;/pre&gt;&lt;b&gt;Groovy code for file validation&lt;/b&gt;&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;//**************************************
// process each file, line by line
//**************************************
files.each {fileName -&amp;gt;
  def errors = []
  def lines = new File(fileName).readLines()
  def lineNumber = 1
  lines.each {line -&amp;gt;
    // for each line - iterate thru descriptors looking for matches if file not excluded
    descriptorList.each {
      if (!(fileName =~ /$it.exclude/)) {
        if ((line =~ /$it.regex/).find()) {
          errors.add(it.description + " on line " + lineNumber)
          errCnt++
        }
      }
    }
    lineNumber++
  }
  if (errors)
    results.put((fileName), errors)
}
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Generating the results report&lt;/b&gt;&lt;br /&gt;
The last part of the port was to create an html output report similar to a JUnit report.&amp;nbsp; The Java code could have been better but it was simply a large set of write statements.&amp;nbsp; I decided to use the HTML markup builder to generate the output report. &lt;br /&gt;
&lt;pre class="brush:groovy"&gt;//*******************************************************
// generate the report
//*******************************************************
def writer = new FileWriter("$opt.r")
def html = new groovy.xml.MarkupBuilder(writer)
def rptDate = new Date()

html.html {
  head{
    title 'Validator Report'
  }
  body {
    h1 "File Validation - as of $rptDate"
    h2 "Validation Descriptors for file extension $opt.e"
    table ('border':0, 'cellpadding':5, 'cellspacing':2, 'width':'80%'){
      tr ('bgcolor':'#a6caf0') {
        th ("Description")
        th ("Validating Regular Expression")
      }
      //iterate thru descriptors - listing the regular expressions used in validation
      descriptorList.each { descriptor -&amp;gt;
        tr ('bgcolor':'#eeeee0') {
          td (descriptor.description)
          td (descriptor.regex)
        }
      }
    }
    // Summary table - just a file &amp;amp; error count
    h2 'Validation Summary'
    table ('border':0, 'cellpadding':5, 'cellspacing':2, 'width':'80%'){
      tr ('bgcolor':'#a6caf0') {
        th ("Files Processed")
        th ("Error Count")
      }
      tr ('bgcolor':'#eeeee0')  {
        td ("$files.size")
        td ("$errCnt")
      }
    }
    if (errCnt)
    {
      // Error details table
      h2 "Validation Details for extension $opt.e "
      table ('border':0, 'cellpadding':5, 'cellspacing':2, 'width':'100%'){
        tr ('bgcolor':'#a6caf0') {
          th ("File")
          th ("Errors")
          th ("Details")
        }
        //iterate thru results map key is filename and value is list of error text)
        results.each { k, v -&amp;gt;
            tr ('bgcolor':'#eeeee0')  {
               td (k)
               td (v.size())
               td {
                 ul {
                   //iterate thru the list of errors
                   v.each {
                     li (it)
                   }
                 }
               }
            }
        }
      }
    }
  }
}
writer.toString()

&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Porting Results&lt;/b&gt;&lt;br /&gt;
Initial Java Ant task:&amp;nbsp; 3 classes and 326 lines of code&lt;br /&gt;
Groovy port: 1 script of 102 lines of code and 1 class with 9 lines of code.&amp;nbsp;&amp;nbsp; There are about 40 lines of processing code and the rest of the code/lines are from the html markup builder for the report.&lt;br /&gt;
&lt;br /&gt;
Shorter and more concise, you decide! &amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Groovy script and class source&lt;/b&gt;&lt;br /&gt;
Here's the full Validator.groovy script&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;/**
 *  Validator script ported from Java Ant task
 */

//********************************************
// handle command line parms - all required
//********************************************
def cli = new CliBuilder(usage: 'groovy Validator -e extension -p propertyFile -d directory -r reportFile')

cli.h(longOpt: 'help', 'usage information')
cli.e(longOpt: 'extension', args: 1, required: true, 'file extension to be validated')
cli.p(longOpt: 'prop', args: 1, required: true, 'property file containing regular expresssion')
cli.d(longOpt: 'directory', args: 1, required: true, 'base directory to start file search')
cli.r(longOpt: 'reportFile', args: 1, required: true, 'output file for validation report')

def opt = cli.parse(args)
if (!opt) return
if (opt.h) cli.usage()

println "Processing $opt.e files \n\tusing $opt.p \n\tfrom directory $opt.d \n\tand generate report output to $opt.r"
println 'extracting files...'

//*******************************************
// get all the files for provided extension
//*******************************************
def files = new FileNameFinder().getFileNames(opt.d, "**/*.$opt.e")
println "processing $files.size files..."

//**************************************************************
// load properties into list of ValidatorDescriptor objects
//**************************************************************
Properties properties = new Properties();
try {
  properties.load(new FileInputStream(opt.p));
} catch (IOException e) {}

def config = new ConfigSlurper().parse(properties)
def descriptorList = []
config."$opt.e".each {
  descriptorList &amp;lt;&amp;lt; new ValidatorDescriptor(it.value)
}

def errCnt = 0
def results = [:]

//**************************************
// process each file, line by line
//**************************************
files.each {fileName -&amp;gt;
  def errors = []
  def lines = new File(fileName).readLines()
  def lineNumber = 1
  lines.each {line -&amp;gt;
    // for each line - iterate thru descriptors looking for matches if file not excluded
    descriptorList.each {
      if (!(fileName =~ /$it.exclude/)) {
        if ((line =~ /$it.regex/).find()) {
          errors.add(it.description + " on line " + lineNumber)
          errCnt++
        }
      }
    }
    lineNumber++
  }
  if (errors)
    results.put((fileName), errors)
}

//*******************************************************
// generate the report
//*******************************************************
def writer = new FileWriter("$opt.r")
def html = new groovy.xml.MarkupBuilder(writer)
def rptDate = new Date()

html.html {
  head{
    title 'Validator Report'
  }
  body {
    h1 "File Validation - as of $rptDate"
    h2 "Validation Descriptors for file extension $opt.e"
    table ('border':0, 'cellpadding':5, 'cellspacing':2, 'width':'80%'){
      tr ('bgcolor':'#a6caf0') {
        th ("Description")
        th ("Validating Regular Expression")
      }
      //iterate thru descriptors - listing the regular expressions used in validation
      descriptorList.each { descriptor -&amp;gt;
        tr ('bgcolor':'#eeeee0') {
          td (descriptor.description)
          td (descriptor.regex)
        }
      }
    }
    // Summary table - just a file &amp;amp; error count
    h2 'Validation Summary'
    table ('border':0, 'cellpadding':5, 'cellspacing':2, 'width':'80%'){
      tr ('bgcolor':'#a6caf0') {
        th ("Files Processed")
        th ("Error Count")
      }
      tr ('bgcolor':'#eeeee0')  {
        td ("$files.size")
        td ("$errCnt")
      }
    }
    if (errCnt)
    {
      // Error details table
      h2 "Validation Details for extension $opt.e "
      table ('border':0, 'cellpadding':5, 'cellspacing':2, 'width':'100%'){
        tr ('bgcolor':'#a6caf0') {
          th ("File")
          th ("Errors")
          th ("Details")
        }
        //iterate thru results map key is filename and value is list of error text)
        results.each { k, v -&amp;gt;
            tr ('bgcolor':'#eeeee0')  {
               td (k)
               td (v.size())
               td {
                 ul {
                   //iterate thru the list of errors
                   v.each {
                     li (it)
                   }
                 }
               }
            }
        }
      }
    }
  }
}
writer.toString()

println "validation complete - possible error count = $errCnt"

//********************************
// for testing launch browser
//********************************
//"c:/program files/Internet Explorer/iexplore.exe $opt.r".execute()
&lt;/pre&gt;&lt;br /&gt;
Here's the one short class - ValidatorDescriptor.groovy&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;class ValidatorDescriptor {
    String description
    String exclude
    String regex

    String toString() {
       "regEx="+regex + " description=" + description + (exclude ? " exclude("+exclude+")" : "")
    }
}
&lt;/pre&gt;&lt;br /&gt;
And finally, my set of properties used for validation:&lt;br /&gt;
&lt;pre class="brush:text"&gt;#################################################################
#
# SQL file regular expressions
#
#################################################################

#
# Find instances of trailing spaces after the semicolon.
# This causes MySQL problems.
#
#
sql.1.regex=;\\s+$
sql.1.description=Trailing spaces after semicolon
sql.1.exclude=SQLServer|Oracle

#
# Instances of lines starting with GO
#
sql.2.regex=^GO
sql.2.description=GO statement


#
# Find spaces before ending semicolon (but not DELIMITER ; which is used for MySQL Stored Procedures)
#
sql.4.regex=^(?!DELIMITER)\\s+;$
sql.4.description=Spaces before ending semicolon
sql.4.exclude=SQLServer|Oracle


#
# Oracle scripts using nvarchar
#
#
sql.5.regex=nvarchar
sql.5.description=Oracle scripts using nvarchar
sql.5.exclude=SQLServer|MySQL|Store Update

#
# MySQL scripts using ntext
#
#
sql.6.regex=\\sntext
sql.6.description=MySQL scripts using ntext data type
sql.6.exclude=SQLServer|Oracle
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;
There you go - another itch successfully scratched!&amp;nbsp;&amp;nbsp; Maybe this task/script will be of help to others.&amp;nbsp; The design was to make this a generic file validation utility and the SQL validation is the only use we have found so far.&amp;nbsp; Enjoy!&lt;br /&gt;
&lt;b&gt; &lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-6596005734302980688?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/cH5BAHAMv_g" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/6596005734302980688/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2010/01/ant-task-ported-to-groovy-part-3.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/6596005734302980688?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/6596005734302980688?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/cH5BAHAMv_g/ant-task-ported-to-groovy-part-3.html" title="Ant task ported to Groovy - Part 3" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2010/01/ant-task-ported-to-groovy-part-3.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cCRXc_fyp7ImA9WxBSFEs.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-7988869346073663085</id><published>2009-12-21T23:44:00.004-06:00</published><updated>2009-12-21T23:51:04.947-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-21T23:51:04.947-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groovy CliBuilder ConfigSlurper" /><title>Ant task ported to Groovy - Part 2</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/1_PrIc01fRHRFQaqb6N--AQygy8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1_PrIc01fRHRFQaqb6N--AQygy8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/1_PrIc01fRHRFQaqb6N--AQygy8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1_PrIc01fRHRFQaqb6N--AQygy8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;Welcome back if you read&lt;a href="http://programmingitch.blogspot.com/2009/12/java-ant-task-ported-to-groovy-part-1.html"&gt; part 1&lt;/a&gt; of this posting.&amp;nbsp; If you haven't read part 1, you may want to take a quick look at that before reading this part of the posting.&amp;nbsp; This posting (part 2) will show the following changes or ports from Java to Groovy for the validator ant task.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://groovy.codehaus.org/gapi/groovy/util/CliBuilder.html"&gt;CliBuilder &lt;/a&gt;for command line interface&lt;/li&gt;
&lt;li&gt;ValidatorDescriptor class&lt;/li&gt;
&lt;li&gt;Consuming the properties file&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;b&gt;Switch from Ant to a Groovy task&lt;/b&gt; &lt;br /&gt;
As I mentioned in part 1, this port will not be an exact port because I am creating a groovy script rather than an Ant/Gant task - partly because I haven't played with Gant yet!&amp;nbsp; Some of the existing Ant task code is shown below.  For those familiar with creating Ant tasks, you will notice the class extends &lt;i&gt;Task&lt;/i&gt; which is an abstract class.&amp;nbsp;&amp;nbsp; The code overrides the execute() method. &amp;nbsp; The validator task checks the input and output parameters and then calls the validate() method to validate the files.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.PatternSyntaxException;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

public class Validator extends Task {

    private static final String DEFAULT_EXCLUDE = "";
    
    // constants used to create the property file keys 
    // --&amp;gt; extension.&lt;number&gt;.regex or extension.&lt;number&gt;.description 
    private static final String REGEX       = ".regex";
    private static final String DESCRIPTION = ".description";
    private static final String EXCLUDE     = ".exclude";
    
    private String extension;
    private String directory;
    private String propertyFile;
    private String reportFile;
    
    private int fileCnt;
    private int errorCnt;
    private List descriptors;
    private Properties props;
    private Map errorMap;

    /**
     * Default constructor
     */
    public Validator() {
        props = new Properties();
        descriptors = new ArrayList();
        errorMap = new HashMap();
        errorCnt = 0;
        fileCnt = 0;
    }

    /**
     * Sets the extension for the task
     * @param extension extension of the files to be validated
     */
    public void setExtension(String extension) {
        this.extension = extension;
    }
    
    /**
     * Sets the root directory to be processed.  This directory
     * and all of its subdirectories will be processed.
     * @param directory directory to be processed.  
     */
    public void setDirectory(String directory) {
        this.directory = directory;
    }
    
    /**
     * Sets the root directory to be processed.  This directory
     * and all of its subdirectories will be processed.
     * @param directory directory to be processed.  
     */
    public void setPropertyFile(String fileName) {
        this.propertyFile = fileName;
    }

    /**
     * Set the report file to be created as output
     * @param reportFile name of the html file to be
     *   generated to show any errors
     */    
    public void setReportFile(String reportFile) {
  this.reportFile = reportFile;
 }
    
 /**
     * Creates an xml file from the bugs file
     */
    public void execute() throws BuildException {
        checkParameters();
        try {
            validate();
        } catch (BuildException e) {
            throw e;
        }
    }

    /**
     * Check that all required attributes have been set
     * @throws BuildException if any of the required attributes
     *      have not been set.
     */
    private void checkParameters() {
           if (extension == null || extension.length() == 0  
                ||   directory == null || directory.length() == 0 
                ||   reportFile == null || reportFile.length() == 0 
                || propertyFile == null || propertyFile.length() == 0) 
               throw new BuildException("Extension, directory, reportFile and property file attributes "
                      + "must be defined for task &amp;lt;" + getTaskName() + "/&amp;gt;" );
    }

    private void validate() {
        File dir = new File(directory);
        log("Processing file extension : "+extension+"\n");
        
        try {
            props.load(new FileInputStream(propertyFile));
                      
            setDescriptors();
            visitAllDirsAndFiles(dir);
            
            writeReport();
            
            log("Validator processed "+fileCnt+ " files and found "+errorCnt+" possible errors!");
            
        } catch (Exception e) {
            log(e.toString());
        }
    }
   private void writeReport() {
     try {
  FileWriter writer = new FileWriter(reportFile);
  writeHeaders(writer);
  writeContents(writer);
  writeTrailer(writer);
  writer.close();
 } catch (IOException e) {
  throw new BuildException(e);
 }
   }

   // some code omitted here - but shown later!!!
}
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Groovy replacement using CliBuilder&lt;/b&gt;&lt;br /&gt;
While not a whole lot shorter than the Ant equivalent, it is short, concise and a good example of &lt;a href="http://groovy.codehaus.org/gapi/groovy/util/CliBuilder.html"&gt;&lt;i&gt;CliBuilder&lt;/i&gt;&lt;/a&gt; usage.&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;def cli = new CliBuilder (usage: 'groovy Validator -e extension -p propertyFile -d directory -r reportFile')

cli.h(longOpt: 'help', 'usage information')
cli.e(longOpt:'extension',  args:1, required:true, 'file extension to be validated')
cli.p(longOpt:'prop',       args:1, required:true, 'property file containing regular expresssion')
cli.d(longOpt:'directory',  args:1, required:true, 'base directory to start file search')
cli.r(longOpt:'reportFile', args:1, required:true, 'output file for validation report')

def opt = cli.parse(args)
if (!opt) return
if (opt.h) cli.usage()

println "start processing $opt.e files using $opt.p from $opt.d and output to $opt.r"
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;RegExDescriptor becomes ValidatorDescriptor&lt;/b&gt;&lt;br /&gt;
First the java...&lt;br /&gt;
&lt;pre class="brush:java"&gt;import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * Regular Expression Descriptor used to help
 * validate source files.  
 *
 */
public class RegExDescriptor {

    private String description;
    private Pattern excludePattern;
    private Pattern pattern;

    public RegExDescriptor(String regExString, String description, String exclude) throws PatternSyntaxException {        this.description = description;
        pattern = Pattern.compile(regExString, Pattern.CASE_INSENSITIVE);
        if (exclude != null &amp;amp;&amp;amp; exclude.length() &amp;gt; 0)
            excludePattern = Pattern.compile(exclude);
        else
            excludePattern = null;
    }

    public Matcher getMatcher(String line) {
        return pattern.matcher(line);
    }

    public String getDescription() {
        return description;
    }
    
    public boolean excludeFile(String name) {
        if (excludePattern == null) 
            return false;
        Matcher matcher = excludePattern.matcher(name);
        return matcher.find();
    }

    public String getPattern()  {
     return pattern.pattern();
    }
    
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("Validator description=").append(description);
        sb.append(" regEx=").append(pattern.pattern());
        if (excludePattern != null)
            sb.append(" exclude regEx=").append(excludePattern.pattern());
        return sb.toString();
    }
}
&lt;/pre&gt;Now the Groovy equivalent, which I renamed to ValidatorDescriptor.  Like a lot of Java classes ported to Groovy, it is significantly shorter since we don't need to specify the getters and setters.  The toString() method is really needed but I used it in testing to display the ValidatorDescriptor classes created from the properties file.&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;class ValidatorDescriptor {
    String description
    String exclude
    String regex

    String toString() {
       "regEx="+regex + " description=" + description + (exclude ? " exclude("+exclude+")" : "")
    }
}
&lt;/pre&gt;&lt;b&gt;Consuming the properties file&lt;/b&gt;&lt;br /&gt;
The next task is to read the properties file and create a list of objects representing each of the errors I am attempting to capture. &amp;nbsp; If you remember from &lt;a href="http://programmingitch.blogspot.com/2009/12/java-ant-task-ported-to-groovy-part-1.html"&gt;part 1&lt;/a&gt; of the posting, there can be three properties: regex, description and exclude.&amp;nbsp; The java processing to read the file and create the list of RegExDescriptors was located in two steps: the first was to read the file into a &lt;i&gt;Properties &lt;/i&gt;object and then call the &lt;i&gt;setDescriptors&lt;/i&gt; method in the &lt;i&gt;Validator &lt;/i&gt;class as part of the main method called by Ant.&lt;br /&gt;
&lt;br /&gt;
The idea is to group the properties together by the extension and the number that is part of the key.  Each matching set is used to construct the RegExDescriptor.&amp;nbsp; The RegExDescriptor creates a &lt;i&gt;Pattern &lt;/i&gt;for the regular expression checking for the error and another for the file name exclusion check.&amp;nbsp; The patterns are compiled at construction time.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;props.load(new FileInputStream(propertyFile));
setDescriptors();

// later in Validator
/*
     * Setup the regular expression descriptors 
     * using the extension to determine which properties
     * are to be used when validating the files.
     */
    private void setDescriptors()
    {
        // strip the leading . and add one to end
        String prefix = extension;
        char c = extension.charAt(0);
        if (c == '.')
            prefix = prefix.substring(1);
        prefix = prefix + ".";
        
        int idx = 1;
        boolean done = false;
        
        // build list of validators using the extension to create the property keys
        while(!done) {
            String regexKey = prefix + idx + REGEX;
            if (props.containsKey(regexKey)) {
                String descriptionKey = prefix + idx + DESCRIPTION;
                String excludeKey = prefix + idx + EXCLUDE;
                try {
                    idx++;
                    String exclude = props.getProperty(excludeKey, DEFAULT_EXCLUDE);
                    descriptors.add( new RegExDescriptor(props.getProperty(regexKey),
                                                       props.getProperty(descriptionKey),
                                                       exclude) ); 
                } catch (PatternSyntaxException e) {
                    StringBuffer sb = new StringBuffer(100);
                    sb.append("Exception compiling regular expression key(").append(regexKey);
                    sb.append(") :").append(props.getProperty(regexKey)).append("\n").append(e);
                    sb.append("\nSkipping this expression...\n");
                    log(sb.toString());
                }
            } else {
                done = true;
            }
        }
    }
&lt;/pre&gt;&lt;b&gt; &lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
Now for the Groovy implementation.&amp;nbsp; It starts out the same, loading a &lt;i&gt;Properties &lt;/i&gt;object.&amp;nbsp; Next, we use the &lt;a href="http://groovy.codehaus.org/gapi/groovy/util/ConfigSlurper.html"&gt;ConfigSlurper &lt;/a&gt;class to group and parse the properties.&amp;nbsp; An empty list to hold the descriptors is defined and then we iterate across the extension (sql in my case) keys and build the new &lt;i&gt;ValidatorDescriptor &lt;/i&gt;objects.  Notice the use of the GString aware string as part of the key for calling the each closure.&lt;br /&gt;
&amp;nbsp; &lt;br /&gt;
&lt;pre class="brush:groovy"&gt;Properties properties = new Properties();
  try {
     properties.load(new FileInputStream('validator.properties'));
  } catch (IOException e) {}

  def config = new ConfigSlurper().parse(properties)
  def descriptorList = []
  config."$extension".each {
     descriptorList &amp;lt;&amp;lt; new ValidatorDescriptor(it.value)
  }
&lt;/pre&gt;&lt;br /&gt;
In the next (and last) posting in this series, we will cover the following:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Replace the FileValidator class&lt;/li&gt;
&lt;li&gt;Using the HTML Builder to generate a report&lt;/li&gt;
&lt;li&gt;Complete listing of the script and classes&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-7988869346073663085?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/d5Wtdt1Nvp0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/7988869346073663085/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2009/12/ant-task-ported-to-groovy-part-2.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/7988869346073663085?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/7988869346073663085?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/d5Wtdt1Nvp0/ant-task-ported-to-groovy-part-2.html" title="Ant task ported to Groovy - Part 2" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2009/12/ant-task-ported-to-groovy-part-2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIFQno7fip7ImA9WxBSFEg.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-5361428813635446182</id><published>2009-12-14T22:10:00.002-06:00</published><updated>2009-12-21T22:35:13.406-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-21T22:35:13.406-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groovy Java Ant Validator" /><title>Java Ant task ported to Groovy - Part 1</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/LFjNFfFlQGvgW-CQnotDiMIoUXw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LFjNFfFlQGvgW-CQnotDiMIoUXw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/LFjNFfFlQGvgW-CQnotDiMIoUXw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LFjNFfFlQGvgW-CQnotDiMIoUXw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;After reading one of &lt;a href="http://mrhaki.blogspot.com/2009/11/groovy-goodness-finding-files-with.html"&gt;Mr. Haki's recent posts&lt;/a&gt;, it reminded me of an Ant task that I had written a couple of years ago that we use in our nightly build.  I started thinking about how much shorter and concise the code would be if written in Groovy. &amp;nbsp;Rather than doing it all in one large posting, I have decided to break it out into 2 or 3 posts and will include all the final Groovy code in the last posting.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Ant task: Validator&lt;/b&gt;&lt;br /&gt;
Our product supports several different databases and while can you generally code SQL to the 'lowest common&amp;nbsp;denominator" for a lot of statements, we were encountering problems with our 'upgrade' scripts mostly due to syntax that was more&amp;nbsp;lenient in Oracle and SQLServer but more restrictive in MySQL.&amp;nbsp;&amp;nbsp; Since the update scripts are not run every day/night, I came up with the idea of using some regular expressions to try and catch these errors as early in the cycle as possible, which is the scheduled nightly build.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:xml"&gt;&lt;target name="validator"&gt;
    &lt;taskdef classname="Validator" classpathref="test.classpath" name="validator"&gt;
    &lt;validator directory="${validate.dir}" extension=".sql"  propertyfile="${validate.dir}\validator.properties" reportfile="${validate.dir}\validator.html"&gt; 
&lt;/validator&gt;
&lt;/taskdef&gt;
&lt;/target&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Inputs &amp;amp; Outputs&lt;/b&gt;&lt;br /&gt;
The validator task takes three input parameters and one output parameters.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Inputs&lt;/i&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;extension - the extension for the file types to be validated&lt;/li&gt;
&lt;li&gt;directory - the directory from which to start checking files&lt;/li&gt;
&lt;li&gt;propertyFile- a properties file containing sets of properties for each validation to be performed&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;i&gt;Outputs&lt;/i&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;reportFile - name of the output html file to be created with the results of the validation&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;b&gt;Java implementation&amp;nbsp;&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The java implementation of this tasks consists of 3 classes. &amp;nbsp;The first class, &lt;i&gt;Validator&lt;/i&gt;, handles the Ant processing, loads the property file into a list of objects, &lt;i&gt;RegExDescriptors&lt;/i&gt;, contains a main loop to visit all directories and files starting at the directory parameter and lastly, writes an output report. &amp;nbsp; The second class, &lt;i&gt;FileValidator&lt;/i&gt;, validates each file line-by-line and records any 'matches' against the regular expressions that represent an error in the SQL runtime syntax. &amp;nbsp;Lastly, property settings are grouped together into a &lt;i&gt;RegExDescriptor&lt;/i&gt;, that contains the description of the error being validated, the regular expression used to 'match' the error and an exclusion regular expression, which is used to exclude some files from some tests. For example, Oracle scripts using the '&lt;i&gt;nvarchar&lt;/i&gt;' data type would be an error so we only want to run that validation against Oracle scripts and not against the SQLServer or MySQL scripts.&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Sample property file&lt;/b&gt;&lt;br /&gt;
This is a sample file containing some of the regular expressions currently being used. &amp;nbsp; These are subject to change since, in some cases, backward slash had to be escaped in the pattern, like the last example sql.3.regex.&lt;b&gt; &lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;pre class="brush:text"&gt;#################################################################
#
# SQL file regular expressions
#
#################################################################

#
# Instances of lines starting with GO
#
sql.1.regex=^GO
sql.1.description=GO statement

#
# Oracle scripts using nvarchar
#
sql.2.regex=nvarchar
sql.2.description=Oracle scripts using nvarchar
sql.2.exclude=SQLServer|MySQL|Store Update

#
# MySQL scripts using ntext
#
sql.3.regex=\\sntext
sql.3.description=MySQL scripts using ntext data type
sql.3.exclude=SQLServer|Oracle

&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Minor limitation&lt;/b&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;One minor limitation of this tool is that it only works on a single line at a time. &amp;nbsp;SQL statements that are longer than a single line are not validated as one SQL statement but simply as lines of text. &amp;nbsp;This has not been a problem as you can see from the sample validations listed above. &amp;nbsp;The errors we try to catch are a mixture of syntax and runtime errors we have encountered.&lt;br /&gt;
&lt;br /&gt;
Additionally, this will not be a 'exact' port, meaning, it will not be an Ant/Gant task, but merely a Groovy script, which could then easily be converted for use in those tools. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Port to Groovy&amp;nbsp;&lt;/b&gt;&lt;br /&gt;
The first part of the port is easy - replacing all the code that recursively starts at a specified directory and creates a list of files matching the extension provided.  First the Java version:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;/*
     * Process all files and directories under dir
     */ 
    private void visitAllDirsAndFiles(File dir) {
        process(dir);
    
        if (dir.isDirectory()) {
            FileFilter fileFilter = new FileFilter() {
                public boolean accept(File file) {
                    return file.isDirectory() || file.getName().endsWith(extension);
                } };
            
            File[] children = dir.listFiles(fileFilter);
            for (int i=0; i&amp;lt;children.length; i++) {
                visitAllDirsAndFiles(children[i]);
            }
        }
&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
Now the Groovy version&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;def sqlFiles = new FileNameFinder().getFileNames(dir', '**/*.sql')
&lt;/pre&gt;Notice the Ant-like "**/*" prefix for the extension.  Groovy does all the work and returns a list of files matching the criteria!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Upcoming&amp;nbsp; &lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;In Part 2&lt;br /&gt;
&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Using the CliBuilder for a command line interface (instead of Ant)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;ValidatorDescriptor as a replacement for RegExDescriptor&lt;/li&gt;
&lt;li&gt;Consuming the property file&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;In Part 3&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Using the HTML Builder to generate a report&lt;/li&gt;
&lt;li&gt;Complete listing of the script and classes&lt;/li&gt;
&lt;li&gt;Replace the FileValidator class&lt;/li&gt;
&lt;/ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-5361428813635446182?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/Dfz-KsOV3C4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/5361428813635446182/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2009/12/java-ant-task-ported-to-groovy-part-1.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5361428813635446182?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5361428813635446182?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/Dfz-KsOV3C4/java-ant-task-ported-to-groovy-part-1.html" title="Java Ant task ported to Groovy - Part 1" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2009/12/java-ant-task-ported-to-groovy-part-1.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU8ASH47eCp7ImA9WxNXGEU.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-7899383684103301334</id><published>2009-10-06T22:48:00.005-05:00</published><updated>2009-10-06T22:57:29.000-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-06T22:57:29.000-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Grails Groovy Spring databinding" /><title>Data binding for one-to-many association - part 2 (improved)</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/cj0vtWll_qfN9KN_TY1E17TdhG4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/cj0vtWll_qfN9KN_TY1E17TdhG4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/cj0vtWll_qfN9KN_TY1E17TdhG4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/cj0vtWll_qfN9KN_TY1E17TdhG4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;b&gt;Improving on the solution...&lt;/b&gt;&lt;br /&gt;
In a &lt;a href="http://programmingitch.blogspot.com/2009/09/example-grails-data-binding-for-one-to.html"&gt;previous posting&lt;/a&gt;, I wrote a small sample of how to handle the data binding for a one-to-many association.&amp;nbsp; While my approach worked, I had a couple nagging issues that I had to resolve.&amp;nbsp; One, based on the code,&amp;nbsp; the form field names and the way Groovy builds the map of request parameters,&amp;nbsp; I had some questions about combining the &lt;i&gt;bindData()&lt;/i&gt; method along with also doing &lt;i&gt;objectInstance.properties = properties&lt;/i&gt;.&amp;nbsp; Two, I had this nagging feeling that this could be handle better.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Issue 1&lt;/b&gt;&lt;br /&gt;
Based on the naming of the form fields that represent objects in the collection, these fields actually appear twice in the params map.&amp;nbsp; Field &lt;i&gt;addresses[0].street&lt;/i&gt; appears in the params map with a key=&lt;i&gt;addresses[0].street &lt;/i&gt;and it also appears in a map within the params map with a key=&lt;i&gt;addresses[0].&amp;nbsp; &lt;/i&gt;This 'sub-map' contains all of the fields of the &lt;i&gt;Address &lt;/i&gt;object.&amp;nbsp; My example used this 'sub-map' when calling the &lt;i&gt;bindData()&lt;/i&gt; method.&amp;nbsp; This all works fine.&amp;nbsp; After completing the iteration across the &lt;i&gt;addresses[x]&lt;/i&gt; sub-map entries within the params map, the last statement in the controller was &lt;i&gt;personInstance.properties = params&amp;nbsp; &lt;/i&gt;which then handles the binding for &lt;b&gt;ALL&lt;/b&gt; the form fields, including the &lt;i&gt;addresses[0].state&lt;/i&gt; field.&amp;nbsp; This means that I was actually binding the association data twice!&amp;nbsp; Using the debugger in Eclispe, I was easily able to verify this.&lt;br /&gt;
&lt;br /&gt;
Below is the output of printing the contents of the &lt;i&gt;params &lt;/i&gt;object after posting to the &lt;i&gt;PersonController&lt;/i&gt;.&amp;nbsp; The fifth line shows an example of the 'sub-maps' that I mention.&lt;br /&gt;
&lt;pre&gt;[
addresses[2].city:Arlington, 
lastName:Miller, 
addresses[0].city:Flower Mound, 
addresses[1].zip:66666, 
addresses[0]:[zip:75022, street:1 Main Street, city:Flower Mound], 
addresses[1]:[zip:66666, street:99 Palm Beach Circle, city:Palm Beach], 
addresses[0].zip:75022, 
addresses[2]:[zip:75066,street:1234 Cowboy Way, city:Arlington ], 
addresses[2].zip:75066, 
addrCount:3, 
addresses[0].street:1 Main Street, 
action:save, 
addresses[2].street:1234 Cowboy Way, 
controller:person,
addresses[1].city:Palm Beach,
firstName:Mike, 
addresses[1].street:99 Palm Beach Circle
] 
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Issue 2&lt;/b&gt;&lt;br /&gt;
That nagging feeling just wouldn't go away.&amp;nbsp; I believed that there had to be a better way and I could swear I actually read about another option.&amp;nbsp; This isn't really a Grails issue, but more a Spring data binding issue, so with the right set of search terms, my Google searches found what I was looking for (and had actually read before).&amp;nbsp; Matt Fleming has written an&lt;a href="http://mattfleming.com/node/134"&gt; initial posting&lt;/a&gt; and then a &lt;a href="http://mattfleming.com/node/235"&gt;followup &lt;/a&gt;on this subject so you can read more there.&amp;nbsp; Short answer: define the list as a LazyList which knows what data type to create when it actually does add elements to the list.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Initial Problem&lt;/b&gt;&lt;br /&gt;
The initial problem encountered was a NullPointerException because the collection was not initialized with the correct number and type of entries.&amp;nbsp;&amp;nbsp; My sample solution handled that by creating the &lt;i&gt;Person &lt;/i&gt;object first, which contains an empty list.&amp;nbsp;&amp;nbsp;  Then it created each of the &lt;i&gt;Address &lt;/i&gt;objects and added those to the list.&amp;nbsp; Lastly, we did the binding using the whole &lt;i&gt;params &lt;/i&gt;map.&lt;br /&gt;
&lt;br /&gt;
Using Matt's solution, you can see the updated &lt;i&gt;Person &lt;/i&gt;object below using the LazyList and defining the collection type to &lt;i&gt;Address&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;import org.apache.commons.collections.FactoryUtils
import org.apache.commons.collections.list.LazyList

class Person {

    static hasMany = [addresses:Address]
    
    static constraints = {
    }
    
    Person() {
        //addresses = []
    }
    
    String firstName
    String lastName
    List
&lt;address&gt;addresses = LazyList.decorate(
                                  new ArrayList(),
                                  FactoryUtils.instantiateFactory(Address.class));
    
    String toString()  {
        firstName + " " + lastName + " Addresses:"+addresses
    }
}
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
The updated controller code is shown below.&amp;nbsp;&amp;nbsp; No reason to call the &lt;i&gt;bindPerson(params)&lt;/i&gt;, we just create the Person object with the &lt;i&gt;params &lt;/i&gt;map and Grails &amp;amp; Spring do the rest!&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;def save = {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //def personInstance = bindPerson(params)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; def personInstance = new Person(params)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(!personInstance.hasErrors() &amp;amp;&amp;amp; personInstance.save()) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; flash.message = "Person ${personInstance.id} created"
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; redirect(action:show,id:personInstance.id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; render(view:'create',model:[personInstance:personInstance])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-7899383684103301334?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/PbbEabpOjHM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/7899383684103301334/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2009/10/data-binding-for-one-to-many.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/7899383684103301334?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/7899383684103301334?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/PbbEabpOjHM/data-binding-for-one-to-many.html" title="Data binding for one-to-many association - part 2 (improved)" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2009/10/data-binding-for-one-to-many.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEICQHg-fip7ImA9WxNXEkU.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-6863344725492145602</id><published>2009-09-29T22:49:00.000-05:00</published><updated>2009-09-29T22:49:21.656-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-29T22:49:21.656-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JMS ExceptionListener Java" /><title>Client needs to help ensure 'guaranteed delivery' with JMS</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/bhL9GVOZ-rdY4LzXTkDs7ZGS3kc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/bhL9GVOZ-rdY4LzXTkDs7ZGS3kc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/bhL9GVOZ-rdY4LzXTkDs7ZGS3kc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/bhL9GVOZ-rdY4LzXTkDs7ZGS3kc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;We recently received a new defect report claiming that some of our data was not being distributed correctly through JMS.   Actually some of the data was not being distributed at all!&amp;nbsp; That's the first time we have heard that complaint - hey, JMS is &lt;i&gt;guaranteed delivery&lt;/i&gt;, right?&amp;nbsp; Well not so fast...&lt;br /&gt;
&lt;br /&gt;
Apparently we had a 'slow leak' in our connection pool within JBoss MQ.&amp;nbsp; After a few days of uptime, the server seemed to stop distributing some of our data.&amp;nbsp; The problem helped expose a deficiency in our JMS client code.&amp;nbsp; We had not registered an &lt;a href="http://java.sun.com/j2ee/1.4/docs/api/javax/jms/ExceptionListener.html"&gt;ExceptionListener &lt;/a&gt;with our &lt;a href="http://java.sun.com/j2ee/1.4/docs/api/javax/jms/Connection.html"&gt;Connection &lt;/a&gt;object and as a result, we were not notified of problems creating a new Connection.&amp;nbsp; I don't know about everyone else but most of the JMS sample client code that I have seen hasn't registered an ExceptionListener so that interface was news to me. &amp;nbsp; Oh well, another learning experience!&lt;br /&gt;
&lt;br /&gt;
So... JMS &lt;i&gt;guaranteed delivery&lt;/i&gt;  requires some assistance from the client as well, to help handle connection errors.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-6863344725492145602?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/uB9xRLNKWKY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/6863344725492145602/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2009/09/client-needs-to-help-ensure-guaranteed.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/6863344725492145602?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/6863344725492145602?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/uB9xRLNKWKY/client-needs-to-help-ensure-guaranteed.html" title="Client needs to help ensure 'guaranteed delivery' with JMS" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2009/09/client-needs-to-help-ensure-guaranteed.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MCSXc5eyp7ImA9WxNXEEs.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-5314000490682281460</id><published>2009-09-24T22:59:00.004-05:00</published><updated>2009-09-27T11:37:48.923-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-27T11:37:48.923-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groovy HTTPBuilder RESTClient" /><title>Using HTTPBuilder to call a RESTful web service</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/uB8xz1mFhTnbuqidftPMgtQvOqI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uB8xz1mFhTnbuqidftPMgtQvOqI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/uB8xz1mFhTnbuqidftPMgtQvOqI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uB8xz1mFhTnbuqidftPMgtQvOqI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;Our team is delivering a new RESTful web service and so I figured that I would  &lt;i&gt;scratch my Grails itch&lt;/i&gt; and create a small  application for testing the new web service.&amp;nbsp;&amp;nbsp;&lt;a href="http://groovy.codehaus.org/modules/http-builder/doc/rest.html"&gt; RESTClient&lt;/a&gt; looked like it would be a great match and it would be  except that I want to display the XML request being passed to the service as well as the  XML response returned from the service.&lt;b&gt;&amp;nbsp;&amp;nbsp; &lt;/b&gt;Displaying the XML request is not a problem.&amp;nbsp; The problem is that RESTClient automatically parses the response data and returns a &lt;a href="http://groovy.codehaus.org/api/groovy/util/slurpersupport/GPathResult.html"&gt;GPathResult&lt;/a&gt; &lt;a href="http://groovy.codehaus.org/api/groovy/util/slurpersupport/NodeChild.html"&gt;NodeChild&lt;/a&gt; object. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt; &lt;/b&gt;After reviewing the documentation for RESTClient and exchanging some emails with the RESTClient developer, he made the suggestion of using&lt;a href="http://groovy.codehaus.org/modules/http-builder/home.html"&gt; HTTPBuilder&lt;/a&gt; instead of RESTClient.&amp;nbsp; The code shown below is the call to HTTPBuilder to call the new service. This topic came up in another posting and you can see an alternative approach &lt;a href="http://agileice.blogspot.com/2009/08/groovy-restclient-httpbuilder-and-put.html"&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Points to notice&lt;/b&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;The second parameter to HTTPBuilder&amp;nbsp; is setting the default content type to TEXT.&lt;/li&gt;
&lt;li&gt;The request sets the Accept header to 'application/xml'.&lt;/li&gt;
&lt;li&gt;HTTPBuilder.RequestConfigDelegate send method sets the content type to XML&lt;/li&gt;
&lt;li&gt;Success handler gets response from 'reader.text' and then &lt;a href="http://stackoverflow.com/questions/231677/best-way-to-pretty-print-xml-response-in-grails"&gt;pretty-prints&lt;/a&gt; the result back in to a String for easy display.&amp;nbsp; &lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;def txnCreate(TransactionSpec txnSpec, String userid, String pswd) {

        def conf = Configuration.get(3)
        if (conf != null) {
           def ppos = new HTTPBuilder( conf.protocol+"//"+conf.server+":"+conf.port, TEXT )
           ppos.headers = [Accept:'application/xml', 'ppos-user':userid, 'ppos-pswd':pswd]
           
           try {
             ppos.request( PUT ) {
                   uri.path = conf.context + conf.url
                   send( XML ) {
                    TransactionSpec (training:txnSpec.training) {
                        delegate.transClassName txnSpec.transClassName
                        delegate.locationNumber txnSpec.locationNumber
                        delegate.currencyCode txnSpec.currencyCode
                        AssociateSpec {
                            delegate.associateNumber txnSpec.associateSpec.associateNumber 
                        }
                        delegate.terminalName txnSpec.terminalName
                        LineItemSpecs {
                            for (item in txnSpec.lineItemSpecs) {
                                LineItemSpec {
                                    sku(item.sku)
                                    quantity(item.quantity)
                                }
                            }
                        }
                        TenderSpecs {
                            for (tender in txnSpec.tenderSpecs) {
                                TenderSpec {
                                    tenderCode(tender.tenderCode)
                                    cardNumber(tender.cardNumber)
                                    expiryDate(tender.expiryDate)
                                    track1Data(tender.track1Data)
                                    track2Data(tender.track2Data)
                                    track3Data(tender.track3Data)
                                    preLockNumber(tender.preLockNumber)
                                    preLockAmount(tender.preLockAmount)
                                    amount(tender.amount)
                                    precision(tender.precision)
                                }
                            }
                        }
                     }   
                   }
                   // success handler
                   response.success = { resp, reader -&amp;gt;
                        // pretty print format the response
                        def stringWriter = new StringWriter()
                        def node = new XmlParser().parseText(reader.text);
                        new XmlNodePrinter(new PrintWriter(stringWriter)).print(node)
                        return stringWriter.toString()
                   }
                   // failure handler
                   response.failure = { resp -&amp;gt;
                      return 'Response status='+resp.status
                   }
             }
           } catch(Exception e) {
               log.error("Caught exception:", e)
               return e.toString()
           }
        }
    }
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-5314000490682281460?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/5Vd9dhJY9YA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/5314000490682281460/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2009/09/using-httpbuilder-to-call-restful-web.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5314000490682281460?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5314000490682281460?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/5Vd9dhJY9YA/using-httpbuilder-to-call-restful-web.html" title="Using HTTPBuilder to call a RESTful web service" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2009/09/using-httpbuilder-to-call-restful-web.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIDQn0zeyp7ImA9WxNQEkk.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-5444987405407536868</id><published>2009-09-17T21:56:00.000-05:00</published><updated>2009-09-17T21:56:13.383-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-17T21:56:13.383-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="blogger template" /><title>Blogger Minima template wastes space</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FHzRvjjsTM3dYH9T6mpveUxJZac/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FHzRvjjsTM3dYH9T6mpveUxJZac/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FHzRvjjsTM3dYH9T6mpveUxJZac/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FHzRvjjsTM3dYH9T6mpveUxJZac/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;I just recently started blogging and so I am trying to figure out what looks good and how to get my blog to look better.&amp;nbsp;&amp;nbsp; I choose the Minima template but noticed that the 'gutters' seemed too wide down the left and right side of the page.&amp;nbsp; Postings with code seemed to caused a lot of the line to wrap and it just didn't look very good. After seeing some other blogs that didn't appear to have that problem, I posted comments asking, "How'd you do that?". &amp;nbsp; Someone suggested adjusting the template and so I took his advice. &amp;nbsp; Below is a just a couple minor tweaks I made to the template and the code examples look much better and the gutters are not nearly so wide!&lt;br /&gt;
&lt;br /&gt;
This all coming from a developer who has spent most of his career in the middle-tier and server-side of applications.&amp;nbsp;&amp;nbsp; For those of you very familiar with CSS, you can probably stop reading NOW.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Updating the Minima template to increase the posting area&lt;/b&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Go to Layout --&amp;gt; Edit HTML page&lt;/li&gt;
&lt;li&gt;Click the 'download template' link to make a backup copy of your template, for safe keeping&lt;/li&gt;
&lt;li&gt;In the editable textarea, make the following changes to the style sheet entries:&amp;nbsp;&lt;/li&gt;

&lt;ul&gt;&lt;li&gt;outer-wrapper width change from 660px to 1000px,&amp;nbsp;&lt;/li&gt;
&lt;li&gt;main-wrapper width change from 410px to 700px&amp;nbsp;&lt;/li&gt;
&lt;li&gt;footer width change from&amp;nbsp; 660px to 1000p&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Click the 'preview' button to see the changes&lt;/li&gt;
&lt;li&gt;If you are happy with the new spacings, click the 'save template' button.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-5444987405407536868?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/uCIjySIZ-kM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/5444987405407536868/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2009/09/blogger-minima-template-wastes-space.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5444987405407536868?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/5444987405407536868?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/uCIjySIZ-kM/blogger-minima-template-wastes-space.html" title="Blogger Minima template wastes space" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2009/09/blogger-minima-template-wastes-space.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8HRXY_fip7ImA9Wx9RFk0.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-6603924400760994823</id><published>2009-09-16T22:45:00.008-05:00</published><updated>2010-12-17T09:47:14.846-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-17T09:47:14.846-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails groovy databinding" /><title>Example Grails data binding for one-to-many association</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Wsi6ZEyOyPtiPpHlCcCkxbJwqVI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Wsi6ZEyOyPtiPpHlCcCkxbJwqVI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Wsi6ZEyOyPtiPpHlCcCkxbJwqVI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Wsi6ZEyOyPtiPpHlCcCkxbJwqVI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;Data binding is an integral aspect of all web applications.&amp;nbsp; The responsibility for the data binding generally falls within the scope of the controller.&amp;nbsp; In this following example,&amp;nbsp; I will show all the '&lt;i&gt;moving parts&lt;/i&gt;' that are needed to easily bind a domain object with a one-to-many association within Grails.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
I looked around for a simple example of data binding to handle a one-to-many association and never really found a full example so I decided to create an example and share it.&amp;nbsp; The example uses a Person domain object with a one-to-many association of Address objects.&amp;nbsp;&amp;nbsp; All of the data is captured on a single screen. &amp;nbsp; The example uses DHTML or Dom scripting to dynamically create multiple address form fields and submits all the data from one screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Domain objects: Person &amp;amp; Address&lt;/b&gt;&lt;br /&gt;
The Person constructor contains just a first and last name.&amp;nbsp;   Notice the Address field implements Serializable and also implements the&lt;i&gt; hashCode()&lt;/i&gt; and &lt;i&gt;equals() &lt;/i&gt;methods as required for objects that are to be placed in a collection.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;class Person {
    static hasMany = [addresses:Address]
    static constraints = {
    }
    
    Person() {
        addresses = []
    }
    
    String firstName
    String lastName
    List&amp;lt;Address&amp;gt; addresses
    
    String toString()  {
        firstName + " " + lastName + " Addresses: "+addresses
    }
    
}


class Address implements Serializable {
    static constraints = {
    }
    
    String street
    String city
    String zip
    
    String toString() {
        street + "\n" + city + ", " + zip
    }
    
    int hashCode() {
        street?.hashCode() + city?.hashCode() + zip?.hashCode()
    }
    
    boolean equals(o) {
        if (this.is(o)) return true
        if (!(o instanceof Address)) return false
        return street?.equals(o.street) &amp;amp;&amp;amp; (city?.equals(o.city)) &amp;amp;&amp;amp; (zip?.equals(o.zip))
    }    
}
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Sample screen shot of create person screen&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
Below is a snapshot of a the create.gsp screen after clicking the 'Add Address' button twice and filling in the data.&amp;nbsp; The 'Add Address' button calls a javascript function (see further below) to create an additional address row in the address table.&amp;nbsp; (I wanted to provide the entire page .gsp source but could not get it formatted correctly - if anyone has suggestions, I would appreciate hearing from you.) &amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_JAJdxIvTyzE/SrGige687NI/AAAAAAAAATY/3kWEahd74cE/s1600-h/createperson.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_JAJdxIvTyzE/SrGige687NI/AAAAAAAAATY/3kWEahd74cE/s400/createperson.JPG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;b&gt;Add Address javascript function&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
Below is the javascript function called from the 'Add Address' button on the form.&amp;nbsp; The important part here is that use of the hidden field, &lt;b&gt;addrCount&lt;/b&gt;, to add an index to the address form field names and ids.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:javascript&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; &amp;lt;script language=" javascript=""&gt;function addAddr(tblId)
{&lt;a href="https://sites.google.com/site/mikesgroovystuff/"&gt;
&amp;nbsp; var tblBody = document.getElementById(tblId).tBodies[0];
&amp;nbsp; var newNode = tblBody.rows[0].cloneNode(true);
&amp;nbsp; var count = parseInt(document.getElementById("addrCount").value);
&amp;nbsp; count++;
&amp;nbsp; document.getElementById("addrCount").value = count;
&amp;nbsp; var cells = newNode.cells;
&amp;nbsp; for (var i=0; i&lt;cells.length; i++)="" {=""&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (cells[i].firstElementChild.id.indexOf("street") &lt;/cells.length;&gt;&lt;/a&gt;!= -1) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cells[i].firstElementChild.id = "addresses["+(count-1)+"].street";
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cells[i].firstElementChild.name = "addresses["+(count-1)+"].street";
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else if (cells[i].firstElementChild.id.indexOf("city") != -1) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cells[i].firstElementChild.id = "addresses["+(count-1)+"].city";
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cells[i].firstElementChild.name = "addresses["+(count-1)+"].city";
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else if (cells[i].firstElementChild.id.indexOf("zip") != -1) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cells[i].firstElementChild.id = "addresses["+(count-1)+"].zip";
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cells[i].firstElementChild.name = "addresses["+(count-1)+"].zip";
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&amp;nbsp; }
&amp;nbsp; tblBody.appendChild(newNode);
}&amp;nbsp;&lt;/pre&gt;&lt;pre class="brush:javascript&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; &amp;lt;script language=" javascript=""&gt;&lt;cells.length; i++)="" {=""&gt; 
&lt;/cells.length;&gt;&lt;/pre&gt;&lt;pre class="brush:javascript&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; &amp;lt;script language=" javascript=""&gt;&lt;cells.length; i++)="" {=""&gt;Here is the initial statement for the hidden addrCount index field.&lt;/cells.length;&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre class="brush:xml"&gt;&amp;lt;g:hiddenField name="addrCount"&amp;nbsp;&amp;nbsp; value="1" /&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;b&gt;PersonController&lt;/b&gt;&lt;br /&gt;
When the form is submitted, the save action is called.&amp;nbsp; I have created a helper method, bindPerson(), to handle the data binding.&amp;nbsp; The method iterates 'addrCount' times, creating a new Address object, calling the bindData() method provided by Grails with the params starting with the value 'addresses[i]'.&amp;nbsp; Lastly, the address is added to the collection and the Person object is returned.&lt;br /&gt;
&lt;br /&gt;
The controller code below works party because my constructor for the Person object initializes the addresses field to an empty list. &amp;nbsp; Other options might be to create a list in the controller and then set the addresses field to that list, or keep the initialized list and call &lt;i&gt;personInstance.addToAddresses(addr). &lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;class PersonController

  def save = {
        def personInstance = bindPerson(params)
        if(!personInstance.hasErrors() &amp;amp;&amp;amp; personInstance.save()) {
            flash.message = "Person ${personInstance.id} created"
            redirect(action:show,id:personInstance.id)
        }
        else {
            render(view:'create',model:[personInstance:personInstance])
        }
    }
    
    def Person bindPerson(params)  {
        def personInstance = new Person()
        def count = params.addrCount.toInteger()
        for (int i=0; i&amp;lt;count; i++) {
            def addr = new Address()
            bindData(addr, params["addresses["+i+"]"])
            personInstance.addresses[i] = addr
        }
        personInstance.properties = params  
        return personInstance
    }&amp;nbsp;&lt;/pre&gt;&lt;pre class="brush:groovy"&gt;&amp;nbsp;&lt;/pre&gt;&lt;b&gt;Results&lt;/b&gt;&lt;br /&gt;
Here you see the results on the show.gsp screen.&lt;br /&gt;
&lt;b&gt; &lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_JAJdxIvTyzE/SrGjAdLKRMI/AAAAAAAAATg/pL9YMEhTLtQ/s1600-h/showperson.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_JAJdxIvTyzE/SrGjAdLKRMI/AAAAAAAAATg/pL9YMEhTLtQ/s400/showperson.JPG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;Wrap up:&lt;/b&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;First you need to setup your domain objects, including implementing Serialization, hashCode() and equals(),&amp;nbsp; where required.&lt;/li&gt;
&lt;li&gt;Form fields need to be name using index, like addresses[0].city or addresses[3].zip&lt;/li&gt;
&lt;li&gt;Finally, the controller needs to bind the association data using the indexed fields.&lt;/li&gt;
&lt;/ol&gt;&lt;b&gt;Note:&lt;/b&gt;&amp;nbsp; After writing this up, I finally realized why my  Address object looked strange, it is missing a field for state.&amp;nbsp; While important for a correct Address object, it isn't absolutely necessary for this example, so I decided not to go back and add it in. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Note:&lt;/b&gt; &lt;b&gt;Please see an improved solution in &lt;a href="http://programmingitch.blogspot.com/2009/10/data-binding-for-one-to-many.html"&gt;Part 2 &lt;/a&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I hope this helps and as always, constructive criticism is appreciated!  Due to the large number of requests, I have created a site over at Groovy sites and you should be able to download from &lt;a href="https://sites.google.com/site/mikesgroovystuff/"&gt;here&lt;/a&gt;.&amp;nbsp; Download site is &lt;a href="https://sites.google.com/site/mikesgroovystuff/"&gt;https://sites.google.com/site/mikesgroovystuff/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-6603924400760994823?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/P0fqCg2XXII" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/6603924400760994823/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2009/09/example-grails-data-binding-for-one-to.html#comment-form" title="26 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/6603924400760994823?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/6603924400760994823?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/P0fqCg2XXII/example-grails-data-binding-for-one-to.html" title="Example Grails data binding for one-to-many association" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_JAJdxIvTyzE/SrGige687NI/AAAAAAAAATY/3kWEahd74cE/s72-c/createperson.JPG" height="72" width="72" /><thr:total>26</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2009/09/example-grails-data-binding-for-one-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYBRnc9fCp7ImA9WxNREks.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-8245903357213260498</id><published>2009-08-30T22:44:00.004-05:00</published><updated>2009-09-06T13:02:37.964-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-06T13:02:37.964-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Groovy" /><title>Simple Groovy mistake had me wondering what the heck was going on!</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/SPmFHf5_SqZyb4UIVqMrJyh7c2U/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SPmFHf5_SqZyb4UIVqMrJyh7c2U/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/SPmFHf5_SqZyb4UIVqMrJyh7c2U/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SPmFHf5_SqZyb4UIVqMrJyh7c2U/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;While 'scatching my programming itch' late one night last week, I made a small mistake which didn't present itself until runtime.&amp;nbsp;&amp;nbsp; When it did occur, it made we wonder what the heck was happening.&amp;nbsp; After fixing my mistake,&amp;nbsp; I just had to figure out what was really happening.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Minor background for readers new to Groovy:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Groovy provides language support to make the routine tasks on collection types easier than Java programmers are used to.&amp;nbsp; For example, creating a map is as easy as:&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;def map = [key1:valueX, key2:valueY]
&lt;/pre&gt;which creates a map with two entries: key1 maps to valueX and key2 maps to valueY.  The fun starts with the many ways of accessing the maps data.  The following are all valid ways of retrieving valueX from the map:&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;def value = map.get('key1')
def value = map['key1']
def value = map.key1
&lt;/pre&gt;&lt;br /&gt;
The first example looks just like Java.  The second and third examples are provided by the Groovy language.  Now, on to the mistake.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Can you guess what happens?&lt;/b&gt;&lt;br /&gt;
I have created a very small subset of the code to show the bug.&amp;nbsp; The actual code resides in a Grails controller method that gets invoked on a form submission.&amp;nbsp;&amp;nbsp; In the submitted form, I use DOM scripting to dynamically create multiple line items for a transaction. &lt;br /&gt;
&lt;br /&gt;
Take a look at the excerpt below and see if you can tell what happens when it executes.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;def params = [itemCount:'3']&amp;nbsp; // this was really form data submitted
for (int i=0; i&amp;lt;params.itemCount; i++)
    def lineItem = new LineItem()
    bindData(lineItem, params["lineItem["+i+"]"])
    transactionInstance.lineItem[i] = lineItem
}
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Anyone see the error?&lt;/b&gt;&lt;br /&gt;
The for loop looped about 10-12 times and then stop even though there were only 3 lineItems submitted on the form.&amp;nbsp; Other times, the loop ran forever.&amp;nbsp; The problem: the value of the itemCount entry is a String and not a Integer, which resulted in a strange comparison (more on that later). &amp;nbsp; The fix was easy, convert the String to an Integer. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;def count = params.itemCount.toInteger()
for (int i=0; i&amp;lt;count; i++)&lt;/pre&gt;&lt;br /&gt;
But why did the loop behave the way it did?&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Operator overload for &amp;lt; (less than)&lt;/b&gt;&lt;br /&gt;
The next step is to figure out what Groovy's doing.&amp;nbsp;&amp;nbsp; The operator &amp;lt;&amp;nbsp; is basically doing a comparison, so what happens when you try either of the following:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;i.compareTo(params.itemCount)
params.itemCount.compareTo(i) 
&lt;/pre&gt;The answer is, both throw a ClassCastException indicating that an Integer can not be cast to a String and vice versa.&amp;nbsp; So how is Groovy coercing this comparison?&amp;nbsp; Time to decompile the code to get to the bottom of this.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Decompile the  code!&lt;/b&gt;&lt;br /&gt;
Below is a snippet of the decompiled code where you can see it calls the ScriptBytecodeAdapter &lt;i&gt;compareLessThan&lt;/i&gt; method with both of the  arguments as  Objects, so we get an identity comparison!&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:groovy"&gt;&amp;nbsp; for(Integer i = $const$0; ScriptBytecodeAdapter.compareLessThan(i, acallsite[1].callGetProperty(params));)
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-8245903357213260498?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/NXcrOY7uYKA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/8245903357213260498/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2009/08/simple-groovy-mistake-had-me-wondering.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/8245903357213260498?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/8245903357213260498?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/NXcrOY7uYKA/simple-groovy-mistake-had-me-wondering.html" title="Simple Groovy mistake had me wondering what the heck was going on!" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2009/08/simple-groovy-mistake-had-me-wondering.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4BSXc4cSp7ImA9WxNSFUw.&quot;"><id>tag:blogger.com,1999:blog-7371895490737388670.post-4671611001556831762</id><published>2009-08-28T20:55:00.000-05:00</published><updated>2009-08-28T20:55:58.939-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-28T20:55:58.939-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="initial" /><title>Finally got a blog!</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/0J4CXnzt0-WssvAYHgR6b1H5vz0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0J4CXnzt0-WssvAYHgR6b1H5vz0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/0J4CXnzt0-WssvAYHgR6b1H5vz0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0J4CXnzt0-WssvAYHgR6b1H5vz0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;Talk about being "&lt;i&gt;late to the party&lt;/i&gt;", I have finally setup a blog.    I plan on blogging on Java, Groovy &amp;amp; Grails and other topics that I would like to share while I "&lt;i&gt;scratch my programming itch&lt;/i&gt;".&lt;br /&gt;
&lt;div&gt;&lt;/div&gt;&lt;div&gt;Hopefully some of my posts will be of interest to others and help them, as so many others have done for me.   Please feel free to comment.    Life's a learning experience!&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7371895490737388670-4671611001556831762?l=programmingitch.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ScratchingMyProgrammingItch/~4/8RBxNAaMLnI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://programmingitch.blogspot.com/feeds/4671611001556831762/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://programmingitch.blogspot.com/2009/08/finally-got-blog.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/4671611001556831762?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7371895490737388670/posts/default/4671611001556831762?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ScratchingMyProgrammingItch/~3/8RBxNAaMLnI/finally-got-blog.html" title="Finally got a blog!" /><author><name>Mike Miller</name><uri>http://www.blogger.com/profile/09697567698545249690</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://programmingitch.blogspot.com/2009/08/finally-got-blog.html</feedburner:origLink></entry></feed>

