Moving My Google Maps Mashup to Grails, part two

I made a few improvements to my Google Maps mashup, and though they’re not as significant as the changes made in my previous posts, I still wanted to make a record of them.

I discussed in my last post the problem I had exposing my domain objects as JSON strings. To summarize the problem:

  1. In order to use the Google Maps API, I need to be able to pass latitude and longitude information from my Location objects (written in Groovy) into JavaScript. Grails pulls the data from a database and populates all the Locations, which are passed from the controller to the view. Somehow the JavaScript in the view needs to extract the coordinates in order to draw the markers on the map.
  2. The page where I want to do the rendering actually lists courses, not just locations. My Course class has an attribute of type Location, which is fine, but means I need to traverse a relationship in order to access the data I need. Normally that wouldn’t be an issue, but JavaScript doesn’t know how to do that.
  3. I can use the convenient Grails “converters” plugin to translate my Course objects into JSON, but that leads to difficulties as well. It seems that the converter doesn’t follow relationships, or, rather that it just inserts the foreign key value where the relationship goes. In other words, the JSON version of a particular Course only lists an integer in the location field.
  4. As a result of (3), I decided to pass both the collection of Course objects and the collection of Location objects to the view. That in itself was awkward, because it meant I had to “dereference” the location array myself for each course, which felt highly brittle.
  5. Also, when the converter operated, it dumped all the information about my objects directly into the web page, where it could be read by anyone who knows how to do a “view source” command. Not good.

The way I solved the problem was to create a special class in my Grails project called CourseMapData:


class CourseMapData {
    String title
    Date startDate
    Date endDate
    String city
    String state
    double latitude
    double longitude
}

That class encapsulates all the data I need out of both the Course object and its associated location. It also leaves out any attributes that might possibly be sensitive. Since it doesn’t have any associations to any other classes, I can transform it into JSON without losing any information.

Since it’s not actually a domain class, I put the source file in the src/groovy folder of my Grails project. In my CourseController, I then added the necessary translation:


def list = {
    if(!params.max)params.max = 10
    def courseList = Course.list(params)
    def cmList = []
    courseList.each { c ->
        def cm = new CourseMapData()
        cm.title = c.title
        cm.startDate = c.startDate
        cm.endDate = c.endDate
        cm.city = c.location.city
        cm.state = c.location.state
        cm.latitude = c.location.latitude
        cm.longitude = c.location.longitude
        cmList << cm
    }

    [ courseList:courseList, cmList:cmList]
}

I was hoping their might be a more elegant way to populate the object (something similar to how request parameters are passed into objects using “obj.properties = params“), but it was easy enough to just write them out. That’s especially true because the values come from both Course and Location.

By passing the collection of CourseDataObjects, my JavaScript code in my list.gsp page reduces to:


function initialize() {
    map = new google.maps.Map2($("map"));
    var homeJSON = ${Location.findByCityAndState('Marlborough','CT').encodeAsJSON()};
    home = new google.maps.LatLng(homeJSON.latitude,homeJSON.longitude);
    map.setCenter(home, 4);

    var cmsJSON = ${[cms:cmList].encodeAsJSON()};
    var courseDataArray = cmsJSON.cms;

    processCourses(courseDataArray);

    map.enableScrollWheelZoom();
    map.addControl(new google.maps.LargeMapControl());
    map.addControl(new google.maps.MapTypeControl());
    map.addControl(new google.maps.OverviewMapControl());
}
google.setOnLoadCallback(initialize);

Now I’m only converting one collection (cmList), and although it dumps a lot of code in the page source, nothing in it is particularly sensitive. The rest is essentially the same as before.

I’m still not quite ready to put my application online, because it hasn’t been secured yet. I plan to use a beforeInterceptor to separate the admin pages from the public pages. It’s a little awkward, though, because this isn’t a site that I actually want anyone but myself to modify. Still, I’d like to be able to access it myself when I’m traveling in order to add in new courses and/or locations.

Hopefully I’ll get a chance to add that functionality soon.

As an aside, I fixed another issue that occurred to me. Obviously I don’t want to have to enter a latitude and a longitude when I create a new Location. I have an earlier post here that talks about using the Google geocoder service to do the translation for me. I finally got around to adding that functionality to my Grails application.

