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:
- User logs on to the form server.
- Server verifies user against directory service, possibly lightweight directory access protocol, and places user's IP address in a session table.
- Form server sends back redirect to tour server.
- Tour server checks that the registered user's IP address is in the session.
- A tour is returned based on the user history stored in the database.
- Google Earth zooms in on a placement and requests an image.
- The user clicks on a link within the placement that then triggers the form server to generate and return a form.
- The student fills in the form and continues with the tour.
- 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.Bidirectional communication
In the previous code example, the network link required us to wait for a refresh action. Luckily, periodically we can get Google Earth to send via a get method the coordinates of the user position in the view window, as shown next:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Folder>
<description>Examples of bi directional flow of information</description>
<name>Network Links</name>
<visibility>1</visibility>
<open>1</open>
<NetworkLink>
<description>Lets send coordinates once in a while</description>
<name>Message Pushing</name>
<visibility>1</visibility>
<open>1</open>
<refreshVisibility>1</refreshVisibility>
<flyToView>0</flyToView>
<Url>
<href>http://localhost:8081/Tour/message</href>
<refreshInverval>2</refreshInverval>
<viewRefreshMode>onStop</viewRefreshMode>
<viewRefreshTime>1</viewRefreshTime>
</Url>
</NetworkLink>
</Folder>
</kml>
The real action occurs in the Url
entity. The viewRefreshTime
tag defines how many seconds pass before the server receives the next set of Earth coordinates. The viewRefreshMode
is set toonStop
, which implies an update of Earth coordinates when the motion in the view window stops. Figure 4 is a screen grab displaying the end effect of the above configuration.
Figure 4. GUI rendering of the network link and associated HTML
Okay, so we can get those pesky coordinates to the server. What should we do with them? Well, we can start by creating a messaging service. Figure 5 defines the two collaborations.
Figure 5. The flow of information between Earth, servlet, and the Web browser
The first passes the message and receives the coordinates through the Web browser:
- The Web browser sends via a post method the parameter's name and message
- The servlet returns the coordinates last received from the Google client as a text message similar to:
Location: -0.134539,51.497,-0.117855,51.5034
IP address: 127.0.0.1
Updated: Fri Oct 21 11:42:45 CEST 2005
The second collaboration passes the coordinates and receives the placement between the servlet and Earth client:
- For every delta T, Google Earth sends via a get method the user's coordinates within the view window.
- The servlet returns a message in a placement. The placement uses the coordinates to calculate roughly where to set down the returned message. Please note that I have copied the algorithm for centering from the KML tutorial.
The generated placement returned resembles the following KML:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Placemark>
<name><![CDATA[<font color="red">Alan Berg</font>]]></name> <description><![CDATA[BLAH BLAH <i> Fri Oct 21 11:42:45 CEST 2005</i>]]>
</description>
<Point>
<coordinates>4.889999,52.369998,0</coordinates>
</Point>
</Placemark>
</kml>
Next is the servlet code that orchestrates the communication:
MessageServlet.java
package test.google.earth.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import test.google.earth.bean.LastLocationBean;
import test.google.earth.bean.LastMessageBean;
import java.util.Date;
public class MessageServlet extends HttpServlet
{
private static LastMessageBean lastMessage=new LastMessageBean();
private static LastLocationBean lastLocation= new LastLocationBean();
public void init(ServletConfig config) throws ServletException {
super.init(config);
lastMessage.setMessage("No message Yet");
lastMessage.setName("System");
lastMessage.setUpdated(new Date());
lastLocation.setCoords("No contact with a client yet");
lastLocation.setIpAddress("");
lastLocation.setUpdated(new Date());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String coords = request.getParameter("BBOX");
if (coords==null){
return;
}
String message;
String name;
Date lastDate;
String ipAddress = request.getRemoteAddr();
synchronized(this) {
lastLocation.setCoords(coords);
lastLocation.setIpAddress(ipAddress);
lastLocation.setUpdated(new Date());
message=lastMessage.getMessage();
name=lastMessage.getName();
lastDate=lastMessage.getUpdated();
}
response.setContentType("application/keyhole");
PrintWriter out = response.getWriter();
String[] coParts= coords.split(",");
float userlon;
float userlat;
try{
userlon = ((Float.parseFloat(coParts[2]) - Float.parseFloat(coParts[0]))/2)+
Float.parseFloat(coParts[0]);
userlat = ((Float.parseFloat(coParts[3]) - Float.parseFloat(coParts[1]))/2) +
Float.parseFloat(coParts[1]);
}catch(NumberFormatException e){
return;
}
String klmString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<kml xmlns=\"http://earth.google.com/kml/2.0\">\n"
+ "<Placemark>\n"
+ "<name><![CDATA[<font color=\"red\">"+name+"</font>]]></name>\n"
+"<description><![CDATA["+message+"<br><i>"+lastDate+"</i>]]></description>\n"
+ "<Point>\n"
+ "<coordinates>"+userlon+","+userlat+",0</coordinates>\n"
+ "</Point>\n"
+ "</Placemark>\n"
+ "</kml>\n";
out.println(klmString);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String name = request.getParameter("name");
if (name==null){
return;
}
String message;
PrintWriter out;
synchronized(this) {
lastMessage.setMessage(request.getParameter("message"));
lastMessage.setName(name);
lastMessage.setUpdated(new Date());
message="<pre>\nLocation: "+lastLocation.getCoords()+
"\nIP address: "+lastLocation.getIpAddress()+
"\nUpdated: "+lastLocation.getUpdated();
}
response.setContentType("text/html");
out = response.getWriter();
out.println(message);
}
}
The message from the Web browser is stored in one static member, the LastMessageBean
, and the coordinates are stored inLastLocationBean
—only one instance of each bean. Further, synchronization occurs for all the static beans while getting or setting. We use single instances for simplification purposes to help limit the amount of code to be written. However, a more practical example would require a session manager that tracks IP addresses and generates results accordingly.
A side issue is that the use of HTML tags inside the placement entity's name tag causes rendering problems. Within the Google client's "places" section, the client renders the HTML, but, in the view window, the full tag displays as text. I consider this inconsistency a bug.
From the current example, the Google client pushes coordinates. The servlet returns KML fragments. Knowing the coordinates allows the pushing of context-sensitive information. We can force interaction via links in the fragments and, if required, make the Web browser the boss. This article has shown you how to take control of the Google Earth client. You now have a conceptual toolset to build your own interactive tours.
Finally
In this article, I have only discussed the rudiments of interaction and have only scratched the surface of KML. You can add further functionality with KML by rendering 3D objects via the extrude
tag or adding pertinent information via snippets. You could use overlays to display famous paintings as users follow Napoleon's retreat from Moscow. With a little imagination and solid Java programming skills, you can build interactive Web applications with the Google Earth client. I look forward to seeing your efforts come to fruition.
About the author
Alan Berg, has been a lead developer at Central Computer Services at the University of Amsterdam for the last seven years. In his spare time, he writes computer articles. He has a bachelor's degree, two masters, and a teaching qualification. In previous incarnations, he was a technical writer, an Internet/Linux course writer, and a science teacher. He likes to get his hands dirty by building and gluing together systems. He remains agile by playing computer games with his kids, who (sadly) consistently beat him.
相关推荐
【标题】"旅游servlet--bdtravel.zip"揭示了这个项目是基于Servlet技术来开发的旅游管理系统。Servlet是Java EE平台中的一个核心组件,主要用于处理Web应用中的动态请求。在这个项目中,Servlet作为服务器端的程序,...
【标题】"TrainingProject---stepik_tours:проектдляпроверки"是一个训练项目,主要用于检验在Stepik平台上学习Python编程的学生们的技能。Stepik是一个在线教育平台,提供编程和信息技术课程,...
《LoadRunner 12在WebTours订票系统中的应用详解》 LoadRunner,作为业界知名的压力和性能测试工具,是HP(现为Micro Focus)公司推出的一款强大测试平台,尤其在软件测试领域中占据重要地位。在本案例中,我们将...
【QTP Mercury Tours 网站安装程序】 QuickTest Professional(QTP)是HP公司推出的一款功能强大的自动化测试工具,主要用于软件的功能测试和回归测试。Mercury Tours 是一个示例应用,常常被用作QTP的学习平台,...
文章首先对MN×MN的Torus-based光学网络芯片中的插入损耗和串扰噪声进行了系统分析,指出这些问题会导致网络性能的下降。作者提出了一个分析模型,该模型适用于任意规模的5×5路由器和基于Torus的ONoCs。 在传统的...
《C#技术详解:以Layton-Temple-Tours项目为背景》 在软件开发领域,C#是一种广泛使用的编程语言,尤其在Windows平台和.NET框架下,它的应用更是无处不在。本篇文章将以"Layton-Temple-Tours"项目为背景,深入探讨...
WEB-Tours 订票系统性能测试报告 本报告对 WEB-Tours 订票系统的性能测试进行了详细的说明和分析。该系统是航空公司机票信息治理的重要组成部分,随着业务系统的发展,系统的性能问题逐渐成为了关注的焦点。因此,...
"shop-hot-tours"是一个可能代表在线旅游平台或者热卖旅行路线的应用程序项目。这个项目的标题暗示了它可能是一个电商性质的平台,专注于提供热门旅游产品和服务。在描述中提到“要启动应用程序,请使用任何服务器”...
标题中的“Colenso-Ma-s-Eco-Tours”是一个虚构的旅游公司,这个项目的目标是构建该公司的官方网站。这个网站的开发使用了三种核心技术:HTML(超文本标记语言)、CSS(层叠样式表)和JavaScript。这三者是网页开发...
自然之旅(Nature Tours)是一个假设性的旅行和休闲服务提供商,其在线存在主要依赖于一个精心设计的网站。这个网站的构建充分利用了现代Web技术,包括HTML5、CSS3以及SASS预处理器。在这个详细的讨论中,我们将深入...
"Web Tours 1.0.7z" 是一个软件安装包的压缩文件,采用7-Zip格式进行压缩,主要用于Web Tours 1.0版本的安装。7-Zip是一种开源的压缩工具,以其高效率和对多种压缩格式的支持而受到用户欢迎。在软件开发和测试领域,...
该项目是通过引导的。可用脚本在项目目录中,可以运行:npm start 在开发模式下运行应用程序。 打开在浏览器中查看它。 如果您进行编辑,则页面将重新加载。 您还将在控制台中看到任何棉绒错误。...
"Travel-and-Tours"这个标题暗示了页面可能与旅游相关,因此设计应突出旅行和游览的主题,同时保持专业和易用。 2. **表单元素**:HTML中的`<form>`标签用于创建表单,包含用户名和密码输入框,通常使用`...
Web Tours 1.0安装包下载 Web Tours是惠普 loadrunner 自带的一个飞机订票系统网站,它是一款基于ASP.net平台的网站,基于先进的.NET Framework,默认支持SqlServer数据库、Access、Mysq等多种数据库,这是基于ie、...
Create React App入门 该项目是通过引导的。 可用脚本 在项目目录中,可以运行: npm start 在开发模式下运行应用程序。 打开在浏览器中查看它。 如果您进行编辑,则页面将重新加载。 您还将在控制台中看到任何...
hp web tours 分析
《LoadRunner WebTours 示例深度解析》 LoadRunner是一款由HP公司开发的强大的负载和性能测试工具,广泛应用于企业级应用系统的性能测试。本示例“WebTours”旨在为初学者提供一个无需安装完整LoadRunner环境即可...
### Webtours安装详细步骤与知识点解析 #### 一、安装前准备 在开始Webtours的安装之前,我们需要确保已经准备好以下环境和工具: 1. **Java Development Kit (JDK) 安装**:Webtours需要JDK的支持来运行其内部的...
妮可S-3D虚拟之旅这是我的第一个专业项目。... 我在该项目期间创建了我的第一个构建过程,以连接,自动添加前缀并最小化我的源代码。 制作此网站最具有挑战性和最大的学习经验,是确保其性能不会因大量媒体资产而...