Thursday, December 06, 2007

Flot plotting in Grails:

I came across the FLOT package (Ref: http://code.google.com/p/flot/ ) while reading Ajaxian (Ref: http://ajaxian.com/archives/plotting-in-jquery ). Flot uses the jQuerry package (Ref: http://jquery.com/ ) to do client side plotting. I wanted to see how this works when dropped into Grails. As expected the results are quite nice.

The set up is rather easy. Obtain the jquery.flot-0.1.js and jquery-1.2.1.min.js files (your versions will obviously change with the march of time) and place these in your web-app/js directory of your grails project.
You will need to reference these in your GSP page HEAD tag with something like:

  <g:javascript library="jquery-1.2.1.min"/>
<g:javascript library="jquery.flot-0.1"/>


At this point your are basically done. You can review the URL's at the top of this page for better information straight from the source. Basically, you will need to place into the BODY tag of your GSP something like the following:

 <div id="placeholder2" style="margin-left:100px;width:600px;height:300px;"></div>

<script id="source2" language="javascript" type="text/javascript">
$(function () {
var d1 = [];
for (var i = 0; i < 14; i += 0.5)
d1.push([i, Math.sin(i)]);

var d2 = ${array};

$.plot($("#placeholder2"), [ d1, d2 ]);
});
</script>

Here is the only interesting aspect of all this. The line var d2 = ${array} is referencing a list from the controller:

  def jflotPlot = {
def array = [[4, 6], [5, 7], [9, 2]]
[array: array]
}


Likely your controller will get more interesting data. ;) This is just a really quick and dirty copy paste job of the examples from the above references into a Grails app. Flot can already at version 0.1 do more types and plots and zooming and other very slick features (see the demos at the flot site ). Integration with Grails is quick and easy.

enjoy
Doug

Wednesday, November 14, 2007

Grails + ROME + geoRSS

Grails + ROME + geoRSS