Now the save method in my LocationController looks like:


def save = {
    def location = new Location()
    location.properties = params
    if (location.latitude == 0 && location.longitude == 0) {
        // Use the Google Maps geocoder to fill in latitude and longitude
        def key = 'longUglyGoogleMapsKey'
        def base = 'http://maps.google.com/maps/geo'
        def query = "q=${location.city},+${location.state}&output=csv&key=${key}"
        def url_string = base + '?q=' +
            ',+' + URLEncoder.encode(location.city,"UTF-8") +
            ',+' + URLEncoder.encode(location.state,"UTF-8") + 
           "&output=csv&key=${key}"
        def results = new URL(url_string).text.split(',')
        location.latitude = results[-2].toDouble();
        location.longitude = results[-1].toDouble();
    }
    if(location.save()) {
        flash.message = "Location ${location.city}, ${location.state} created."
        redirect(action:show,id:location.id)
    } else {
        render(view:'create',model:[location:location])
    }
}

To use it, I modified my create.gsp page for Locations to include the phrase:

“Note: leave latitude and longitude empty or 0.0 to use the embedded geocoder.”

Then when I enter the data, I can see the latitude and longitude fill in automatically. Sweet.

Moving My Google Maps Mashup to Grails, part one

The Google Maps API is easy to use. The basic idea is to create a Map2 object (the former GMap2, now known as google.maps.Map2) and add Marker objects to it. The Marker objects then use InfoWindow objects to display all the information for that marker, which can either appear on load, or you can set up an event (like a click) to make the info display. I also like the Polyline objects, especially because you can make them follow geodesics.

While there are many good tutorials about Google Maps on the web, my favorite reference is Scott Davis’s book Google Maps API, v2. I purchased the eBook version at Pragmatic Programmer and really like it.

Since the API is in JavaScript, the key issue for me is how to get my location data into the code. It’s all in a database, but it’s also considered poor design to talk directly to a database from the view. When I wrote my app originally in Java, I did the normal process of building a data access layer in front of the database and then using a servlet to access it, turn the locations into Java objects, and then pass the whole lot to the view as request attributes. That’s all well and good, but of course JavaScript code can’t read Java objects directly.

Dave Crane has a good discussion of this issue in his book Ajax in Action. (Of course it’s a good discussion — everything in that book is good. :)) I recently also picked up his Prototype and Scriptaculous in Action book, and it too talked about the mismatch problem.

Crane lists the available options as

  • Content-centric, where the back-end code returns already-formatted HTML which a web page can render,
  • Script-centric, where actual JavaScript code is returned and executed by the browser, and
  • Data-centric, where the information is returned in some format that both sides can understand.

For my situation, the data-centric approach is really the only option. I’m not returning information that I want to render directly. My hope is for Google Maps to do all the rendering. For the same reason, I don’t want to return actual code, because that wouldn’t simplify anything.

I’m going with the data approach. Since JavaScript doesn’t understand either Java or Groovy objects, I need to select an intermediate format for the data. That also means I need to be able to generate the format from the Java or Groovy objects and then parse it in JavaScript.

As Crane points out, the major options are either XML or JSON.

I do remember back when XML was popular. I thought it was pretty cool, too, during that late 90’s and the first few years of this century. But XML gets parsed into DOM trees, and the DOM access API’s in JavaScript are bulky and cumbersome.

(But not as ugly as those in Java. I’ve always been amazed how badly Java interacts with XML, especially now that seemingly every business must, by law, build a service oriented architecture implementing web services.)

Groovy’s approach to XML is refreshingly easy, but again it doesn’t really help me here. I need to get my latitudes and longitudes into the constructor of Google’s LatLng class, which is what Marker uses to draw at a particular location.

The other intermediate format possibility is JSON. I really like JSON. It’s easy, short, and quite flexible. I wonder if JSON had been around when XML first became available if we’d all be using it instead.

Before I get to that, though, I have to mention another possibility that I actually used in my original implementation. There I relied on JSP tags, which generated JavaScript as though it was any other set of strings.

