Tuesday, June 29, 2010

XMLSlurper trying to annoy me

Just a little note: If you ever wonder why you're iteration of XMLSlurper elements does not work: Try inserting a .children() before the .each(). Have a look at this code, where you have one case where it works without and in the second place only with .children():

ncbiXML.GBSeq.'GBSeq_feature-table'.GBFeature.each{feature ->
 if((feature.GBFeature_key as String) == "CDS")
 {                   
  feature.GBFeature_quals.children().each{qual ->
  }
 }

Parsing XML: two stumbling blocks and a problem with params

Today I wanted to parse some XML content from NCBI into my grails application. I followed the instructions on:

http://www.ibm.com/developerworks/java/library/j-grails05208/index.html

Although the connection did not seem to have any problems, the parsing from a XMLSlurper object to a map did. There were in fact two problems I had to face and luckily I found the solution for both of them here:

http://stackoverflow.com/questions/1849547/groovy-xmlslurper-not-parse-my-xml-file

The first problem was that you cannot have a dash in your XML node unless you embrace it with hyphens like this:
ncbiXML.GBSeq.'GBSeq_accession-version' as String

I guess dashes are otherwise interpreted like dots (separators). I imagined something like that when I encountered the error "no property like that".

After fixing this the code ran through. The tests however still failed as only empty values were returned. The solution was to ignore the top node of the XML input. Starting one node below everything worked fine.

Now, equiped with a nice map I wanted to create domain objects following the helpful steps at the end of this article:

http://thediscoblog.com/2009/02/19/restful-grails-services-in-3-steps/

To make the properties editable before submission, I added a new action to a controller that redirects to "create" and hands over the xml parsed map from XMLSlurper as params.

That would probably have worked if it hadn't been for one property that was not a string, but an object. I thought no problem, all I have to do is use a dynamic finder to get my object with the string. This produces errors as grails interpreted this parameter as String and threw conversion exceptions when trying to parse a string to my object:

Cannot convert value of type [java.lang.String] to required type

I have googled for hours and tried everything, but finally I found the very simple solution. You have to put it like this to convince grails that it has to look up for a domain object itself via id:

ncbiMap.'organism.id' = organism.id

Again, the hyphens are very important. In the beginning I tried different things without them and then grails tries to resolve the dot instead of letting the parameter go.

Now everything works fine and I hope someone can use this to get started real fast on this (not like me :-)

Monday, June 28, 2010

grails-ui autocomplete with "onSelect" event

Today I had my first try in integrating an autocomplete feature. I was more successful than expected due to the very easy to use grails-ui library. You have to put code like that in your controller to serve data to the taglib:
def searchResultsAsJSON = {
     def jsonList = Gene.list().findAll{it.name.startsWith(params.query)}.collect{[id: it.id, label: it.name]}
     
     def jsonResult = [
         results: jsonList
     ]
     render jsonResult as JSON
 }

As you can see you need to provide your data JSON formatted. You also have to use the parameter "query" to filter results that fit what the user has already typed in. Furthermore you can collect only those properties of your domain class that are really necessary for the autocomplete. These are namely an id and a label to display and search. Okay now that we've seen this part, let's have a look at the GSP:

<gui:autoComplete
            minQueryLength="3"
         queryDelay="0.5"
         id="quickSearch"
         resultName="results"
         labelField="label"
         idField="id"
         controller="quickSearch"
         action="searchResultsAsJSON"
  />

Here you can see different options that you can influence, e.g. how many letters one has to type in before the taglib starts AJAX-calling. Although more or less self-explaining, I will say a few words about those properties:
  • idField is the name of the ID field in the JSON output
  • labelField is the name of the label that is displayed for search in the JSON output
  • resultName is the name of the top node used in JSON. In the above example this was results.
At this stage I was already quite happy with my results, but I wanted one more feature that was unfortunately not included. I wanted to define some action when a selection has been made by the user. Therefore I added some javascript to the page:

YAHOO.util.Event.onDOMReady(function() {
   GRAILSUI.quickSearch.itemSelectEvent.subscribe(function(type, args) {
      ${remoteFunction(controller:"quickSearch", action:"showResult", params: '\'name=\'+GRAILSUI.quickSearch.getInputEl().getValue()', update: [success:'body',failure:'body'])};
   });
 });

It took some time to find out how to do this, but finally it worked. What one has to know is:

What event do I have to subscribe to and even more complicated how do I access information about the selected entry? The event's name was itemSelectEvent and I managed to access the DOM element to get the selection's value, but I would be very interested to access the ID of the selected entry, too. Up until now, I could not find the ID anywhere in the DOM. Any comments on this problem are welcome!

Wednesday, June 23, 2010

add drag and drop functionality to GRAILS-UI datatable editors

In my application I have added a GRAILS-UI datatable with in-line cell editing functionality at the bottom of my page. Problem was that the date picker element, which is a big fat, didn't fit onto the page and was unusable though. I asked the mailing list for help about that and Matthew Taylor adviced me to try and manipulate the position via CSS. That did not work for me as I figured out that the position was hard-coded in the style property of the div tag.


When I googled for a solution I found a post where it is explained how drag and drop functionality can be added to a YUI calendar widget. I adapted the solution here. Unfortunately I found no better way as to manipulate GRAILS-UI's source code. I edited DataTableTagLib.groovy around line 215 like this:

case 'date':
 editorConstruction += """
  var ${editorName} = 
  new YAHOO.widget.DateCellEditor();\n
  ${editorName}.subscribe('showEvent', function()
  {var dd = new YAHOO.util.DD(
  ${editorName}.getContainerEl());});\n"""
break;

With this, the date picker has become draggable and can be of use for my users again.

Wednesday, June 16, 2010

grails-ui menubar and ajax with remoteFunction

I wanted to turn the links of the grails-ui menubar into ajax remoteFunctions or remoteLinks. This was - once more - far more complicated than I had anticipated. Fortunately almighty google brought me to the solution. The ugly thing: One has to change the code like stated in the jira. Now another ugly thing about the solution is - as indicated by the author - that one still has to provide a url. Not a problem I thought, but the whole thing did not work at all. I had to spend some time, before I could figure out what was going on:

Both - the URL and the remoteFunction - are executed. The remote function comes first (which is a good thing as we will see), but then the URL kicks in and you have a double page change behaviour. The fix is as easy as you can imagine (I wish someone had told me). You have to add 'return false' at the end of the remote function. This stops the URL href feature from being executed at all. VoilĂ  remote function can reign in peace now.

javascript event mechanism for my application

The more and more I ajaxify my grails application,the harder it gets to keep all information on a site up-to-date. In my worst-case scenario there are dozens of dependencies and it is impossible to think of all of them. So the time for a event mechanism has finally come. Why haven't you done that a long time ago, you might ask. Well, I am not really familiar with javascript and as there is no in-editor correction like in my early Java days on Eclipse, I have had a hard time finding bugs in my code.

Lucky me: the cool guys from the YUI project have already taken the worst complexity of the problem of my shoulders. This means that I have used the YUI2 event utility. There are benefits I can not even imagine as a newbie, but features like automatic scope correction, object pass-throughs, etc. sound very cool and benefitial to me. Here is how I have set the whole thing up:

I have modified the main.gsp to introduce an event handler object. Putting it here makes sure that it will be available on every page:


I have not imported any js files as the necessary files have already been included by other grails plugins (mainly grails-ui). Read the doc if you have to.

One a page where I want to have event functionality I first declare an event (in this case it was within a taglib):


Now, whenever necessary I declare a callback function and register it with the event handler as listener:


The callback functions then usually make use of ${remoteFunction} to update a specific part of the page. I would not have guessed it, but if you got rid of spelling mistakes it works like a charm!

Bookmark TagLib

Today I have created a taglib for creating bookmarks. It needs two attributes attrs.type and attrs.id, where type corresponds to the class name. There is only JS code for Internet Explorer and Firefox included, so unfortunately it won't work on other browsers (yet).

def includeBookmarkThisPageLink = {attrs ->
  def url = request.getRequestURL().toString().replaceFirst(".dispatch", "").replaceFirst("/grails", "") + '/' + attrs.id
  def title = attrs.type.get(attrs.id)
  
  out << """"""
 }

springsource STS hangs on startup

I'm using springsource STS for developing my grails application. Usually it works fine, but today when I started it up, it hung up completly. I had to force quit, but even restarting brought no further result. I looked into workspace/.meta/.log


!ENTRY com.springsource.sts.ide.ui 4 0 2010-06-16 08:09:04.833
!MESSAGE An unexpected error occurred while retrieving feed content.
!STACK 1
org.eclipse.core.runtime.CoreException: Download of http://springide.org/blog/feed/ failed: Unexpected HTTP response 404
at com.springsource.sts.internal.core.net.HttpClientTransportService.toException(HttpClientTransportService.java:205)
at com.springsource.sts.internal.core.net.HttpClientTransportService.stream(HttpClientTransportService.java:187)
at com.springsource.sts.core.HttpUtil.stream(HttpUtil.java:112)
at com.springsource.sts.internal.ide.ui.editors.AggregateFeedJob.run(AggregateFeedJob.java:76)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
!SUBENTRY 1 com.springsource.sts.core 4 0 2010-06-16 08:09:04.833
!MESSAGE Download of http://springide.org/blog/feed/ failed: Unexpected HTTP response 404

From this I knew that there was a problem loading a feed. Google found this for me

http://forum.springsource.org/showthread.php?t=85770

Somebody with the same problem found a workaround: One of the projects is causing the block, god knows why. Rename this project's folder -> Start STS -> Close STS -> Name folder back -> Start STS -> WORKS AGAIN! *YES*

Hopefully, someone finds a solution for this and for another bug for which I don't have a solution (I get update source failed errors with string index out of bounds exception (-34)).

Tuesday, June 15, 2010

grails-ui datatable in-line cell editing and dropdowns

Another post about almost the same topic. How to feed the dropdown options for the in-line editing with values from the database. It is quite simple, although I was running in the wrong direction for some time and I was not the first one with this problem.

The simple answer is: you have to add a groovy collection to your model like this (I wanted to be able to choose a user, so I collected user names from the spring security core user class)

def userNames = User.list().collect{it.username}
render(template: '/layouts/template', model: [userNames: userNames])

Now you can do it like this:

..., config:[dropdownOptions: userNames, disableBtns:true]],...