If you are looking to do some RSS/ATOM feeds in Grails you likely are looking at either at the examples that Glen Smith has done (ref: http://blogs.bytecode.com.au/glen/2006/12/22/1166781151213.html ) or to work with the Feeds plugins (ref: http://grails.org/Feeds+Plugin ) by Marc Palmer. Both are excellent places to start.

What I want to talk about there is adding geospatial data to a RSS feed in the Grails framework by building off this work. The above efforts leverage off the ROME package from http://rome.dev.java.net. For geospatial elements there is the GeoRSS Module for ROME by Marc Wick (ref: http://georss.geonames.org ).

Adding this ability to a Grails project is rather easy. Obviously you need to have the Rome and GeoRSS jar files from these referenced sites in your project lib directory. From there you can do something like the following. Please note these examples are based on the work of these previously mentioned individuals and the credit is theirs. I just glued things together.

So likely you will end up with something like this in your controller:

  // some import for this..   (watch me polute my namespace) ;)
import com.sun.syndication.feed.synd.*;
import com.sun.syndication.io.SyndFeedOutput;
import com.sun.syndication.feed.module.georss.*;
import com.sun.syndication.feed.module.georss.geometries.*;


def supportedFormats = ["rss_0.90", "rss_0.91", "rss_0.92", "rss_0.93", "rss_0.94", "rss_1.0", "rss_2.0", "atom_0.3"]

def rss = {
render(text: getFeed("atom_0.3"), contentType: "text/xml", encoding: "UTF-8")
}

def all = {
def format = params.id
if (supportedFormats.contains(format)) {
render(text: getFeed(format), contentType: "text/xml", encoding: "UTF-8")
} else {
response.sendError(response.SC_FORBIDDEN);
}
}

def getFeed(feedType) {

def ageModels = AgeModel.list()
def jdb = Sql.newInstance('[ WE ARE MAKING SQL CALLS SO THE CONNECT STRING GOES HERE. GORM WOULD BE NICER, BUT NOT AN OPTION FOR ME')

def entries = []
ageModels.each {ageModel ->
List functionData = jdb.rows("select latitude_degrees, longitude_degrees from hole where leg like ${ageModel.leg} and site like ${ageModel.site} and hole like '${ageModel.hole}'")
def locationString = functionData[0][1] + ", " + functionData[0][0]

def desc = new SyndContentImpl(type: "text/plain", value: "Entry for leg " + ageModel.leg + " locate at " + locationString + ageModel.rating + " " + ageModel.status);
def entry = new SyndEntryImpl(title: ageModel.leg + "_" +ageModel.site + ageModel.hole + " - " + ageModel.user,
link: 'http://localhost:8080/janusAmp/rest/lsh/' + ageModel.leg + "/" + ageModel.site+ "/"+ageModel.hole,
publishedDate: ageModel.date, description: desc);

// Select the style of encoding you want to do.
// def geoRSSModule = new W3CGeoModuleImpl()
// def geoRSSModule = new GMLModuleImpl()
def geoRSSModule = new SimpleModuleImpl()
geoRSSModule.setPosition(new Position(functionData[0][0], functionData[0][1]));
entry.getModules().add(geoRSSModule);
entries.add(entry);
}

SyndFeed feed = new SyndFeedImpl(feedType: feedType, title: 'Recently added age models',
link: 'http://www.chronos.org', description: 'List of age models from Janus data',
entries: entries);

StringWriter writer = new StringWriter();
SyndFeedOutput output = new SyndFeedOutput();
output.output(feed, writer);
writer.close();

return writer.toString();
}

The only thing different than what Glen, shows in his blog is the addition of the bold lines to add in the geoRss element. The result... geospatially enabled RSS feeds in the Grails framework (and anywhere else for Groovy and Java of course)

A few things to note:
a) While Google Earth and Google Maps should read this output I had some issues with the resulting files. Running things through the validator at: http://cite.opengeospatial.org/test_engine/georss_validator/ one gets some errors related to the namespaces. I noticed that the examples for RSS feeds at http://georss.org/ even had some issues. While the ATOM version validates ok the RSS based feed errors out in the same way that my generated feeds do. Likely this is an issue with ROME and if I track down the issue I will follow up on it. Until the feeds validate these feeds do not appear to work in Google Earth or Maps.
b) However, you can generate the rss version 2 feed with the SimpleModuleImpl() from the georss jar file and that will translate correctly with the rss to kml style sheet found at http://www.kovacevic.nl/hacks/kml/georss2kml.xsl (ref: http://www.kovacevic.nl/blog ).

RSS to KML via XSL in Grails:

So you can drop into your controller something like:
  def kml = {
def xslPath = getAppPathService.serviceMethod().toString() + "georss2kml.xsl"
def kmlxsl = new File(xslPath).getText().toString()
def rssxml = getFeed("rss_2.0")

def mywriter = new StringWriter()

def factory = TransformerFactory.newInstance()
def transformer = factory.newTransformer(new StreamSource(new StringReader(kmlxsl)))
transformer.transform(new StreamSource(new StringReader(rssxml)), new StreamResult(mywriter))

render(text: mywriter.toString(), contentType: "text/xml", encoding: "UTF-8")
}
you make also need the following in your code for XSL support:
//  for the XSLT transform
import javax.xml.transform.TransformerFactory
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.stream.StreamSource

