Servlet-based Google Earth tours

The art of communication between client and servlet

The Google Earth client is a technological icon from this part of our century. Google Earth is not the first Earth client and is nearly the same as its lesser known predecessor, Keyhole. However, with the Google name behind it and the basic version free to the end user, it has market penetration and recognition—an interesting target to write for.

This article has one overriding mission: to show you how truly simple it is to send information to and from a servlet via the Earth client. With this degree of interaction, you can create imaginative services by applying basic Java programming skills.

Licensing and competition
At the time of this writing, Google Earth is in beta form (version 3.0.0616). The license (found in the client's Help section) is commercial. If you wish for an equivalent open source example, I recommend concentrating your efforts on the excellent Nasa World Wind project.

The basics

The Google Earth client parses XML in the form of Keyhole Markup Language (KML) version 2, a proprietary namespace. Numerous KML configurations are possible to affect a GUI. The difficulty in creating a well-balanced application is associated more with knowing the KML details than the subtleties of coding. A short list of KML entities includes:

  • Placements, which mark the location on Earth
  • Folders, which help organize the other features
  • Documents, which are containers for folders that may include style elements
  • Image overlays, which are used for adding images
  • Network links, which are a means of describing where and how to communicate with a server or, as in our situation, a servlet

For the sake of simplicity, in this article, I focus on the use of the folder, placement, and network-link elements. Further, I define a tour as a folder that contains a series of placements.

On installation of the Google software under Windows, the file extension KML and the MIME (Multipurpose Internet Mail Extensions) type "application/keyhole" are registered. This means that the client is activated by either a click on a KML file or a receipt, through TCP/IP, of a file with the "application/keyhole" MIME type.

If the KML text returned is:

 <Folder><name>Hello World [127.0.0.1] </name></Folder>

Then the program will display the following:

Figure 1. GUI representation of the Hello World folder

To activate the Earth client, simply browse to the correct URL—for example, the HelloServlet whose source can be downloaded from Resources (http://localhost:8080/Tour/hello). Doing so activates the following doGet() method, which redirects to doPost(), allowing all Web browsers to view the results:

 

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); }

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("application/keyhole"); PrintWriter out = response.getWriter(); String message ="<Folder><name>Hello World [" + request.getRemoteAddr()+ "]</name></Folder>"; out.println(message); }

Do not be distracted by the code's simplicity. The method has powerful implications. A server can act as intermediary between different data types and Google Earth. One can imagine a situation where different XML dialects are involved for tour data, with the server performing Extensible Stylesheet Language transformations before passing on the finished response. Further, the server can choose which response to return, allowing for personalization. The document entity in KML allows for style definitions, and, by changing the style depending on IP address range, one can potentially differentiate between various customers.

To practice, we should begin working with Google Earth and exporting KML files. At the top of Google's program is the Add menu. From here, you may add placements, folders, and image overlays. You may then save the generated KML via the File menu. I strongly recommend editing the exported XML and seeing how your modifications affect Earth. Yes, let's play king of the world!

Learning city locations

This section introduces an educationally orientated application: a program that teaches students names of cities and their relationships with a given land. We shall build a servlet that acts as a flashcard by sending a random city location back to the client. A placement expresses the city in KML. This placement has an embedded HTML link that points the user to a relevant and, one hopes, interesting Website. Thus, we now have user interaction involving both a Web browser and Google Earth.

The student can pull in the next placement by selecting Refresh from the menu that appears when the mouse hovers over the network link, as shown in Figure 2.

Figure 2. GUI representation of refreshing a network link to regenerate a placement (in this case, London)

The behind-the-scenes trick to our application is the use of a network-link entity. The network link loads a data file from http://location. Place the file on your desktop and double click it. Google Earth runs, and the KML fragment, shown below, loads from the server.

City.kml

 <?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
    <NetworkLink>
      <description>Refresh me</description>
      <name>Random City</name>
      <visibility>1</visibility>
      <open>1</open>
      <refreshVisibility>1</refreshVisibility>
      <flyToView>1</flyToView>
      <Url>
        <href>http://location </href>
      </Url>
    </NetworkLink>
</kml>

The entity meanings within this configuration are:

  • visibility, which defines whether the network link can be seen
  • open, which explains whether the tag is to be expanded
  • refreshVisibility, which defines whether the refreshed placement's visibility overrides the user's choice
  • flyToView, which "flys" the user to the placement in the view window if set to 1

Many of the entities are common across most root elements—description, for example. Note that the tag names are case sensitive, so be careful coding or you might have difficult-to-debug failures. Personally, I find the relationship between the different tag values and their influence on interactions with the GUI not always logical. Therefore, you may require play-around time in any new use of the KML fragments.

Caution
By default, the browsers Firefox, Opera, and Internet Explorer react differently to receiving a .kml extension from the Web. The most consistent method for activating the network-link file is to avoid the server for the initial KML file, and allow users to download the file onto their desktops, where they can launch it themselves by double-clicking on it. Another more adventurous approach is to place the KML file within a JSP (JavaServer Pages) page and allow the JSP page to return the "application/keyhole" MIME type followed by the relevant KML fragment. For example, the city.jsp page is simply the city.kml file, but with the content type modified and the XML Schema removed. The code starts with:
 <%response.setContentType("application/keyhole");%>
    <NetworkLink>

Back to the code, the servlet returns a placement with HTML coding in the description. Being a good XML citizen, we have placed the HTML fragment within the <!CDATA[]]> delimiting tag, thus avoiding confusing the XML parsers:

 <Placemark>
   <name>London</name>
   <description>