Assuming my courses all contain locations, and that each location has a latitude and a longitude, what I did was:


<c:forEach var="course" items="${courses}">
    loc = new google.maps.LatLng(
        "${course.location.latitude}","${course.location.longitude}");
    // etc...
</c:forEach>

and went on from there. The benefit to this approach is that I could access the courses directly as Java objects, using the normal dot notation to get where I needed to go.

The downside to this approach is that it makes for some truly ugly JavaScript. Note that I don’t have the word “var” in front of my (JavaScript) loc variable above. I can’t, because my <c:forEach> loop is going to generate a new copy of that line — and every other line in the loop — for every single course. I also didn’t try to store the values as I went along, which I suppose I could have done by declaring an array ahead of time, assigning each LatLng to an array at the “i”th index location, and manually incrementing the index. The effect is that I’m writing out each iteration of every loop.

I have to say, though, that the approach did work. I saved myself the difficulty of translating from Java objects to anything else, at the expense of repeating about a dozen lines of code over and over again for every course.

That can’t be the “right” way to go. Since I was porting to Grails anyway, I investigated what tools it (and, of course, Groovy) brought to the task.

Chapter 9 of Graeme Rocher’s book The Definitive Guide to Grails discusses the Grails tags available for Ajax applications. He goes through tags <g:remoteField>, <g:remoteLink>, and <g:formRemote> in some detail. Unfortunately for me, all three of those tags have an attribute called “update” which indicates which <div> element will contain the resulting data.

I don’t want to update a <div> element. I want numbers back.

Incidentally, in order to get a better sense of what was going on, I used those tags and looked at the resulting generated HTML. Not surprisingly, the tags all created Ajax.Updater calls in Prototype, my library of choice. What I wanted was an Ajax.Request, from whose results I could extract the text data and parse away.

Since the DGG book is getting a bit dated (already! I hope a good revision when Grails goes to 1.0 in October is already in the works), I checked the tag reference at the Grails web site. In addition to the above three tags, it also listed <g:remoteFunction> and <g:submitToRemote>, but neither of those were necessarily appropriate either.

The fact is, however, the data I need is already in the web page. It’s just in the form of a collection of instances of the Groovy classes called Course and Location, which are part of my domain model. All I need to do is to convert them to JSON and I’m off to the races.

Enter the Converters plug-in project for Grails, which is even built into Grails 0.6. The Converters plugin gives a convenient (according to the web site, YMMV) way to convert your “domain objects, maps, and lists to JSON or XML very quickly.”

The web page has examples on it, but I must admit I found them rather confusing. It’s entirely possible I’m missing something obvious. For example, I’m still not sure how it would help me to do a “render Course.get(0) as JSON” in a controller. I guess in my page I could set up a normal Ajax.Request myself to call an action implemented that way, but I’m not sure that’s they way the example is intended to be used.

I also got messed up when I tried to convert my collection to JSON, rather than a single object. The line above,

render Course.get(0) as JSON

works just fine, but

render courseList as JSON

throws exceptions. Eventually I wound up going to

render [crs:courseList] as JSON

which did the job, at the price of introducing a variable I don’t need. Today, though, I did some poking around on the Grails User mailing list archive at Nabble and found that

def data = courseList as Course[]
render data as JSON

might work instead, but I haven’t yet tried that out.

What I ultimately did was to go into my GSP page and use the converter’s encodeAsJSON() function. My page contains:


function initialize() {
    map = new google.maps.Map2($("map"));
    var homeJSON = ${Location.findByCityAndState('Marlborough','CT')
        .encodeAsJSON()};
    home = new google.maps.LatLng(homeJSON.latitude,homeJSON.longitude);
    map.setCenter(home, 4);

    // Transform the course list to a JSON object
    //  whose 'crs' property is the list of individual courses
    var coursesJSON = ${[crs:courseList].encodeAsJSON()};

    // Do the same with the locations
    var locsJSON = ${[locs:locationList].encodeAsJSON()};
    var courseArray = coursesJSON.crs;
    var locsArray = locsJSON.locs;

    processCourses(courseArray,locsArray);

    map.enableScrollWheelZoom();
    map.addControl(new google.maps.LargeMapControl());
    map.addControl(new google.maps.MapTypeControl());
    map.addControl(new google.maps.OverviewMapControl());
}
google.setOnLoadCallback(initialize);

That brings me to my other difficulty with using the JSON builder. My location objects are not normally embedded in my course GSP pages. I expected to get to the locations by traversing from the course to its location. The problem is, if you look at the generated JavaScript, the first Course object becomes

{
      "startDate": "2005-04-04 00:00:00.0",
      "title": "Intro Java with WSAD",
      "class": "Course",
      "endDate": "2005-04-08 00:00:00.0",
      "client": 1,
      "location": 1,
      "id": 1,
}

which means its location is just a foreign key value, not an actual object. I can’t traverse from Course to Location in JSON form. Since I want information from both objects (i.e., the Course title and dates, and the Location’s latitude and longitude), I had to make both sets of data available to my view.

(Also, note that the date is now firmly a string. I tried parsing it using JavaScript’s Date class, but no luck.)

That, at least, was easy. My CourseController.groovy class originally had


def list = {
    if(!params.max)params.max = 10
    [ courseList: Course.list( params )]
}

in it, and now it has


def list = {
    if(!params.max)params.max = 10
    [ courseList: Course.list( params ), locationList: Location.list() ]
}

I had to be sure not to pass the params argument to Location.list(), because while I want the course listing table to have pagination, I don’t know which locations I’m going to need for the courses so I have to send them all. It also forces me to traverse the relationship myself. In my processCourses function, I have


function processCourses(courseArray, locsArray) {
    // === Plot the markers ===
    for (var i = 0; i < courseArray.length; i++) {
        var c = courseArray[i];
        var loc = locsArray[c.location - 1];
        var latlng = new google.maps.LatLng(loc.latitude,loc.longitude);
        var label = "<b>" + c.title + "</b><br />" +
            "<em>" + loc.city + ", " + loc.state + "</em><br />" +
            c.startDate.split(' ')[0] + " -- " +
            c.endDate.split(' ')[0];

        var marker = createMarker(latlng, label);
        map.addOverlay(marker);

        var polylineOptions = {geodesic:true};
        var polyline = new google.maps.Polyline(new Array(home,latlng),
             "#ff0000",2,0.5,polylineOptions);
        map.addOverlay(polyline);
    }
}

and you can see that my location comes from selecting the proper element out of the locations array, based on the index value that comes from course.location. It’s not pretty, but it does seem to work.

This leaves me with two issues that have kept me from putting my application on the web yet.

  1. By default, Grails applications let the user add, edit, and remove elements as well as list them. I have to add some login mechanism before I expose that functionality. 🙂 Jason Rudolph in his Getting Started with Grails book used an interceptor for that. I’ll no doubt start there.
  2. Rendering the course as a JSON object embeds all of its details inside the JavaScript.

That’s a much bigger problem. My course objects have references to clients and even to rates in them, and I’d just as soon not expose that to anyone capable of doing a “view source” on the page (security by obscurity, indeed). I’m not exactly sure how I’m going to handle that.

My first thought is to create some kind of “narrow” interface to course objects that would expose only the fields I need to show. I’m going to try creating a class called, say, CourseMapData, which will consist of


class CourseMapData {
    String title
    Date startDate
    Date endDate
    String city
    String state
    double longitude
    double latitude
}

which will be populated from a Course object and its associated Location, send that to the view and convert it to JSON. I think that will work, but it’ll mean adding a new Groovy class that isn’t technically a domain object from the Grails point of view. I haven’t done that before, so that’s a good learning opportunity. Of course, I’ll also have to put in a method to do the conversion, too, and that method isn’t exactly a controller action, so I’m not sure where it goes, either.

I guess that’s part of the problem with eliminating formal DAO classes. Grails supplies finders automatically, which is great. I loved being able to use Location.findByCityAndState() without having to write anything. But I would normally put my conversion method in the Course DAO, and now I’m not so sure what to do.

When I get those issues worked out, I’ll no doubt post a “part two” entry here.

Moving My Google Maps Mashup to Grails, part zero