into your controller where AppPathService is (not mine.. but I don't have the reference for this.. bad me)

 import org.codehaus.groovy.grails.commons.*
import org.apache.commons.logging.*

import org.springframework.beans.BeansException
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware

class GetAppPathService implements ApplicationContextAware {

GrailsApplication grailsApplication
ApplicationContext appCtx

boolean transactional = true

def void setApplicationContext(ApplicationContext arg0) throws BeansException {
appCtx = arg0;
}
def serviceMethod() {
String applicationPath = "${appCtx?.getServletContext()?.getRealPath("/")}"
return applicationPath
}
}
What the KML does is load in the XSL file (it's looking at the root of the response which will be your web-apps directory. You can move and alter this as you wish. Of course you could simple place the XSL in the controller too like at http://groovy.codehaus.org/Processing+XML+with+XSLT which is what kml method is based on. I like this this way a bit better. At this point you should be generating KML from this and Google Earth and Google Maps should load and monitor this URL just fine.

I do want the get the GeoRSS feed vaildating though and will work on that effort as noted.

enjoy
Doug

Monday, November 12, 2007

Checking REST and RSS style feeds

Continuing to do work with REST in Grails as well as RSS feeds. One issue is testing some of these URL's. In my last post I spoke about a groovy client using Apache's http client package which is quite nice for doing testing with. I also ran across this Firefox extension (RestTest) which is quite handy.

I also found this to a nice tool for testing RSS feeds with since it's not hard to get into a situation these days where your browser will either try and show you the RSS styled up or even redirect you to Google Reader or some other RSS reader. You can put the RSS/ATOM URL into this extensions interface and simply retrieve the XML of your feed for inspection during coding.

On the topic of RSS/ATOM and Grails check out the Feeds Plugin at the Grails site.

Tuesday, October 23, 2007

Groovy REST client with Apache httpclient (setting accept request-header value)

Been doing quite a bit with REST style services in Grails. In particular trying to follow closes REST best practices approaches. One of these approaches is to inspect the HTTP Accept header values. (Ref: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html).

While creating these services a person really needs a simple client that they can alter the accept request-header field with. I created one using the Apache httpclient package (http://jakarta.apache.org/httpcomponents/httpclient-3.x/).

Simply download and place the commons-httpclient-*.jar file into your groovy lib directory (or somewhere you class loader will find it) and generate a Groovy program like:


import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.GetMethod;

def url = "URL TO SERVICE"
client = new HttpClient()
get = new GetMethod(url)
get.setRequestHeader("Accept", "text/xml")
client.executeMethod(get)

println get.getResponseBodyAsString().toString()


It's a simple client and one can alter the ACCEPT header value easily to check and validate REST services response to various settings of accept request-header.

Monday, September 17, 2007

Using CHRONOS Timescale Converter Service Calls

The timescale converter web application accessible through the CHRONOS portal (Ref: http://portal.chronos.org/gridsphere/gridsphere?cid=tools_tsconvert) uses publicly available web service calls to the timescale service described by the WSDL document located at http://services.chronos.org:9090/axis/timescales.jws?wsdl. These services are available for use on any platform.

Simple clients to these end points can be created in any modern programming language. Examples using Python and Groovy, two popular dynamic languages, are given below. Examples using Ruby or C# would be quite similar.

Example using Python

#!/usr/bin/python
#

import re, string
from SOAPpy import SOAPProxy

server = SOAPProxy("http://services.chronos.org:9090/axis/timescales.jws")
time = 20.0

while time < 40.0:

result = server.convertTime("GTS 2004", "Berggren 95",time)

print time , result

time = time + 0.1



Example using Groovy

import groovy.net.soap.SoapClient

def proxy = new SoapClient("http://services.chronos.org:9090/axis/timescales.jws?wsdl")


def serviceClosure = {

time -> return proxy.convertTime("GTS 2004", "Berggren 95", time)
}

for (float f = 20;f< 40.0; f=f+0.1) {
println serviceClosure(f)
}

A slightly more advanced example of a real-world application of these services is the implementation of the service in a Java-based web application server. In this case, a user would use e.g. the Xfire (http://xfire.codehaus.org/Client+and+Server+Stub+Generation+from+WSDL) or Apache Axis (http://ws.apache.org/axis/java/client-side-axis.html) packages to generate a library from the WSDL file. The resulting library could then be easily called from various locations in the application with only a few lines of code.

The first step would involve the creation of the stub classes in a WSDL-to-Java process. We will use the Apache Axis package in this example but the process is similar for Xfire or C# style environments. The initial stub classes are generated through a call like:

java -cp axis.jar:commons-logging-1.0.4.jar:commons-discovery-0.2.jar:axis-ant.jar:log4j-1.2.8.jar:wsdl4j-1.5.1.jar:jaxrpc.jar:saaj.jar org.apache.axis.wsdl.WSDL2Java -o . -d Session -p org.chronos.ws http://services.chronos.org:9090/axis/timescales.jws?wsdl

The result of this call is a set of Java source files that would then be compiled:

javac -classpath axis.jar:commons-logging-1.0.4.jar:commons-discovery-0.2.jar:axis-ant.jar:log4j-1.2.8.jar:wsdl4j-1.5.1.jar:jaxrpc.jar:saaj.jar org/chronos/ws/*.java

and the resulting class files collected into a jar file:

jar -cvf timescale.jar org/chronos/ws/*.class

The resulting jar file can then be used to greatly simplify the creation of clients in Java or any other Java byte code compatible language like Jruby, Jpython or Groovy.

An example of Java client that gets the color scheme for the Geological Time Scale is:

public class wsClient {
public static void main(String [] args) throws Exception {

// Make a service
org.chronos.ws.TimescalesService service = new org.chronos.ws.TimescalesServiceLocator();

// Now use the service to get a stub to the service org.chronos.ws.Timescales_PortType ts = service.gettimescales();

// Make the actual call

System.out.println("call " + ts.getColorScales());

}

}


A Groovy client that uses the jar file (here using the batch convert method for time conversion) is:
import java.text.DecimalFormat

// Make a service

def org.chronos.ws.TimescalesService service = new org.chronos.ws.TimescalesServiceLocator();

// Now use the service to get a stub to the service

def org.chronos.ws.Timescales_PortType ts = service.gettimescales();

// Make the actual call

def batchResults = (ts.convertTimeBatch("GTS 2004", "Berggren 95", 0.toDouble(), 60.toDouble(), 1.toDouble()));


DecimalFormat df2 = new DecimalFormat( "#,###,###,##0.000" );

// Closure for 2 place formating

def decf2 = {

value -> return new Double(df2.format(value)).doubleValue();

}

for (item in batchResults) {
println decf2(item)
}


These examples illustrate the process involved in the creation of clients using only the WSDL URL. Once created, jar libraries like those at the end of the process can be dropped into application server class paths and used in frameworks like Grails (http://www.grails.org), Seam ( http://www.jboss.com/products/seam) or JSR-168 portal environments like Gridsphere (http://www.gridsphere.org). Any application or tool with network access can invoke these services in a similar manner.

All CHRONOS services a similar pattern and can be utilized in web-based or stand-alone clients that have access to the network.

Tuesday, September 04, 2007

Grails SQL date formating lib

Been working with Grails more and created a little tag lib I thought I would post up for others. The date that comes out of the domains is a rather ugly SQL date style so I create a tag lib with the following code:

 def formatSqlDate = { attrs -> 
def String startdatetime = "${attrs['targetDate']}"
def DateFormat odf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.S");
def DateFormat df = new SimpleDateFormat( "MMM d, ''yy" );
out << df.format(odf.parse(startdatetime))
}
Then I can simple reference it with:

<g:formatsqldate targetdate="${domain.dateObject}">

A person can mode the date format string all they want and also could put in various cases or a flag to select a format style if they wished.

Friday, July 27, 2007

Terminal shell in eclipse


The state of working with Grails in Eclipse is not the best for me. Using the external tool call has been a pain and I have been using an external terminal shell. Today I went looking for a terminal shell solution built into Eclipse and found the Target Management Project.

You can install the components for this via the Eclipse update manager with the information from: http://europa-mirror1.eclipse.org/dsdp/tm/updates/.

Once this is done use the menu sequence Window -> Show_View -> Other and select the Remote Systems folder. From there I added "Remote System Details" (not really needed) and "Remote Shell". Using the triangle menu for this latter element I selected the default local connection.

After all this though.. failure.. it exec's each command out to the shell and as such there is no way to re-attach and kill a process easily. If you run grails run-app it's disconnected to one has to ps its PID and kill it. (not optimal).

After some looking I found sshView (http://www.eclipse-plugins.info/eclipse/plugin_details.jsp?id=1187). This installed but gave some very strange behavior and never was able to get it to successfully work. You can access it in the same sequence as above and look for sshview.

In the end there is easyShell. However, all this does is launch the shell I was using when I started this journey. Yes, you can configure it to open up in the directory the file is in and you can get to rather easily through the contextual menu. In the end not really worth the time and effort and still no good built into the IDE view shell solutions that I can find at least.