Wednesday, May 9, 2007

Embedding Google Maps in your Groovy application

Google provides a wide variety of API for embedding their applications into your web pages. They are very convenient if your are developing web applications but I find it very painful to embed them into any Java application. Hopefully as far as GMaps is considered, the swingx-ws project is providing a JXMapViewer class in which you can configure a tile provider for using the Google map servers. Let's use Groovy to build a small apps using Google geocoding and putting some information on a map.

Central to our small application is the JXMapViewer. Each mapviewer is associated to a tile factory which delivers the image pieces. Once configured, the mapviewer will take care of the rest querying the map server when required depending on your location. Configuring the tile factory is the more tricky part of the snipplet, here are all the arguments of the constructor:

def tfi = new TileFactoryInfo(0, 20, 17, 256, true, true,"can't disclose", "x", "y", "zoom")

The first four numbers to the TileFactoryInfo constructor represent the minimum zoom, the maximum zoom, the total zoom levels, and the tile size (very often a tile is a 256 pixels square) . The two booleans are used to indicate if the x coordinates go left to right or right to left and if the y coordinate goes from top to bottom or out from the equator. The rest of the parameters are for the base url and the name of the http parameters in the get request to fetch tiles.

Let's continue by defining our Swing interface including the JXMapViewer. Here the code defining our panel which includes a textfield (in which you could type an address), the widget containing the map viewer and two buttons for zooming in and out.


import java.awt.*
import java.awt.BorderLayout as BL

import javax.swing.*
import javax.swing.WindowConstants as WC
import javax.swing.JOptionPane as JOP
import javax.swing.BorderFactory as BF
import javax.swing.SwingUtilities as SU

import org.jdesktop.swingx.mapviewer.*
import org.jdesktop.swingx.JXMapViewer

import groovy.swing.SwingBuilder

def googleKey = "your google api key"

def mapViewer = new JXMapViewer()
def tfi = new TileFactoryInfo(...)

mapViewer.tileFactory = new DefaultTileFactory(tfi)
mapViewer.zoom = 5
mapViewer.centerPosition = [48.856558, 2.350966] // Paris

def swing = new SwingBuilder()
def frame = swing.frame(title: 'Groovy Maps',defaultCloseOperation:WC.DISPOSE_ON_CLOSE) {
panel(id: "mainPanel", layout: new BL()) {
panel(constraints: BL.NORTH, layout: new BL()) {
textField(id: "address", constraints: BL.CENTER, columns: 50,
border: BF.createTitledBorder("Address"), actionPerformed: {
def address = swing.address.text
// geocoding code here
}
widget(mapViewer)
panel(constraints: BL.SOUTH) {
button(text: "+", actionPerformed: { mapViewer.zoom -= 1 })
button(text: "-", actionPerformed: { mapViewer.zoom += 1 })
}
}
}
frame.pack()
frame.size = [800, 600]
frame.locationRelativeTo = null

frame.visible = true



Using the Google geocoder is pretty simple when using an http request to http://maps.google.com/maps/geo? with the following parameters in the URI:
# q, the address that you want to geocode,
# key, you API key,
# output , the format in which the output should be generated. In our example, we will use xml, the other options are kml, csv, or json.

In our case, the address will come from a texfield so the code looks like this:

textField(id: "address", constraints: BL.CENTER, columns: 50,
border: BF.createTitledBorder("Address"), actionPerformed: {
def address = swing.address.text

// geocoding
SU.invokeLater {
Thread.start {
def geocodingUrl = "http://maps.google.com/maps/geo?q=
{URLEncoder.encode(address)}&output=xml&key=${googleKey}".toURL()
def node = new XmlSlurper().parseText(geocodingUrl.text)
if (node.Response.Status.code == "200") {
def coord = node.Response.Placemark.Point.coordinates.text().
tokenize(',').collect{Float.parseFloat(it) }
mapViewer.centerPosition = coord[1..0]
}
}
}
})


Assemby all the pieces give you the global application ...

In conclusion, JXMapViewer is a powerful component that make it easy to embed maps in your groovy application. In a next stage, I will show you how to add more information in a different layer.

Wednesday, May 2, 2007

J-7 for JavaOne 07

Now that Groovy-1.1-BETA-1 and Grails-0.5 are out, it's time to focus on JavaOne. There will be an important presence for both projects since at least 8 sessions are mentioning Groovy. Apart from these sessions, two other events are worth to attend:
# On May 7, if you are in SF and are interested by dynamic languages - don't miss the RedMonk unconference track during the CommunityOne event,
# On May 8, join the Groovy and Grails community for the Groovy/Grails One Meet-up at the W Hotel from 6:30pm.

And probably many more to be announced !

Groovy is enterprise ready

It has been a long time since my last post. But important things are happening for enterprise scripting. Yes, Groovy-1.1-beta-1 was released yesterday. This release has new features that could speed up its adoption at the enterprise level. In this post, let's focus on annotations that is something brought by Java 5. Nowadays, annotations are everywhere from Spring Framework, Hibernate, TestNG to the newcomer Google-Guice lightweight dependency injection framework.
Let's see how Guice and Groovy can be used jointly.
All you need is a fresh Groovy 1.1-beta-1 install and guice-1.0.jar and aopalliance-1.0.jar from Google-Guice. As an example, I will use the stupid mathematic application I am using for the GroovySOAP tutorial.
Let say, you have an addition contract like this one:

import com.google.inject.*
interface Calculator {
def add(a,b)
}

Here is an obvious instanciation of that contract (this should be implemented as a singleton):

@Singleton
class CalculatorImpl implements Calculator {
def add(a, b) {a + b }
}

The next step is to write the client that will need that service to be injected. In Groovy, this is as simple as shown below. The @Inject annotation is used for that purpose.

class Client {
@Inject
Calculator calc

def executeCalc(a, b) { calc.add(a,b) }
}

What is not yet done is the wiring between our client and the implementation class. This can be done programmatically using the so called Modules in Guice. Here is what I am doing here:

class MyModule implements Module {
void configure(Binder binder) {
binder.bind(Calculator).to(CalculatorImpl)
}
}

At this point, we are done. Here is how you can use your client in Groovy:

def injector = Guice.createInjector(new MyModule())
def client = injector.getInstance(Client)
assert 3 == client.executeCalc(1,2)

If you want to learn more on this topic, here are further reading on Guicy by MrG and some early experiment on JPA and annotations in Groovy by Romain.