Friday, July 22, 2005

Using Google Earth's KML with J2EE (JSP/JSTL)

Google Earth is cool despite being proprietary software which is not usually my thing. A few weeks ago I did some experiments with the Google Maps API and this was quite successful. I've just discovered that there is an "API" of sorts for the Google Earth client and thought I'd give that a whirl too. Google Earth's underlying communication format is called KML (an XML format). See:

Google Earth KML Tutorial
Google Earth KML Documentation and
Google Earth Community forums

The examples in the KML tutorial use PHP, I've re-implemented one of them into J2EE which I will reproduce here.

First you need to install the Google Earth Desktop Client.

Google Earth has defined two new MIME content types:

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

KML is just plain text XML and KMZ is compressed (e.g. gzipped) KML.

The following will describe how to produce the "Tracking a Point Directly Under Your View" using J2EE. This uses something calledView-Based Refresh.

First create a KML format document (with extension .kml) and install it on your server containing something like:


<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<NetworkLink>
<name>Test Network Link</name>
<open>1</open>
<Url>
<href>http://localhost/GoogleEarth/index.jsp</href>
<viewRefreshMode>onStop</viewRefreshMode>
<viewRefreshTime>1</viewRefreshTime>
</Url>
<visibility>1</visibility>
</NetworkLink>
</kml>

This essentially informs the Google Earth client of the details of your web service, when and how it should be called. Once you've written your dynamic script (as below) then all you need do is load it in your web browser [e.g http://localhost/GoogleEarth/test.kml]. Once installed Google Earth should pickup KML files automatically.

You'll see in the above document that I've asked it to retrieve a JSP page from my local server. This is the JSP page which will dynamically create KML documents and will be called periodically (at an interval defined in the previous document) by the Google Earth Client:


<%@ page contentType="application/vnd.google-earth.kml+xml; charset=UTF-8" %><%--
--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %><%--
--%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %><%--
--%>
<%@ taglib uri="http://jakarta.apache.org/taglibs/string-1.1" prefix="str" %><%--

--%>
<jsp:useBean id="now" class="java.util.Date"/><%--

longitude_west, latitude_south, longitude_east, latitude_north

--%>
<str:split separator="," var="bbox"><%--
--%>
<c:out value="${param.BBOX}" /><%--
--%>
</str:split><%--
--%>
<c:set var="longitude_west" value="${bbox[0]}"/><%--
--%>
<c:set var="latitude_south" value="${bbox[1]}"/><%--
--%>
<c:set var="longitude_east" value="${bbox[2]}"/><%--
--%>
<c:set var="latitude_north" value="${bbox[3]}"/><%--
--%>
<c:set var="userlon" value="${(longitude_east - longitude_west)/2 + longitude_west}"/><%--
--%>
<c:set var="userlat" value="${(latitude_north - latitude_south)/2 + latitude_south}"/><%--
--%>
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Placemark>
<description><c:out value="${param.BBOX}" /></description>
<name><fmt:formatDate value="${now}" type="time" timeStyle="full" /></name>
<LookAt>
<longitude><c:out value="${userlon}"/></longitude>
<latitude><c:out value="${userlat}"/></latitude>
<range>540.68</range>
<tilt>0</tilt>
<heading>3</heading>
</LookAt>
<Point>
<coordinates><c:out value="${userlon}"/>,<c:out value="${userlat}"/>,0</coordinates>
</Point>
</Placemark>
</kml>

I've used the Jakarta String tag library to split the BBOX parameter by the comma separator but apart from that this is JSTL. This JSP page is called after the "camera" comes to a stop in the Google Earth client. So you are presented with a new marker after every pan around the globe comes to a halt. In my next entry I plan to describe how I managed to extend this method to combine Google Earth with GeoURL feed data.

[Note] In my case I ran these scripts on Tomcat 5, depending on your server you may or may not need the addition "_rt" on the end of the JSTL tag library references.

10 comments:

Mark McLaren said...

I have a problem with String tag split:







how is bbox declared?



Thanks!
Note: Comment imported. Original by Ghebry at 2005-11-09 18:08

Mark McLaren said...

Hi,



BBOX is passed as a parameter into the JSP page by Google Earth. Therefore Google Earth will call your JSP page with something like:





http://localhost/GoogleEarth/index.jsp?BBOX=-122.497790,37.730385,-122.380087,37.812331





The split tag library copies the BBOX parameter into an array of the four values. The delimeter of this parameter is a comma. Once we have the four values in our array we can then access them in our JSP. The four values are the "bounding box" of the Google Earth client window. These values correspond to longitude_west, latitude_south, longitude_east and latitude_north.



I hope this helps, Mark


Note: Comment imported. Original by markmc website: http://content.mark-mclaren.info/ at 2005-11-09 18:38

Mark McLaren said...

is there a way to set the mime type so it opens in google earth - currently opens xml within ie
Note: Comment imported. Original by Anonymous at 2006-01-30 21:59

Mark McLaren said...

In JSP it would be something like this:





<%@ page contentType="application/vnd.google-earth.kml+xml; charset=UTF-8" %>


Note: Comment imported. Original by markmc website: http://cse-mjmcl.cse.bris.ac.uk/blog at 2006-01-30 23:01

Mark McLaren said...

I recieve the following error message:



----------------------------

HTTP Status 500 -



type Exception report



message



description The server encountered an internal error () that prevented it from fulfilling this request.



exception



org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application

org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:50)

org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:411)

org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:118)

org.apache.jasper.compiler.TagLibraryInfoImpl.generateTLDLocation(TagLibraryInfoImpl.java:316)

org.apache.jasper.compiler.TagLibraryInfoImpl.(TagLibraryInfoImpl.java:147)

org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:418)

org.apache.jasper.compiler.Parser.parseDirective(Parser.java:483)

org.apache.jasper.compiler.Parser.parseElements(Parser.java:1539)

org.apache.jasper.compiler.Parser.parse(Parser.java:126)

org.apache.jasper.compiler.ParserController.doParse(ParserController.java:220)

org.apache.jasper.compiler.ParserController.parse(ParserController.java:101)

org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:203)

org.apache.jasper.compiler.Compiler.compile(Compiler.java:495)

org.apache.jasper.compiler.Compiler.compile(Compiler.java:476)

org.apache.jasper.compiler.Compiler.compile(Compiler.java:464)

org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:511)

org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:295)

org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)

org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)

javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

sun.reflect.GeneratedMethodAccessor58.invoke(Unknown Source)

sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

java.lang.reflect.Method.invoke(Method.java:585)

org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:243)

java.security.AccessController.doPrivileged(Native Method)

javax.security.auth.Subject.doAsPrivileged(Subject.java:517)

org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:272)

org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:161)

---------------------
Note: Comment imported. Original by Anonymous at 2006-08-28 00:36

Mark McLaren said...

Very handy example, I am looking to do something along these lines. However, I am looking to tie into an EJB that queries a database and gets constantly updated KML. I want my JSP to have links to other data, some pertaining to the overlaid data in Google Earth, which when clicked would get added details. Wouldn't the automated refresh specified in the initial KML file make this difficult, as every time it refreshes it would load the original JSP, and I would lose where I am at in the browser? Maybe I am just having a brainfart as I havent messed with JSP in ages...
Note: Comment imported. Original by James at 2006-11-28 20:58

Mark McLaren said...

Hello,

I have a web application which is currently using MapExtreme API for tracking and tracing and showing the location on the webpage, Now I want to embedd google earth API's to show the location of traking and tracing, so could anybody help me to get this.



Regards

Kapil
Note: Comment imported. Original by Kapil at 2007-02-26 08:55

Lyndon Adams said...

Many thanks for the post. You have saved me a whole load of time and headaches.

prathap kumar said...

Interesting Article

Java Training in CHennai | Online Java Training

prathap kumar said...

Java EE Online Training