Sunday, July 24, 2005

A simple Java KMZ Servlet Filter for use with the Google Earth client

Google Earth reads KML and KMZ files, the MIME types for these are:

  • application/vnd.google-earth.kml+xml kml
  • application/vnd.google-earth.kmz kmz

The KMZ format looks to be simply a PKZipped version of the KML file. Although rather interestingly there is scope to add images and perhaps other media (e.g. 3d models, video and audio) into the zip file.

It seems that at present the main body of Google Earth developers are using PHP but as you can see from my recent posts I have been having some success developing for it with JSP technologies.

First, I tried to load a GZipped file into Google Earth but that didn't appear to work. It looks that Google Earth currently only supports "PKZIP" style files at present.

I thought to myself that I could create a Servlet Filter to dynamically create PKZIP files. I found an old article entitled Two Servlet Filters Every Web Application Should Have (circa 2003, virtually Jurassic!) on O'Reilly's OnJava that describes how to create a GZIP compression servlet filter to automatically compress the output of JSPs. I need to produce something very similar but this time with the emphasis on PKZIP.

It took a little longer that I expected to get my KMZFilter working. It seems that "all modern browsers" are assumed to accept the gzip encoding. Therefore there no longer seems to much point in searching for "gzip" in the accept-encoding request header as most browsers don't bother to send that header anymore. Additionally it isn't quite as straight forward as changing all the java.util.zip.GZIPOutputStream references in the GZIPFilter to java.util.zip.ZipOutputStream either.

The KMZ servlet filter version I produced does no yet support zipping up multiple files. To support multiple files I'd need to work out from the requested filename (e.g. index.kmz) the file list that I'd need to include in the zip file, perhaps an XML properties file would do the trick (actually that would be quite an elegant solution).

My web.xml contains the following, note that I have mapped the KMZ extension to JSP so that I can carry on writing JSP to do the actual KML file creation:


<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd"
>

<web-app>

<filter>
<filter-name>KMZFilter</filter-name>
<filter-class>markmc.KMZFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>KMZFilter</filter-name>
<url-pattern>*.kmz</url-pattern>
</filter-mapping>

<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.kmz</url-pattern>
</servlet-mapping>

<taglib>
<taglib-uri>http://jakarta.apache.org/taglibs/string-1.0</taglib-uri>
<taglib-location>/WEB-INF/taglibs-string.tld</taglib-location>
</taglib>

</web-app>

Kudos to Jayson Falkner as I stole most of the code from his GZIPFilter but you are very welcome to have the source code filter for the KMZFilter I produced. I make no guarantees about the filters reliability, actually that probably goes for almost everything I produce (I will not be a hostage to responsibility)!!

Download KMZFilter source code

I ran into another little problem that was fixed by updating my Google Earth client to the latest version (at this time 3.0.0395(beta)) and "Presto Chango!" it works great.

[Update]
Inspired by the compression filter example that comes with Tomcat I have improved my filter and it works much better now.

$CATALINA_HOME/webapps/examples/WEB-INF/classes/compressionFilters

This was not helped by the Servlet Filters responses of <html><body></body></html> rather than an error I could actually do something with! If I were being professional about it I'd also add some code to make sure, even when responding with a servlet exception that the response from this filter was always KML/KMZ.

0 comments: