Archive for 2008

Web services in Grails

This article summarizes my experience with web services in Grails (and also Groovy). It will focus the on client side –
consuming web services. If you are looking for server size – providing services, you can use plugins like Metro or XFire.

Options

Once you want to create a web service client in pure groovy, you do not have much options. I have found just two libraries: Groovy SOAP and Groovy WS.

The first one is a deprecated module, so one have to use the Groovy WS.

Sisyphean challenge

Libraries

Making it running is a hard job. There are handy examples on the home page of the Groovy WS, but none of the examples was working. I spent significant amount of time to find out what is the problem. I was receiving this strange error message:

	Oct 26, 2008 9:48:19 PM org.apache.cxf.bus.spring.SpringBusFactory createBus
WARNING: Failed to create application context.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.apache.cxf.wsdl.WSDLManager' defined in class path resource [META-INF/cxf/cxf.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.apache.cxf.wsdl11.WSDLManagerImpl]: Constructor threw exception; nested exception is java.lang.ClassCastException: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:881)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:837)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:440)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
        at java.security.AccessController.doPrivileged(Native Method)
 
 
	blah blah blah

After investigation I did find that the problem is with libraries. The groovy WS library does not like xerces and xml-apis libraries.

SSL

The second difficulty was SSL. I do not remember details. It was somehow unable to download WSDL over SSL. It was necessary to download it and store into file system.

Compatibility

GroovyWS uses the Apache CXF libraries and they do not support RPC/Encoded web services.

java.lang.RuntimeException: Error compiling schema from WSDL at {https://my.url?wsdl}: undefined simple or complex type 'soapenc:Array' 
at org.apache.cxf.endpoint.dynamic.DynamicClientFactory$InnerErrorListener.error(DynamicClientFactory.java:418)

Conclusion

I did not find the groovyWS to be a matured library. It is possible to use it for consuming web services, but only for the simplest ones. As soon as there is SSL, authentication… one have to use a “bigger hammer”. In my case, the hammer was Netbeans, that generated all the necessary classes.

Last, but not least. At the beginning I was not really sure what is the problem. I was suspecting the web services not to work correctly. So, I did use the soapUI testing tool to check that the web services are alive.

String similarity detection

I was looking for a simple string similarity detection algorithm and I did find the one on CatalySoft. Since I like it and I found it useful, I did create a groovy equivalent of it.

Here is the code:

public class LetterPairSimilarity {
 
  /** @return an array of adjacent letter pairs contained in the input string */
  private static def letterPairs(String str) {
    (0..str.size()-2).collect{str[it,it+1]} 
  }
 
  /** @return an ArrayList of 2-character Strings. */
  private static def wordLetterPairs(String str) {
    (str.split("\\s").collect{it} - [""]).collect{ letterPairs(it) }.flatten()
  }
 
  /** @return lexical similarity value in the range [0,1] */
  public static double compareStrings(String str1, String str2) {
    if (!str1 || !str2 || str1=="" || str2=="") {return 0.0}
    def p1=wordLetterPairs(str1.toUpperCase())
    def p2=wordLetterPairs(str2.toUpperCase())
 
    2*p1.intersect(p2).size() / (p1+p2).size
  }
}

Modalbox in Grails

There is a nice and handy javascript library for creating kind of a modal “window”, similar to the famous lightbox. Here are few lines of code to make it running in a Grails application

Installation

First of all, you have to download the library. The easiest way is to install a plugin modalbox

grails install-plugin modalbox

There was a slight problem in version 0.2. So, check your plugins/modalbox-0.2/grails-app/taglib/ModalboxTagLib.groovy. The version was not correct and the script tags were not correctly ended. Here is my tag library.

class ModalboxTagLib {
 
    static namespace = "modalbox"
 
    def createLink = { attrs,body ->
        // By default trigger onclick, but allow onmouseover etc
        def event = attrs.event ? attrs.event : 'onclick';
 
        // linkname only supported for backwards-compatibility. Default it to empty-string
        def linkname = attrs.linkname ? attrs.linkname : ""
 
        out << """
            <a href='${g.createLink(attrs)}' title='${attrs['title']}' ${event}='Modalbox.show(this.href, {title: this.title, width: ${attrs['width']}}); return false;'>${linkname}${body.call()}</a>
        """
    }
 
    def modalIncludes = {
        def jsFolder    = createLinkTo(dir:'plugins',file:'modalbox-0.2/js/modalbox')
        def cssFolder   = createLinkTo(dir:'plugins',file:'modalbox-0.2/css')
 
        out << """
            <script type='text/javascript' src='${jsFolder}/prototype.js' ></script>
    		<script type='text/javascript' src='${jsFolder}/scriptaculous.js?load=effects'></script>
    		<script type='text/javascript' src='${jsFolder}/modalbox.js' ></script>
    		<link rel='stylesheet' href='${cssFolder}/modalbox.css' />
        """
    }
}

“Parent” view

In the view that will call the Modalbox, use tag modalInclude like this one.

<modalbox:createLink controller="book" action="showDetails" params="[bookId:book.id]" title="Book details" width="500">book</modalbox:createLink>

Once clicked, it calls book/showDetails

“Modalbox” view

The view of book/showDetails is quite simple. You can create any static page and it will be displayed. If you want something more “spicy”, use AJAX.

Book details
 
<g:formRemote name="myForm" url="[controller:'book',action:'findSimilar']" update="[success:'similar']" onComplete="Modalbox.resizeToContent()">
	<input type="hidden" name="bookId" value="${book.id}" />
	<input id='search' name='search' />
	<input type="submit" value="Find similar" />
</g:formRemote >
 
<div id="similar">
</div>
 
<a href="#" title="Close window" onclick="Modalbox.hide(); return false;">Close</a>

Notice the resizeToContent() method. It assures, that the content that will come via AJAX will fit. Last, but not least; for comfortable close, there is the last line.

Enjoy it.

Grails: internationalization in the service

Today I spent some time by creation of localized messages in a service. Here is a small tutorial.

1. Create your service

grails create-service Local

2. Add a messageSource variable to your new service

class LocalService {
  def messageSource
}

3. Use it in a service method

// Initialize parameters
Object[] testArgs = {}
def msg = messageSource.resolveCode("message.code.to.translate", new java.util.Locale("EN")).format(testArgs)

4. Finally edit the grails-app/i18n/messages.properties

message.code.to.translate=It works!!!

Monitoring number of SQL queries in MySQL

I have created a new application in Grails and surprisingly, in production environment it was slower than on my laptop. Production administrator found that my application generate too many SQL queries. The delay was caused by network latency. So, I had to find a way how to monitor number of SQL queries on MySQL server.

For monitoring of the current session, there is a handy command:

SHOW STATUS WHERE variable_name='Com_select'

For monitoring of all the sessions, there is a switch:

SHOW global STATUS WHERE variable_name='Com_select'

All variables could be listed by

SHOW STATUS