<![CDATA[<a href="http://www.visitlondon.com/choose_site/?OriginalURL=/">London</a>]]>
</description>
   <address>London, UK</address>
   <styleUrl>root://styleMaps#default+nicon=0x304+hicon=0x314</styleUrl>
   <Point>
      <coordinates>-0.1261969953775406,51.50019836425783,50</coordinates>
   </Point>
</Placemark>

The three new entities seen in this placement are:

  • address, a logical tag to contain the address
  • styleUrl, which defines the graphic to be displayed in this case at the placeholder
  • Point/coordinates, cylindrical coordinates of the location

The servlet generates a random placement response via this code fragment:

 manager.KMLRenderOfRandomPlacement();

Our whole application is elementary. The servlet does not keep track of state. Management class refactoring separates rendering from data management. The Manager.java init method loads data into an array of property beans. Obviously, in a real application, where communication with a database is necessary, a persistence management framework, such as iBATIS or Hibernate, would prove useful. The placement beans model the data needed within the returned placement. The bean has the property point, which is a bean in itself. This allows later expansion of the model as the developer learns more details of KML composition and what a point can achieve within the Earth GUI.

The QuizServlet shown below is a thin wrapper around Manager.java; for every post or get request, the servlet returns a valid KML response.

QuizServlet.java

 

package test.google.earth.servlet;

import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.*; import javax.servlet.ServletConfig; import test.google.earth.manager.Manager;

public class QuizServlet extends HttpServlet { private Manager manager;

public void init(ServletConfig config) throws ServletException { super.init(config); this.manager= new Manager(); manager.init(); }

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); }

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("application/keyhole"); PrintWriter out = response.getWriter(); out.println(manager.KMLRenderOfRandomPlacement()); } }

Manager.java

package test.google.earth.manager;

import java.util.Random; import test.google.earth.bean.PlacementBean; import test.google.earth.bean.PointBean;

public class Manager { private PlacementBean[] cityArray; private String styleURL; private String open; private Random generator; private int idx;

public Manager(){}

public void init(){ this.styleURL="root://styleMaps#default+nicon=0x304+hicon=0x314"; this.open="1"; this.generator = new Random(); String[] coords = {"-0.1261969953775406,51.50019836425783,50", "12.5,41.889999,50","4.889999,52.369998,0"}; String[] name = {"London","Italy","Amsterdam"}; String[] address={"London, UK","Rome, Italy","Amsterdam, Netherlands"}; String[] description={ "<a href=\"http://www.visitlondon.com/choose_site/?OriginalURL=/\">London</a>", "<a href=\"http://www.roma2000.it/\">Rome</a>", "<a href=\"http://www.uva.nl/\">University of Amsterdam</a>"}; this.idx=coords.length;

cityArray= new PlacementBean[coords.length];

//Init the array of placements for (int i =0; i<coords.length;i++){ placementBean placementBean = new PlacementBean(); placementBean.setAddress(address[i]); placementBean.setDescription(description[i]); placementBean.setName(name[i]); placementBean.setOpen(open); placementBean.setStyleURL(styleURL); pointBean pointBean = new PointBean(); pointBean.setCoordinate(coords[i]);

placementBean.setCoordinates(pointBean); this.cityArray[i]=placementBean; } }

public synchronized PlacementBean nextRandomPlacement(){ return cityArray[ generator.nextInt( this.idx )]; }

public synchronized String KMLRenderOfRandomPlacement(){

return renderKMLPlacement(nextRandomPlacement()); }

private String renderKMLPlacement(PlacementBean pBean){ String klmString="<Placemark>\n"+

"\t<name>"+pBean.getName()+"</name>\n"+ "\t<description><![CDATA["+pBean.getDescription()+"]]></description>"+ "\t<address>"+pBean.getAddress()+"</address>\n"+ "\t<styleUrl>"+pBean.getStyleURL()+"</styleUrl>\n"+ "\t<Point>\n"+

"\t\t<coordinates>"+pBean.getCoordinates().getCoordinate()+"</coordinates>\n"+ "\t</Point>\n"+ "</Placemark>\n"; return klmString; } }

Adding remotely served graphics to the placements is straightforward. The styleUrl tag needs a link to the Web, e.g., http:/imageServer/image.gif. This allows the code to expand so the window's view renders a placement with an image, such as a nation's flag, in the current application.

Looking further into this methodology, one could imagine a situation where the user has the opportunity to fill in a Web form while interacting with the Google Earth client. See Figure 3 for a viable definition of such an infrastructure.

Figure 3: Potential infrastructure for a form-based tour service

An Apache Web server sits in front of two servlets. The first is the form server that returns Web forms depending on the parameters sent. The second is the tour servlet that generates a list of placements to make up one tour enclosed in a folder. The tour server calculates the image URL, but the image itself is stored statically on the filesystem to improve performance.

The collaborations are as follows:

  1. User logs on to the form server.
  2. Server verifies user against directory service, possibly lightweight directory access protocol, and places user's IP address in a session table.
  3. Form server sends back redirect to tour server.
  4. Tour server checks that the registered user's IP address is in the session.
  5. A tour is returned based on the user history stored in the database.
  6. Google Earth zooms in on a placement and requests an image.
  7. The user clicks on a link within the placement that then triggers the form server to generate and return a form.
  8. The student fills in the form and continues with the tour.
  9. Sometime later, the student logs out. This forces the application to send an email to the relevant teacher with a professionally formatted report on the user's answers. Thus, the server has delivered the homework.

As you can see, with imagination, creation of functional and educationally rewarding applications is viable. However, we are still missing direct feedback from the client to the servlet on a periodic basis, not just when the student refreshes the placement. The next section drills down into this issue.

1 2 Page 1