grails-ui datatable in-line cell editing and dates

Today I am playing with the cool in-line cell editing feature of gui:datatable. I wasn't able to get the datePicker working however until I found the solution in a comment on Matthew Taylor's blog.

Apparently, one has to transform the date into a JSON compatible shape. Lucky for us, Matthew has already provided us with such a method:

grailsUITagLibService.dateToJs(myDateObject)

Okay, parsing the String back to a date in the controller was hard work for me. What has been suggested by Matthew in his DemoController produces exceptions. I had to put some own effort into this:

else if(params.field == "date")
         {
          def simpleDateFormat = new java.text.SimpleDateFormat("E MMM dd yyyy HH:mm:ss ZZZZZZZ", Locale.ROOT);

          Date date = simpleDateFormat.parse(params.newValue)
          passage.date = date
         }

externalize datasource settings

Although common practice, it is not so easy to find out how to externalize your settings in a good way. I found the solution in combination of two posts:

How the property file has to look like:
http://stackoverflow.com/questions/970133/externalizing-grails-datasource-configuration

How it should be included by grails:
http://phatness.com/2010/03/how-to-externalize-your-grails-configuration/comment-page-1/#comment-1484

Wednesday, June 9, 2010

take care when using it in groovy each loop

One mistake I am making over and over is the following situation:

 def someCollection = [...]
 someCollection.each{
   println it // it works here
   doSomethingWithClauses{
     println it // it cannot be resolved here
   }
 }