I’m not quite ready to make it live on the web yet, but I’ve just about finished porting my Google Maps mashup to Grails. In earlier posts I’ve discussed how I built a Google Maps mashup showing the names and locations of all the courses I’ve taught over the last three years.

In its earlier incarnation (still on the web here, though eventually that link is going to point to the Grails version), everything was written in straight Java. I stored the data in three database tables, which I accessed by using a service layer supported by Spring and a data access layer that used Hibernate via JPA. The page itself is just straight JSP, with the necessary JavaScript thrown in. The page is just read only, too; there’s no way to add new courses or modify existing ones.

The whole application is a natural for Grails, though. It’s essentially a web interface on some database tables, with a small domain model, some simple searching capabilities, and only a bit of business logic thrown in here and there. That makes it ideal for me to do as a learning activity. Even better, when I’m finished, I’ll have a nice web-based interface to a system where I can store my course information as I go along.

Pardon me while I digress into an interesting story. Years ago, my father decided he really wanted to learn how to sail. As was his wont, he threw himself into the subject, digging up every book he could find, talking to people he knew were sailors, and basically trying to learn the entire subject in zero time.

My father and I are generally quite different people, but we definitely share that characteristic. I’m not sure what drives him to obsess so deeply about whatever subject he gets interest in, but for me, I have a few motivations:

  1. I just plain want to know, as fast as humanly possible.
  2. I’m terrified I’ll make a horrible mistake out of ignorance.
  3. I really want to do whatever the activity is, right away, but I really, really don’t want to look foolish when I make normal beginner mistakes.
  4. Being able to do cool stuff is so much fun I want to show everybody else how to do it, too.

Number 4 is a big reason why I’m an instructor. Number 1 makes me horribly impatient, but highly motivated. Numbers 2 and 3 tend to get in the way a lot, but I’m working on that.

Anyway, when my father was deep in his learning phase about sailing, he met an experienced sailor who offered to take him on a trip on the Chesapeake Bay. They experienced a lot of very high winds and waves — certainly more than my father was expecting. Still, he asked tons of questions and learned a lot.

What his friend told him, though, was that at the time my father was a great “book” sailor. He knew a lot of theory, but didn’t yet have the practical experience necessary to make sense of it all. He certainly knew enough to get into trouble, but probably not enough to know how to get back out again.

I totally get that, too. When I get wrapped up in a new subject, I dig through what feels like tons of material in a very short time. I rapidly get to the point of being a good “book” sailor. The problem is that I always carry this deep-seated fear that I don’t really know what I’m doing. That feeling doesn’t go away until I actually do the things I’m learning about.

That’s something I often think of as the “instructor trap”. Instructors spend so much time teaching that they often don’t have the time or energy left for doing, and it’s the doing that makes all the difference. You can certainly take that too far — I personally believe that industry experience can be vastly overrated. I’ve known plenty of developers who may have spent twenty years developing, but as far as learning anything new goes, it might as well have been the same single year repeated twenty times. Still, if all you know is the book, you’re missing a lot.

The term I apply to that situation is the Ten Canonical Errors. I’ve used that term here, but not in a long time.

(Quick aside: what level of geek do you have to be to use the term “canonical” in a sentence? Worse, what level of geek do you have to be to come up with a term that actually includes the word “canonical”? Yikes. It’s a good think I’m basically in touch with my inner geek.)

The idea behind the Ten Canonical Errors is that every time I learn a technology, when I start to use it there will be at least ten mistakes I’ll make that will cost me hours if not days. It doesn’t matter how many books I’ve read or people I’ve talked to, I’m still going to get stuck over and over. It’s inevitable. No matter how much I try to avoid them, the mistakes are going to happen. It’s just part of the process, just an extremely aggravating part.

Here’s a JavaScript example. HTML is simple, right? There’s nothing to it. I used to thing JavaScript was easy, too, until I started digging into Ajax, but that’s not the error I made.

One day I was trying to do a simple “Google suggest” type of Ajax application, where the server provided suggestions each time I typed in a character. I wasn’t doing anything fancy. As I recall, I as just doing a simple variation on a book example. But no matter what I tried, the JavaScript wouldn’t work.

