Groovy in the CloudsGroovy in the Clouds - Vladimír Oranýhttp://vladimir.orany.cz
http://vladimir.orany.cz
2013-05-16T16:17:45-07:002013-05-16T16:17:45-07:001800Gaelyk 2.0 Released<p>Gaelyk 2.0 is finally out. Some of the new features were already listed on this site.</p>
<p>The most important features are:</p>
<ul>
<li>Groovy 2.0 support and removing <code>GaelykCategory</code></li>
<li><a href='http://gaelyk.appspot.com/tutorial/app-engine-shortcuts#advanced_fulltext_search'>Search DSL</a></li>
<li><a href='http://gaelyk.appspot.com/tutorial/url-routing#path-variables'>Optinal routes parameters</a></li>
<li><a href='http://gaelyk.appspot.com/tutorial/views-and-controllers#better-params-handling'>Better parameters conversion</a></li>
<li>Better coercion performance</li>
<li>Returning <a href='https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/QueryResultList'>QueryResultList</a> and <a href='https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/QueryResultIterator'>QueryResultIterator</a> from <code>datastore.execute{}</code> and <code>datastore.iterate{}</code> methods</li>
<li>and many others &#8230;</li>
</ul>
<p>Gaelyk 2.0 is already available on Maven Central or you can download it from <a href='http://gaelyk.appspot.com/download'>Gaelyk Download Page</a>.</p>
<h3 id='whats_new_in_gaelyk_20_session_at_gr8conf'>What&#8217;s new in Gaelyk 2.0 Session at Gr8Conf</h3>
<p>If you are attending <a href='http://www.gr8conf.eu'>Gr8Conf EU</a> next week, I&#8217;ll be glad meeting you at my session <a href='http://gr8conf.eu/Presentations/Whats-new-in-Gaelyk-2.0'>What is new in Gaelyk 2.0</a> where all the new features will be shown.</p>
<a href='https://www.google.com/calendar/event?action=TEMPLATE&tmeid=b2c2dHBmdTZjdmJraWo4NTZjbTNxY29rZmMgdmxhZGltaXIub3JhbnlAbQ&tmsrc=vladimir.orany%40gmail.com' class='btn btn-primary' target='_blank'><i class='icon-calendar icon-white'> </i> Add to Google Calendar</a>
<h3 id='gaelyk_spock_and_core_plugins'>Gaelyk Spock and core plugins</h3>
<p>Gaelyk related projects were relased as well:</p>
<ul>
<li><a href='https://github.com/gaelyk/gaelyk-spock'>Gaelyk Spock 0.4</a></li>
<li><a href='https://github.com/gaelyk/gaelyk-resources-plugin'>Gaelyk Resources Plugin 2.0</a></li>
<li><a href='https://github.com/gaelyk/gaelyk-bootstrap-resources'>Gaelyk Bootstrap Resources Plugin 2.0</a></li>
<li><a href='https://github.com/gaelyk/gaelyk-console-plugin'>Gaelyk Console Plugin 2.0</a></li>
<li><a href='https://github.com/gaelyk/gaelyk-datastore-viewer-plugin'>Gaelyk Datastore Viewer Plugin 2.0</a></li>
</ul>
<p>Thank all the great people helping with this release!</p>http://vladimir.orany.cz/announcements/2013/05/17/gaelyk-20-released
http://vladimir.orany.cz/announcements/2013/05/17/gaelyk-20-released2013-05-17T00:00:00-07:00Everyday Gaelyk: Common Query DSL pitfalls<p><a href='http://gaelyk.appspot.com/tutorial/app-engine-shortcuts#query'>Gaelyk Query DSL</a> makes quering <a href='https://developers.google.com/appengine/docs/java/datastore/'>Google App Engine Datastore</a> a lot simpler but sometimes it isn&#8217;t working as expected.</p>
<h2 id='variable_naming_conflict'>Variable naming conflict</h2>
<p>Some of problems origins from using the variable or property names which are already taken. Names of the properties in where clause are converted to <code>String</code> automatically. What property we will be querying?</p>
<p><em>Variable name conflict</em></p>
<pre><code>def count = 123
// a lot of code here so you&#39;ve already forgotten you have such a variable
def maxCount = 100
datastore.execute {
from Item
where count &lt;= maxCount
}</code></pre>
<p>This query will be translated as <code>123 &lt;= 100</code> which probably isn&#8217;t what you wanted.</p>
<h2 id='binding_variable_name_conflict'>Binding variable name conflict</h2>
<p>Previous example was quite obvious but what if we have following query:</p>
<p><em>Binding variable name conflict</em></p>
<pre><code>datastore.execute {
from Item
where users &gt; 10
}</code></pre>
<p>Instead of getting result of items having more than ten users we get empty result set. It&#8217;s because <code>users</code> is Gaelyk&#8217;s shortcut to <a href='https://developers.google.com/appengine/docs/java/gettingstarted/usingusers'>UserService</a> so the where clause is translated to something like <code>UserService@xyz123 &gt; 10</code> which obviously returns no results.</p>
<p>If you run into name conflict just use good old String as property name in the where clause such as <code>where &#39;users&#39; &gt; 10</code>.</p>
<h2 id='entity_pitfalls'>Entity pitfalls</h2>
<p><code>@Entity</code> annotation adds sevral useful methods to the POGO class such as <code>findAll</code> which resemble their <a href='http://grails.org/doc/2.1.0/ref/Domain%20Classes/findAll.html'>Grails counterparts</a>. But don&#8217;t get confused. The syntax of using such methods differs slightly. <code>find</code>, <code>findAll</code> or <code>count</code> method are just shortcuts to Query DSL!</p>
<p><em>Using findAll method</em></p>
<pre><code>@Entity class Item {
int count
}
Item.findAll { count == 10 }</code></pre>
<p>The query listed above will return all the items since the condition is ignored because the <code>where</code> keyword is missing.</p>
<p><em>Using findAll method with where</em></p>
<pre><code>@Entity class Item {
int count
}
Item.findAll { where count == 10 }</code></pre>
<p>We have added the <code>where</code> keyword to the <code>findAll</code> method but now we&#8217;ll always get empty result because all field of <code>@Entity</code> class are unindexed by default. You need to mark the field <code>@Indexed</code> to use it in queries.</p>
<p><em>Using findAll method with where on indexed field</em></p>
<pre><code>@Entity class Item {
@Indexed int count
}
Item.findAll { where count == 10 }</code></pre>
<h2 id='summary'>Summary</h2>
<p>Using Query DSL you should basically always take care about two important things:</p>
<ol>
<li>Property names are always converted to String, this is may make mess if the variable with the same name is already defined (even in Gaelyk shortcut bindings). Use String constants instead of property names in case of any possible name conflict.</li>
<li>All properties you&#8217;re querying must be indexed. When using <code>@Entity</code> annotations all the properties are unindexed by default.</li>
</ol>http://vladimir.orany.cz/everyday%20gaelyk/2013/04/03/everyday-gaelyk-common-query-dsl-pitfalls
http://vladimir.orany.cz/everyday%20gaelyk/2013/04/03/everyday-gaelyk-common-query-dsl-pitfalls2013-04-03T00:00:00-07:00Everyday Gaelyk: Save your query dsl for later use<p>In <a href='http://gaelyk.appspot.com'>Gaelyk</a> you can already save <a href='http://gaelyk.appspot.com/tutorial/app-engine-shortcuts#query'>query created by query dsl</a> using <code>datastore.query{...}</code> and than excute it using <a href='https://developers.google.com/appengine/docs/java/datastore/queries#Retrieving_Results'>datastore prepare</a> function but this method only support a subset of dsl statements - namely <code>select</code>, <code>from</code>, <code>where</code>, <code>and</code> and <code>sort</code>. Corection using <code>as</code> or setting <code>limit</code> or <code>offset</code> is simply ignored. In <a href='/everyday%20gaelyk/2013/03/16/everyday-gaelyk-living-on-the-edge-with-gaelyk-snapshots'>Gaelyk 2.0</a> you can use <code>datastore.build{...}</code> method to create instance of <a href='http://gaelyk.appspot.com/api/groovyx/gaelyk/query/QueryBuilder.html'>QueryBuilder</a>.</p>
<div class='alert'>
<p><strong>Warning!</strong> Thanks to <a href='http://docs.codehaus.org/display/GROOVY/Creating+an+extension+module'>Groovy 2.0
extension modules</a> you can use helper method on any <code>DatastoreService</code> instance even outside groovlets or templates
but you still have to assing the <code>DatastoreService</code> in <code>datastore</code> variable and call
the methods on that variable to make query dsl transformation working.</p>
<p>This is current limitation and should change in time of final Gaelyk 2.0 release.</p>
</div>
<p>Let&#8217;s show the difference between <code>datastore.query</code> and <code>datastore.build</code> methods:</p>
<p><em>Query method example</em></p>
<pre><code>Query query = datastore.query {
from &#39;Comment&#39; as Comment
where author == 10
sort by crate desc
limit 10
}
PreparedQuery pq = datastore.prepare query
// The limit is gone! We need to set it again
FetchOptions.Builder options = withLimit(10)
// set the offset if there is page param specified
if(params.page){
options = options.offset((params.page as int) * 10)
}
def comments = pq.asList(options.build())
// and we also get only entities not comments
for(Entity e in entity){
// which needs to be coerced manually
Comment comment = e as Comment
process comment
}</code></pre>
<p>When using <code>datastore.query</code> method a portion of query parameters where erased, expecially loosing coercion is very confusing. On the other hand if you use <code>datastore.build</code> instead than all the information are kept.</p>
<p><em>Build method example</em></p>
<pre><code>QueryBuiler dsl = datastore.build {
from &#39;Comment&#39; as Comment
where author == 10
sort by crate desc
limit 10
}
// set the offset if there is page param specified
if(params.page){
dsl.offset((params.page as int) * 10)
}
def comments = dsl.execute()
// no need to coerce manually
for(Comment in comments){
process comment
}</code></pre>http://vladimir.orany.cz/everyday%20gaelyk/2013/03/21/everyday-gaelyk-save-your-query-builder-for-later-use
http://vladimir.orany.cz/everyday%20gaelyk/2013/03/21/everyday-gaelyk-save-your-query-builder-for-later-use2013-03-21T00:00:00-07:00Everyday Gaelyk: Handle long running datastore queries gracefully<p><span>Google App Engine</span> is full of hidden traps. One of them is the need to restart long running queries when the query expired causing following exception to be thrown:</p>
<p><code>The requested query has expired. Please restart it with the last cursor to read more results</code></p>
<p>In <a href='/everyday%20gaelyk/2013/03/16/everyday-gaelyk-living-on-the-edge-with-gaelyk-snapshots'>Gaelyk 2.0</a> you can now tell your <a href='http://gaelyk.appspot.com/tutorial/app-engine-shortcuts#query'>query</a> to restart automatically if this happen. Restarting happen under the hood so you can use <code>for</code> loops flawlessly.</p>
<p>To enable automatic restarting of queries add <code>restart automatically</code> statement to your query dsl. Currenty, you can only use this option on <code>iterate</code> method, because it doesn&#8217;t make much sense with <code>execute</code> method.</p>
<p><em>Simple restarting query</em></p>
<pre><code>def comments = datastore.iterate {
from Comment
limit 50000
restart automatically
}
for(comment in comments){
// would throw exception randomly for long running queries
process comment
}</code></pre>
<p>You can use <code>restart automatically</code> with <code>select all</code> and <code>select keys</code> query types. It also works with coerced queries using <code>as Type</code> keyword e.g. <code>form &#39;Comment&#39; as Comment</code>.</p>http://vladimir.orany.cz/everyday%20gaelyk/2013/03/21/everyday-gaelyk-handle-long-running-datastore-queries-gracefully
http://vladimir.orany.cz/everyday%20gaelyk/2013/03/21/everyday-gaelyk-handle-long-running-datastore-queries-gracefully2013-03-21T00:00:00-07:00Everyday Gaelyk: Solving java.lang.NoClassDefFoundError: com/google/appengine/api/search/AddResponse<p>Today, <a href='https://developers.google.com/appengine/'>Google App Engine</a> Team said farewell to <a href='https://code.google.com/p/googleappengine/wiki/SdkForJavaReleaseNotes#Version_1.7.5_-_February_13,_2013'>deprecated classes</a> in <a href='https://code.google.com/p/googleappengine/wiki/SdkForJavaReleaseNotes#Version_1.7.6_-_March_19,_2013'>version 1.7.6</a> causing sevral sites crashed. Even the application was deployed with older <a href='https://developers.google.com/appengine/downloads#Google_App_Engine_SDK_for_Java'>SDK</a> the <code>AddResponse</code> class just disappeared. Yes, we all were warned in that release notes but who cares about the warnings. I wish they have mentioned when the new version will be released too so we&#8217;ll be extra careful today.</p>
<p>For <span>Gaelyk</span> users there are two choices to fix your application:</p>
<ul>
<li>Switch to <a href='/everyday%20gaelyk/2013/03/16/everyday-gaelyk-living-on-the-edge-with-gaelyk-snapshots'>Gaelyk 2.0 snapshot</a> unless version 2.0 is finally out</li>
<li>Build <a href='https://github.com/mmigdol/gaelyk/tree/removeSearchFrom13'>Gaelyk 1.3 snapshot</a> fixed by <a href='https://github.com/mmigdol'>Michael Migdol</a> and use it</li>
</ul>
<p>Both solutions was discussed <a href='https://groups.google.com/forum/?hl=en&amp;fromgroups=#!topic/gaelyk/s2vNNVlv0ME'>in this thread</a>. If you use <code>GaelykCategory</code> class directly in your code, 1.3 snapshot is better option for you because the class is no longer present in the code base of 2.0 snapshots. The category class was broken into serval separate extension modules.</p>
<p>If you&#8217;re using plain Java in your Google App Engine application, just switch to latest 1.7.6 SDK and compliation errors will guide you.</p>http://vladimir.orany.cz/everyday%20gaelyk/2013/03/19/everyday-gaelyk-how-to-solve-javalangnoclassdeffounderror-comgoogleappengineapisearchaddresponse
http://vladimir.orany.cz/everyday%20gaelyk/2013/03/19/everyday-gaelyk-how-to-solve-javalangnoclassdeffounderror-comgoogleappengineapisearchaddresponse2013-03-19T00:00:00-07:00Everyday Gaelyk: Find blob file by name<p>Google App Engine has sort of <a href='https://developers.google.com/appengine/docs/java/blobstore/overview#Writing_Files_to_the_Blobstore'>support for saving files to the blobstore</a>. <a href='http://gaelyk.appspot.com'>Gaelyk</a> adds some nice <a href='http://gaelyk.appspot.com/tutorial/app-engine-shortcuts#file-service'>sugar to the files service</a>. You can easily create file in blobstore using following shortcut:</p>
<p><em>Creating file in the blobstore</em></p>
<pre><code>def file = files.createNewBlobFile(&quot;text/plain&quot;, &quot;hello.txt&quot;)
file.withWriter { writer -&gt;
writer &lt;&lt; &quot;some content&quot;
}</code></pre>
<p>It is very nice that you have to set the content type and the name of the file but neither the content type nor the file name is used anywhere. If you <a href='https://developers.google.com/appengine/docs/java/blobstore/overview#Serving_a_Blob'>serve the file from the blobstore</a> the content type doesn&#8217;t seem to be set to the response and of course you can&#8217;t find file by its name easily. But it doesn&#8217;t mean there is no way how to do it.</p>
<p>Google offers class <a href='https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/blobstore/BlobInfoFactory'>BlobInfoFactory</a> to query the information about stored blobs but you would have to walk throught all the blobs in your application to find the proper blob. Luckily, blob information is just plain entity and <a href='https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/blobstore/BlobInfoFactory'>BlobInfoFactory</a> exposes fields <code>BlobInfoFactory.KIND</code>, <code>BlobInfoFactory.CREATION</code> and <code>BlobInfoFactory.FILENAME</code> which can help you find the desired file.</p>
<pre><code>String name = &quot;hello.txt&quot;
def files = datastore.execute {
from BlobInfoFactory.KIND
where BlobInfoFactory.FILENAME == name
sort desc by BlobInfoFactory.CREATION
}
if(files){
new BlobKey(files[0].key.name).serve(response)
} else {
response.status = 404
out &lt;&lt; &quot;No such file $name&quot;
}</code></pre>
<p>Since the file name isn&#8217;t guaranteed to be unique, you can get more than one result. Sorting the blob information by its creation time help you to get the latest file as the first element of returned list. This might be acctually handy if you want to implement very simple and inefficient version system. You can create new blob key from the name of the entity returned from the query and using this key you can serve the file to the client.</p>http://vladimir.orany.cz/everyday%20gaelyk/2013/03/19/everyday-gaelyk-find-blob-file-by-name
http://vladimir.orany.cz/everyday%20gaelyk/2013/03/19/everyday-gaelyk-find-blob-file-by-name2013-03-19T00:00:00-07:00Everyday Gaelyk: Simplify flow in groovlets by handling their return values<p><a href='http://gaelyk.appspot.com/tutorial/plugins'>Gaelyk plugin system</a> allows you to define <code>after</code> hook which is called when <a href='http://gaelyk.appspot.com/tutorial/views-and-controllers#groovlets'>groovlet</a> execution is finished. Since <a href='/everyday%20gaelyk/2013/03/16/everyday-gaelyk-living-on-the-edge-with-gaelyk-snapshots'>Gaelyk 2.0</a> the result returned from the groovlet is bound to the <code>after</code> closure so you can e.g. turn that result into the JSON response.</p>
<!--more-->
<p>Let say you have a groovlet serving some JSON content by id and you want to simplify it&#8217;s flow.</p>
<p><em>JSON groovlet, standard version</em></p>
<pre><code> response.contentType = &#39;application/json&#39;
if(users.isUserLoggedIn){
response.status = 401
json(error: &#39;You must be logged in&#39;)
} else {
// uses @Entity annotation
Item item = Item.get(params.id as long)
if(!item){
response.status = 404
json(error: &#39;Item not found&#39;)
} else {
json(id: item.id, title: item.title)
}
}</code></pre>
<p>In fact, this example is pretty trivial but still it would be handy if we can cut off some unnecessary branching:</p>
<p><em>JSON groovlet, version with plugin</em></p>
<pre><code> // see following
request.renderAsJson = true
if(users.isUserLoggedIn){
return [status: 401, error: &#39;You must be logged in&#39;]
}
// uses @Entity annotation
Item item = Item.get(params.id as long)
if(!item){
return [status: 404, error: &#39;Item not found&#39;]
}
[id: item.id, title: item.title]</code></pre>
<p>This can be actually quite simply accomplished by creating plugin which will render groovlet result as JSON. You can follow <a href='http://gaelyk.appspot.com/tutorial/plugins#anatomy'>the guide on Gaelyk website</a>. Basically, you need a script containing the <code>after</code> handler:</p>
<p><em>JSON renderer plugin</em></p>
<pre><code>after {
// render as json only when this attribute is set to groovy truth
if(request.renderAsJson){
// sets the json
response.contentType = &#39;application/json&#39;
// result is stored in &#39;result&#39; closure variable
if(result instanceof Map &amp;&amp; result?.status){
// set the status from the status map value
response.status = result.remove(&#39;status&#39;) as int
}
// render the result
JsonBuilder json = new JsonBuilder()
json result
json.writeTo(response.writer)
}
}</code></pre>
<p>Save the script as <code>WEB-INF/plugins/jsonRenderer.groovy</code> and create another file <code>WEB-INF/plugins.groovy</code> with single line <code>install jsonRenderer</code> and you can try it yourself in your Galeyk 2.0 application.</p>
<p>If you got another idea how to use result of groovlet exection in your application, please, leave a message under the post.</p>http://vladimir.orany.cz/everyday%20gaelyk/2013/03/17/everyday-gaelyk-simplify-groovlets-flow-by-handling-its-return-value
http://vladimir.orany.cz/everyday%20gaelyk/2013/03/17/everyday-gaelyk-simplify-groovlets-flow-by-handling-its-return-value2013-03-17T00:00:00-07:00Everyday Gaelyk: More readable routes with optional path parameters<p>At the time of writing, the original <a href='http://gaelyk.appspot.com/tutorial/url-routing'>Gaelyk documentation</a> still contains the verbose way how to define following routes with optional path variables. <a href='/everyday%20gaelyk/2013/03/16/everyday-gaelyk-living-on-the-edge-with-gaelyk-snapshots'>Gaelyk 2.0</a> helps you to get rid of lot of boilerplate routes definition.</p>
<!--more-->
<p><em>Current approach to define optional path variables</em></p>
<pre><code>get &quot;/article/@year/@month/@day/@title&quot;,
forward: &quot;/article.groovy?year=@year&amp;month=@month&amp;day=@day&amp;title=@title&quot;
get &quot;/article/@year/@month/@day&quot;,
forward: &quot;/article.groovy?year=@year&amp;month=@month&amp;day=@day&quot;
get &quot;/article/@year/@month&quot;,
forward: &quot;/article.groovy?year=@year&amp;month=@month&quot;
get &quot;/article/@year&quot;,
forward: &quot;/article.groovy?year=@year&quot;
get &quot;/article&quot;,
forward: &quot;/article.groovy&quot;</code></pre>
<h3 id='defining_optional_path_variables_in_gaelyk_20'>Defining Optional Path Variables in Gaelyk 2.0</h3>
<p>As soon as Gaelyk 2.0 is released you can save a lot of typing, because adding a question mark <code>?</code> at the end of path variable definition such as <code>@title</code> has the same effect multiple declaring the multiple routes as described above.</p>
<p><em>New way to define optional path variables</em></p>
<pre><code>get &quot;/article/@year?/@month?/@day?/@title?&quot;, forward: &quot;/article.groovy&quot;</code></pre>
<p>If the path variable is present it is appended as <code>path_variable_name=@path_variable_name</code> to destination specified in <code>forward</code> or <code>redirect</code> definition e.g. <code>/article/2013</code> is forwarded to <code>/article.groovy?year=2013</code>.</p>
<h3 id='handling_trailing_slashes'>Handling trailing slashes</h3>
<p>If the route defined ends with slash, all the routes matched must ends with slash and vice versa, e.g. <code>/article/2013</code> will match the route above but <code>/article/2013/</code> won&#8217;t because the route does not end with slash.</p>
<h3 id='mixing_optional_and_required_path_variables'>Mixing optional and required path variables</h3>
<p>Of course there is no need to have all the parameters optional. For example, we can make <code>year</code> required:</p>
<p><em>Mixed optional and required path variables</em></p>
<pre><code>get &quot;/article/@year/@month?/@day?/@title?&quot;, forward: &quot;/article.groovy&quot;</code></pre>
<h3 id='making_path_variables_sticky'>Making Path Variables Sticky</h3>
<p>Sometimes you want to have some path variable recognized even if the previous are mising. For example, you want to be able to specify paging using <code>@page</code> path variable, which itself is optional as well the other path variables. You can do this by assigning the path variable unique prefix like <code>page-</code> as in following examples. Take a note you can have multiple path variables with prefixes as long as the prefixes are unique. Also routes are handled as special type of regular expressions so you can use some features like <code>[io]n</code> to specify that the prefix might be either <code>in</code> or <code>on</code>.</p>
<p><em>Sticky path variable</em></p>
<pre><code>get &quot;/article/@year?/@month?/@day?/@title?/page-@page?/[io]n-@tag&quot;, forward: &quot;/article.groovy&quot;</code></pre>
<p>This route will match following situations and many others:</p>
<p><em>Sticky path variable usage</em></p>
<pre><code>/article/in-groovy =&gt; /article.groovy?tag=groovy
/article/page-1 =&gt; /article.groovy?page=1
/article/2013/page-2/on-groovy =&gt; /article.groovy?year=2013&amp;page=2&amp;tag=groovy
/article/2013/03/16 =&gt; /article.groovy?year=2013&amp;month=03&amp;day=16</code></pre>http://vladimir.orany.cz/everyday%20gaelyk/2013/03/16/everyday-gaelyk-more-readable-routes-with-optional-path-parameters
http://vladimir.orany.cz/everyday%20gaelyk/2013/03/16/everyday-gaelyk-more-readable-routes-with-optional-path-parameters2013-03-16T00:00:00-07:00Everyday Gaelyk: Living on the edge with Gaelyk snapshots<p>I&#8217;ve setup <a href='https://gaelyk.ci.cloudbees.com/'>Gaelyk Continuous Integration Server</a> on <a href='http://www.cloudbees.com'>CloudBees</a> few months ago so each time the change is pushed to Gaelyk repository and the tests are passing then the new JARs are pushed to the snapshot repository currently hosted at <a href='https://oss.sonatype.org/content/repositories/snapshots/'>SonaType OSS</a>. If you like living on the edge and using the latest features you can use these in your application.</p>
<!--more-->
<p>Updating <a href='http://www.gradle.org'>Gradle</a> build is pretty easy. Only thing you need to do is to declare <a href='https://oss.sonatype.org/content/repositories/snapshots/'>SonaType snapshot repository</a> in <code>repositories</code> configuration closure</p>
<p><em>Repositories configuration</em></p>
<pre><code>repositories {
...
mavenRepo url: &#39;https://oss.sonatype.org/content/repositories/snapshots/&#39;
}</code></pre>
<p>and change the version of your <a href='http://gaelyk.appspot.com'>Gaelyk</a> dependency to the snapshot version, <code>2.0-SNAPSHOT</code> at the time of writing.</p>
<p><em>Dependencies configuration</em></p>
<pre><code>dependencies {
...
compile &#39;org.gaelyk:gaelyk:2.0-SNAPSHOT&#39;
}</code></pre>
<span class='label'>EDIT</span>
<p>By default Gradle caches the snapshot versions. To disable caching for all snapshot versions add following to your <code>build.gradle</code> file:</p>
<p><em>Disable snapshot versions caching</em></p>
<pre><code>configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, &#39;seconds&#39;
}</code></pre>
<p>If you haven&#8217;t adopted Gradle for Gaelyk development, you can download latest snapshots from <a href='https://oss.sonatype.org/content/repositories/snapshots/org/gaelyk/gaelyk/2.0-SNAPSHOT/'>Sonatype OSS Snapshot Repository</a>. Be sure you are using the same <a href='http://groovy.codehaus.org/Download'>Groovy</a> and <a href='https://developers.google.com/appengine/downloads'>GAE SDK</a> version as listed in <a href='https://raw.github.com/gaelyk/gaelyk/master/common.gradle'>common build configuration</a>.</p>
<p>Here you go, you&#8217;re now using the latest version of <a href='http://gaelyk.appspot.com'>Gaelyk</a> available.</p>http://vladimir.orany.cz/everyday%20gaelyk/2013/03/16/everyday-gaelyk-living-on-the-edge-with-gaelyk-snapshots
http://vladimir.orany.cz/everyday%20gaelyk/2013/03/16/everyday-gaelyk-living-on-the-edge-with-gaelyk-snapshots2013-03-16T00:00:00-07:00Everyday Gaelyk: Handling input parameters gracefully<p>The <code>params</code> object added to <a href='http://groovy.codehaus.org/Groovlets'>groovlets</a> and <a href='http://groovy.codehaus.org/Groovy+Templates'>templates</a> has one very enpleasant feature that it either contains values of type <code>String</code> or <code>String[]</code> depending on how many parameters were submitted. In <a href='/everyday%20gaelyk/2013/03/16/everyday-gaelyk-living-on-the-edge-with-gaelyk-snapshots'>Gaelyk 2.0</a> is now handling parameters much easier.</p>
<!--more-->
<p>Prior Gaelyk 2.0 following unpleasant situation may occur:</p>
<p><em>Problems with params prior Gaelyk 2.0</em></p>
<pre><code>// query = ?tag=one&amp;tag=two
params.tag == [&#39;one&#39;,&#39;two&#39;] as String[]
// this is ok
params.tag.collect { it } == [&#39;one&#39;, &#39;two&#39;]
// query = ?tag=one
params.tag == &#39;one&#39;
// oops, String.each iterates over characters
params.tag.collect { it } == [&#39;o&#39;, &#39;n&#39;, &#39;e&#39;]
// query = ?limit=100
params.limit == &#39;100&#39;
params.limit as int == 100
// query = ?limit=100&amp;limit=200
params.limit == [&#39;100&#39;, &#39;200&#39;] as String[]
try {
params.limit as int
assert false
} catch(ClassCastException e) {
// cannot cast String[] to int
assert true
}</code></pre>
<p>These casts are now safe in Gaelyk 2.0.</p>
<p><em>Safe parameters handling in Gaelyk 2.0</em></p>
<pre><code>// query = ?tag=one&amp;tag=two
params.tag == [&#39;one&#39;,&#39;two&#39;] as String[]
// this is ok
params.tag.collect { it } == [&#39;one&#39;, &#39;two&#39;]
// query = ?tag=one
params.tag == &#39;one&#39;
// oops, String.each iterates over characters
params.tag.collect { it } == [&#39;o&#39;, &#39;n&#39;, &#39;e&#39;]
// use as String[] to ensure having String array
(params.tag as String[]).collect { it } == [&#39;one&#39;]
// query = ?limit=100
params.limit == &#39;100&#39;
params.limit as int == 100
// query = ?limit=100&amp;limit=200
params.limit == [&#39;100&#39;, &#39;200&#39;] as String[]
// first value is taken on cast to single value (not array or collection)
params.limit as int == 100</code></pre>
<p>Simply said use <code>as String[]</code> on values from <code>params</code> whenever you expect multiple values and <code>as &lt;type supported by String.asType() or String&gt;</code> if you expect single value.</p>http://vladimir.orany.cz/everyday%20gaelyk/2013/03/16/everyday-gaelyk-handling-input-parameters-gracefully
http://vladimir.orany.cz/everyday%20gaelyk/2013/03/16/everyday-gaelyk-handling-input-parameters-gracefully2013-03-16T00:00:00-07:00Everyday Gaelyk: Adding methods to groovlets and templates<p>Since <a href='/everyday%20gaelyk/2013/03/16/everyday-gaelyk-living-on-the-edge-with-gaelyk-snapshots'>Gaelyk 2.0</a> is build on the top of <a href='http://groovy.codehaus.org/Groovy+2.1+release+notes'>Groovy 2.1 branch</a>, you can use <a href='http://docs.codehaus.org/display/GROOVY/Creating+an+extension+module'>extension modules</a> to add useful methods to particular classes. As all <a href='http://groovy.codehaus.org/Groovlets'>groovlets</a> and <a href='http://groovy.codehaus.org/Groovy+Templates'>templates</a> are basically scripts, all of them extend <code>groovy.lang.Script</code> class. Every method added to <code>groovy.lang.Script</code> will be available in your groovlets and templates as well as other scripts and can be easily used nearly as easy as Grails tags.</p>
<!--more-->
<h2 id='simple_method'>Simple Method</h2>
<p>If you create simple extension class like following</p>
<p><em>Extension class</em></p>
<pre><code>package cz.orany.vladimir.gaelyk
class GroovyTemplatesExtensions {
static String helloWorld(Script self) { &quot;Hello World&quot; }
}</code></pre>
<p>and register it in <code>org.codehaus.groovy.runtime.ExtensionModule</code> file in the <code>META-INF/services</code> directory</p>
<p><em>Extension module descriptor</em></p>
<pre><code>moduleName=gaelyk-scripts-module
moduleVersion=1.0
extensionClasses= cz.orany.vladimir.gaelyk.GroovyTemplatesExtension
staticExtensionClasses=</code></pre>
<p>you will be able to call the method from your template, e.g. <code>test.gtpl</code></p>
<p><em>Example template</em></p>
<pre><code>&lt;html&gt;
&lt;head&gt;&lt;title&gt;Test hello&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;${helloWorld()}&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h2 id='advanced_taglike_method'>Advanced tag-like method</h2>
<p>Of course you can create more sofisticated methods which be close to <a href='http://grails.org/doc/latest/guide/theWebLayer.html#6.3+Tag+Libraries'>Grails tags</a>.</p>
<p><em>Secured &#8216;tag&#8217;</em></p>
<pre><code>&lt;% secured { %&gt;
&lt;p&gt;This is only visible when the user is signed in&lt;/p&gt;
&lt;% } %&gt;</code></pre>
<p>The usage is really simple, the implementation isn&#8217;t difficult either. You basically write same code as you would write in the template:</p>
<p><em>Method implementation</em></p>
<pre><code>static void secured(Script self, Closure body) {
self.with {
if(users.userLoggedIn){
body()
}
}
}</code></pre>
<p>The core trick is using the context of current script by calling <code>self.with</code> method. In that case you get simply access to all the bindings available in the script itself.</p>http://vladimir.orany.cz/everyday%20gaelyk/2013/03/15/gaelyk-20-preview-adding-methods-to-groovlets-and-templates
http://vladimir.orany.cz/everyday%20gaelyk/2013/03/15/gaelyk-20-preview-adding-methods-to-groovlets-and-templates2013-03-15T00:00:00-07:00