As soon as you use the it in encapsulated code {}, it cannot be resolved anymore. It took me ages to find that mistake in the first place, but unfortunately I produce something like that quite often and then I wonder what the hell is wrong.

What you have to do to make it right is giving the iteration variable another name:

 def someCollection = [...]
 someCollection.each{ someItem ->
   println someItem // it works here
   doSomethingWithClauses{
     println someItem // hey cool it works here too
   }
 }

Tuesday, June 8, 2010

How to get rid of compiler errors

Today I stumbled about a page that gives a pretty cool introduction in how to setup grails 1.1 in eclipse:

http://www.objectpartners.com/2009/05/27/eclipse-setup-for-grails-11-development/

The author also explains how to get rid of compiler errors that are due to the acegi plugin. This helped to erase almost all of them, for the rest I think I should check whether the grails path is set correctly.

including javascript in gsp

Today I have tried out at least a hundred different ways for including js files into my main.gsp by hand. My approach looked like that:



I tried ${resource} first, but then I found this in grails Q&A:

Q: Why won't XXX Javascript Library Display Properly?

A: Sometimes third party javascript libraries depend upon other resources loaded directly from the javascript files themselves like stylesheets. Examples of libraries that do this would be the Yahoo UI libraries and niftycube. When the javascript attempts to load the URL Grails changes the URL so that the resource is not found. Try adding a link using the createLinkTo tag for the particular resource.