My error was that I put all the JavaScript in a separate file and called it from the web page. Not a problem, right? In my page, I had:

<script type="text/javascript" src="myscript.js" />

That nice, clean XML, because I put in the “/>” at the end. Unfortunately, even though the contained JavaScript was so simple it HAD to work, it wasn’t working.

Eventually (and it took a while), I discovered this little paragraph in the XHTML specification:

“Given an empty instance of an element whose content model is not EMPTY (for example, an empty title or paragraph) do not use the minimized form (e.g. use <p> </p> and not <p />).”

So guess what that means? I have to write

<script type="text/javascript" src="myscript.js"></script>

instead, because even though I don’t have anything between the open and close tags, the fact that it’s possible to have something between them means I’m not allowed to minimize the tag, even though that’s perfectly valid XML.

Grr. I can’t believe somebody decided that. I have no idea what they were thinking. Still, it didn’t matter how many books I read ahead of time, it was probably inevitable that I was going to miss that. The only good thing about making it was that I could then check one off in the Ten Canonical Errors column.

By this point in my career, though, I generally have a vague sense of how far along I am along the errors path. I’ll describe myself as about two errors in, or even as many as eight. I don’t think I ever consider myself past all ten, no matter how long I’ve been in the field. Still, if I can get past six or seven, I generally feel pretty comfortable using the technology, and I know that if a problem comes up I’ll eventually be able to figure it out.

These days I’d say I was around a 7 on Hibernate and JPA, maybe a 6 or 7 on Spring (it’s so big there are still so many things I haven’t done yet), maybe only a 4 or 5 on JSF, and certainly a 9 on basic Java and probably close to that on server side and advanced Java topics. I’ve been using this stuff for quite some time now.

On Groovy, though, I wouldn’t put myself beyond a 4 yet, though I’m making progress. I didn’t think I was much beyond a 2 on Grails, but the fact that it’s based on Groovy, Spring, and Hibernate means I’m learning fast.

In terms of time invested, I’ve been playing with Groovy since about January, so that’s most a year at this point. I’ve read the bulk of the Grails book, too, so I’m not completely unaware of how it works. Still, when I compare it to what I can do in Java, it’s easy to get intimidated. But Groovy is so much more fun, that the sheer enjoyment of using it keeps me going.

(The whole transition from Java to Groovy really helps me identify with my poor COBOL programmers in my Intro Java classes. That transition is brutal. Moving from Fortran to Java was very hard for me, too, but I made that transition way back in the mid 90’s.)

In the end, building my Grails version of my course mapping application took me less than a week, even though I could only work on it for a few hours after class each night. The bulk of that time has been on topics that had very little to do with Grails, too. I’ve been struggling the last couple of days with how to transform Groovy collections into JavaScript arrays (including the associations — it if was just a single class it would be easy) which I could then process for Google Maps. I think I have it working now, but it’s been quite a battle.

I was going to post that code here today, but it’s been a long day and this post has already gotten out of hand. Look for some good coding info starting tomorrow. 🙂

MyEclipse + JPA + Spring + Hibernate = DAO (mostly)

I just about have my Google Maps mashup working. When it’s deployed, it’ll show markers for each location where I’ve taught a course. Eventually I’ll filter them by year, connect them to home with polylines, and maybe more.

As a mashup, it’s not the most interesting application ever written, but it’s given me a good opportunity to learn the Google Maps API and to play with some other interesting technologies.

In this case, that means Spring 2.0 and the Java Persistence API (JPA). I needed some way to get my course data into and out of a database, and I certainly didn’t want to hardwire anything if I could avoid it. That meant I really needed a Data Access Object (DAO) layer for my courses.

I’ll describe the details over the next few posts, but here’s the good part. The newest version of MyEclipse, version 6.0, makes it extremely easy to add both Spring 2.0 libraries and JPA to a given project. The wizard provided asks for which JPA provider to use, with the available options being TopLink and Hibernate. Just because I’m familiar with it, I chose Hibernate.

(That lead to a serious bug later involving conflicts in the asm jar file, which I’ll also describe later.)

I also used Java 5 annotations to do the mappings, as in:


@Entity
@Table(name="locations")
public class Location {
    @Id  @GeneratedValue
    private int id;