So it tried ${createLink}, but in the end nothing worked. I finally succeeded when I discovered that there was an extra taglib to do the trick with YUI JS files, which I was interested in:



The solution can be found in the most obvious place: http://www.grails.org/YUI+Plugin

Really wish I had looked there sooner :-)

Now I wonder if the problem was YUI specific and if my approach would work on other files. Maybe I'm going to find out some day...

Monday, June 7, 2010

grails, sql, datasource

If you are trying to use groovy.sql.Sql to formulate your own queries: don't use the Sql.executeInsert() method as it won't work on HSQLDB. executeInsert() produces an exception claiming "unknown function". But if you use Sql.execute() you won't encounter such a problem.

Before you ask: the advantage of executeInsert would have been that you get the ids of auto-generated columns as return value(s).

Wednesday, June 2, 2010

Querying simple collections in grails

Imagine a domain class has a collection of simple types like e.g.

class Domain
{
static hasMany[strings: String]
}

What would you do if you wanted to have a set of all instances of Domain that have a string called "blabla". Well my first guess was to use the dynamic method findBy, but this does not work. The same goes for using Domain.withCriteria{}. I found the solution in a jira where you can find a feature request about that. Meanwhile you have to do the querying yourself. I have included a static method within my Domain class to avoid DRYness:

static def match(String matchThis)
{
Domain.executeQuery('from DBUser where :name in elements(strings)', [name: matchThis])
}

Problem solved...

Tuesday, June 1, 2010

datasources plugin for grails

In my current project I wanted to have content and security information separated from application specific settings. I therefore wanted to store the information into separate databases. This was far easier than expected with the datasources plugin from grails. I only had to install the plugin and add the file datasources.groovy to /grails-app/conf/

datasources = { 
 datasource(name: 'ds2'){
  domainClasses([org.openlab.settings.GlobalSetting, org.openlab.settings.UserSetting, org.openlab.security.Requestmap])
  pooled(true)
  driverClassName('org.hsqldb.jdbcDriver')
  url('jdbc:hsqldb:mem:devDB')
  username('sa')
  password('')
  dbCreate('create-drop')
  hibernate {
   cache {
    use_second_level_cache(false)
    use_query_cache(false)
   }
  }  
 } 
}

The usual datasource configuration remains intact and is the core or default database. In datasources.groovy you can define as many additional databases as you like. You only have to follow this pattern where the hibernate information is included as well as the definition of domain classes you wish to store in the new database.

The clear distribution of domain classes to datasources makes this approach easy and the only thing you have to consider are foreign key relations when separating the wrong domain classes.