    private String city;
    private String state;
    private double latitude;
    private double longitude;

    // ... etc ...
}

I also used Spring’s @Transactional attribute in order to build a service layer that interacted with the CourseDAO. That was seriously easy, especially when I had the excellent Spring in Action book to use for reference. Since I already planned to use Spring’s dependency injection to manage the DAO classes into the service layer (i.e., I had Spring inject the transaction manager, the data source, the entity manager factory, and whatever annotation capabilities I needed), I let Spring manage as much as possible.

Just for completeness, I wrote my DAO tests in Groovy, too. 🙂

The process was all kinds of fun, actually. As soon as I decide the code is good enough, I’ll describe all the pieces here. In the meantime, I’m just rather insufferably pleased with myself.

Trivial Geocoding with Google and Groovy

I’m building a simple Google Maps mashup that will show where I’ve given classes over the past few years. It’s not much, but it’s an easy demonstration of the technology and, even better, an easy way for me to learn the Google Maps API and to play with Groovy some more.

As for Google Maps, the documentation online isn’t bad, but I have a better alternative. Scott Davis wrote an excellent introductory book for the technology called Google Maps API, v2. I bought the eBook at Pragmatic Programmers for a whopping $8.50. I’m glad to have the eBook, but it’s a bit of a shame, too, because I can’t think of a way to get it autographed when I see Scott at the No Fluff, Just Stuff conference in September.

One of the key elements of any Google map is the latitude and longitude of a particular location. To determine that, you need a geocoder, which is an application that turns place names into lat, long pairs. There are many free ones available on the Internet, but since I’m using Google anyway, I figured I might as well take advantage of theirs.

The data is available at a URL with the appropriate query parameters set. That’s an example of a RESTful web service, of course. Here’s the query for the home office of Kousen IT, Inc.:

http://maps.google.com/maps/geo?q=Marlborough,+CT&output=csv&key=xyz&#8230;

I’m using the csv response type, which returns a string of the form:

200,4,41.63257,-72.46314

The first element is the response code (200 for ok, 404 for not found, 610 for “you forgot to add in your key,” etc). The second element is the magnification level, and the last two elements are the latitude and longitude desired. There are also response types for XML, JSON, and others.

I’m going to put all my city, state locations in a database table, but just to test it out I wrote the following Groovy script:


def key = 'my Google Maps API key'
def cities = ['Marlborough','Camarillo','Boston','Winston-Salem']
def states = ['CT','CA','MA','NC']
for (i in 0..3) {
    def city = cities[i]
    def state = states[i]
    def query = "q=${city},+${state}&output=csv&key=${key}"
    def url_string = base + '?q=' +
        ',+' + URLEncoder.encode("${city}","UTF-8") +
        ',+' + state + "&output=csv&key=${key}"
    def results = new URL(url_string).text
    println "${city}, ${state}: " + 
        results.split(',')[-2,-1]*.toDouble()
}

I know there are better ways to store and access the data, but as I say I’m going to move to a database soon anyway. I used the URLEncoder class (from Java) to make sure that if I have any cities with spaces in the name (“Los Angeles”) it gets added to the URL in an encoded form (“Los+Angeles”).

The other parts I like are:

  1. Using the split(String) method in the String class to tokenize the String. I’m still used to using the old StringTokenizer class, but since Java 1.5 the split method has been available. I might as well get used to it.
  2. The beautiful array access from the end of the array [-2,-1] rather than from the beginning [2,3]. If they ever add any data to the response, I’m still fine as long as the lat and long are still the last two elements.
  3. Using the “spread-dot” operator to convert each element of the resulting string into a double.

If this code was going to be any longer I’d create a DAO class for the conversion. I might do that anyway, but this was so easy I couldn’t resist just writing it directly. The results were:

Marlborough, CT: [41.63257, -72.46314]
Camarillo, CA: [34.22291, -119.05074]
Boston, MA: [42.35864, -71.05665]
Winston-Salem, NC: [36.0996, -80.24105]

I still can’t get over how much easier it is to do anything in Groovy compared to raw Java. Programming is fun again. 🙂

%d bloggers like this: