docx

advertisement
Lab 5 – Google Maps
In this lab you will use the results of Lab 3 to display the location of the cellular phone in
a Google Map in real-time. You will use the part of Lab 3 that obtains GPS fixes every
10 seconds and sends them using UDP to the database on a server.
Objective
The objective to this lab is to:
1. Create a Google Web Toolkit Project
2. Learn how to use Remote Procedure Calls (RPC) in GWT
3. Learn how to use the Google Maps to create a simple mapping application
Experiment 1 Writing the server-side code
In this part you will create the required NetBeans project to develop a Google Map
application.
To get started with the NetBeans project, do the following steps:
1. Run NetBeans
2. Create a new project (File -> New Project)
3. Choose Java Web -> Web Application and Click Next
4. Write in your project name, e.g., Lab 5 and select the appropriate path where to
store it
5. Select the server where you will be deploying your application and the Context
Path for your app. Click Next and Finish
6. Your Lab 5 project appears in the upper left window
7. Right Click in project’s name and in the menu click Properties
8. In the categories list, click Libraries
9. Click Add JAR/Folder button, go to your gwt installation folder, select the gwtservlet.jar and click open
Page 1 of 24
10. Click Add JAR/Folder button, go to your Postgres installation folder, look for the
jdbc folder and select the posgis_1.3.3.jar. Click Open and then Click Ok.
11. Right Click on Source Packages, and in the menu that appears, click New>Package.
12. Write the package name as cse.usf.edu.lab5.client.services and click finish
13. Repeat steps 11 and 12, with the new package name being
cse.usf.edu.lab5.client.entities
In this exercise you will write the server-side code for the Google Map application. This
code will create the server-side methods that will invoke the database to obtain the last
location stored in the database of the active users.
1. Right click in the package cse.usf.edu.lab5.client.entities and in the menu click
New->Java class
2. Write down the name of the class as TrackingUpdate. Click finish
3. Select all the code that appears in the TrackingUpdate.java screen and delete it
4. Copy and paste the following code in that area and save it (File->Save)
Listing 1- TrackingUpdate.java
package cse.usf.edu.lab5.client.entities;
import com.google.gwt.user.client.rpc.IsSerializable;
// A GWT serializable class used to encapsulate the information about active
sessions
public class TrackingUpdate implements IsSerializable{
private double latitude;
private double longitude;
private int sessionid;
private String username;
public TrackingUpdates(){
}
public int getsessionId(){
return sessionid;
}
public String getUsername(){
return username;
}
public double getLatitude(){
return latitude;
}
public double getLongitude(){
Page 2 of 24
return longitude;
}
public void setSessionid(int sessionid){
this.sessionid = sessionid;
}
public void setUsername(String usr){
this.username = usr;
}
public void setLatitude(double lat){
this.latitude = lat;
}
public void setLongitude(double lng){
this.longitude = lng;
}
}
This code is a simple wrapper of the session information. There are two important aspects
to show of this code:
import com.google.gwt.user.client.rpc.IsSerializable
This line is importing an interface called isSerializable from the Google Web Toolkit
library. A serializable object is an object that can be transmitted and received by the
client-side and server-side applications in the same form without the programmer’s
intervention in coding and decoding it from its state to a byte stream and vice versa.
public class TrackingUpdate implements IsSerializable
This line is stating that the TrackingUpdate class is implementing the IsSerializable
interface.
Now, we need to create the service interface and the implementation of the interface. In
order to do this, follow the next steps:
1. Right click in the package cse.usf.edu.lab5.client.services and in the menu click
New->Java interface
2. Write down the name of the interface as TrackingServiceManager. Click finish
3. Select all the code that appears in the TrackingServiceManager.java screen and
delete it
4. Copy and paste the following code in that area and save it (File->Save)
Listing 2- TrackingServiceManager.java
package cse.usf.edu.lab5.client.services;
import com.google.gwt.user.client.rpc.RemoteService;
import cse.usf.edu.lab5.client.entities.TrackingUpdate;
Page 3 of 24
// An interface that exposes a method that returns the session updates.
public interface TrackingServiceManager extends RemoteService{
public TrackingUpdate[] getTrackingUpdates();
}
There are two important aspects to show of this code. The line,
import com.google.gwt.user.client.rpc.RemoteService
is importing an interface called RemoteService from the Google Web Toolkit library.
This interface does not provide any methods, but its functionality is to state that the
service interface that you wrote is going to be utilized by the Google Web Toolkit as a
service provider. This is stated in the line
public interface TrackingServiceManager extends RemoteService
The next step is to write the service implementation. To do this, follow the next
instructions:
1. Right click in the package cse.usf.edu.lab5.client.services and in the menu click
New->Java class
2. Write down the name of the interface as TrackingServiceManagerImpl. Click
finish
3. Select all the code that appears in the TrackingServiceManagerImpl.java screen
and delete it
4. Copy and paste the following code in that area and save it (File->Save)
Listing 3- TrackingServiceManagerImpl.java
package cse.usf.edu.lab5.client.services;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import cse.usf.edu.lab5.client.entities.TrackingUpdate;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
Page 4 of 24
import javax.naming.NamingException;
import org.postgis.Point;
// Provides server side implementation of the TrackingServiceManager interface
public class TrackingServiceManagerImpl extends RemoteServiceServlet
implements TrackingServiceManager{
public TrackingUpdate[] getTrackingUpdates()
{
Connection theConnection = null;
try{
javax.naming.InitialContext ic = new javax.naming.InitialContext();
javax.sql.DataSource dataSource =
(javax.sql.DataSource)ic.lookup("jdbc/lbsclass");
theConnection = dataSource.getConnection();
PreparedStatement queryStatement =
theConnection.prepareStatement("select fieldsession.sessionid as sesid,
fielduser.username as uname, ST_AsText(tracking.position) as pos "+
"from fieldsession,
tracking,fielduser, (select max(idtracking) as idtrack "+ "from fieldsession, tracking
"+ "where fieldsession.datestop is NULL and fieldsession.sessionid =
tracking.sessionid "+"group by fieldsession.sessionid) as s2 "+"where
fieldsession.datestop is NULL and "+"fieldsession.sessionid = tracking.sessionid
and "+ "tracking.idtracking = s2.idtrack and "+"fieldsession.iduser =
fielduser.iduser");
ResultSet rs = queryStatement.executeQuery();
List returnList = new LinkedList();
while(rs.next())
{
TrackingUpdate newUpdate = new TrackingUpdate();
newUpdate.setSessionid(rs.getInt("sesid"));
newUpdate.setUsername(rs.getString("uname"));
Point theNewPoint = new Point(rs.getString("pos"));
newUpdate.setLongitude(theNewPoint.getX());
newUpdate.setLatitude(theNewPoint.getY());
returnList.add(newUpdate);
}
theConnection.close();
if(!returnList.isEmpty())
{
Page 5 of 24
TrackingUpdate theReturnVector[] = new
TrackingUpdate[returnList.size()];
int i = 0;
for (Iterator it = returnList.iterator(); it.hasNext();)
{
TrackingUpdate theUpdate = (TrackingUpdate) it.next();
theReturnVector[i] = theUpdate;
i++;
}
return theReturnVector;
}
return null;
}
catch (NamingException ex){
Logger.getLogger(TrackingServiceManagerImpl.class.getName()).log(Level.SEVER
E, null, ex);
try {
theConnection.close();
} catch (SQLException ex1) {
Logger.getLogger(TrackingServiceManagerImpl.class.getName()).log(Level.SEVER
E, null, ex1);
}
}
catch (SQLException ex){
Logger.getLogger(TrackingServiceManagerImpl.class.getName()).log(Level.SEVER
E, null, ex);
}
return null;
}
}
In order to understand the code, read the following explanation carefully.
There are many imports in this file. The first import that is written in the code is
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
This import is required because it provides the GWT service functionality. GWT services
are pieces of code that execute over servlets. In Java, servlets are classes that listen for
HTTP requests in a URL and execute code in the server when a client invokes such URL.
The import that comes after this,
import cse.usf.edu.lab5.client.entities.TrackingUpdate;
Page 6 of 24
is making available the class which objects are going to be returned to the client upon the
service invocation.
The next set of imports
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
correspond to the SQL libraries in Java and the list and linked list classes available in the
standard J2SE API.
The following set of imports
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.NamingException;
correspond to the management of the exceptions (errors) that can be raised when the
query is performed in the database.
Finally the last import
import org.postgis.Point;
provides a wrapper of the point object stored in the database. We will use these objects to
translate the coordinates obtained from the query to latitude and longitude values.
The basic idea of this code is to provide an implementation of the service interface for the
TrackingManagerService. In order to do this, the TrackingManagerService.java class
must provide an implementation of such interface. In Java, an implementation of an
interface means to write code in a method whose name and parameters and return value
correspond to the ones that are declared in the interface. Look that in the declaration of
the class
public class TrackingServiceManagerImpl extends RemoteServiceServlet
implements TrackingServiceManager{
it states that the class is implementing the TrackingServiceManager interface. Remember
from Listing 2 that the interface is only declaring one procedure
public TrackingUpdate[] getTrackingUpdates();
This method is therefore the one that is implemented in the TrackingServiceManagerImpl
class. In general, the implementation will query the database to get the location of those
Page 7 of 24
sessions that are active in the system. Those sessions correspond to the sessions in the
database whose date end is null.
The code is basically divided into three sections:
1. Connecting to the database and execution of the query
2. Retrieving of the results of the query
3. Returning an array of TrackingUpdate objects with the information about
sessions.
1. Connecting to the database and execution of the query
For connecting to the database, the code uses a connection pool resource that is
provided by the server where the application is deployed. The code that perform this
is
Connection theConnection = null;
javax.naming.InitialContext ic = new javax.naming.InitialContext();
javax.sql.DataSource dataSource =
javax.sql.DataSource)ic.lookup("jdbc/lbsclass");
theConnection = dataSource.getConnection();
The connection in the code above is obtained by using the jdbc/lbsclass resource from
the database. This code looks for the resource (InitialContect ic = new …), get the
data source and after this, it gets the connection. If the resource is not found, the code
will throw a NamingException.
Now that if the connection is obtained, the code will invoke the database with a query
wrapped in a PreparedStatement object called queryStatement
PreparedStatement queryStatement = theConnection.prepareStatement("select
fieldsession.sessionid as sesid, fielduser.username as uname,
ST_AsText(tracking.position) as pos "+
"from fieldsession, tracking,fielduser, (select max(idtracking) as idtrack "+
"from fieldsession, tracking "+
"where fieldsession.datestop is NULL
and fieldsession.sessionid =
tracking.sessionid "+
group by fieldsession.sessionid) as s2 "+
"where fieldsession.datestop is NULL and "+
"fieldsession.sessionid = tracking.sessionid and "+
"tracking.idtracking = s2.idtrack and "+"fieldsession.iduser = fielduser.iduser"
);
ResultSet rs = queryStatement.executeQuery();
Page 8 of 24
This code is obtaining the last received location per active session in the system. In
order to do this, the SQL query uses a subquery in the from
(select max(idtracking) as idtrack from fieldsession, tracking
where fieldsession.datestop is NULL and fieldsession.sessionid = tracking.sessionid
group by fieldsession.sessionid) as s2
which provides the id of the last valid received location of any active session.
Looking at this subquery, an active session is a session whose datestop is null. As this
subquery is performed in the from part of the query, the results are seen by the
database engine as a table. These results are then cross producted with the others
tables (fieldsession, and tracking) in order to obtain the information we want, which
is the sessionid, the username, and the location of each active session. The statement
ResultSet rs = queryStatement.executeQuery();
is the one that performs the query to the database.
2. Retrieving of the results of the query
As there is no way to know beforehand the number of records in the ResultSet to
safely allocate the size of the returning TrackingUpdate array, we will use a list of
TrackingUpdate objects as intermediate storage for obtaining the records from the
ResultSet and know the size of the returning array. The code that provides this
functionality is
List returnList = new LinkedList();
while(rs.next())
{
TrackingUpdate newUpdate = new TrackingUpdate();
newUpdate.setSessionid(rs.getInt("sesid"));
newUpdate.setUsername(rs.getString("uname"));
Point theNewPoint = new Point(rs.getString("pos"));
newUpdate.setLongitude(theNewPoint.getX());
newUpdate.setLatitude(theNewPoint.getY());
returnList.add(newUpdate);
}
theConnection.close();
This code iterates over the ResultSet, creating a TrackingUpdate object per active
session record in the database and adding each object to a list (returnList). From this
code observe the lines
Page 9 of 24
Point theNewPoint = new Point(rs.getString("pos"));
newUpdate.setLongitude(theNewPoint.getX());
newUpdate.setLatitude(theNewPoint.getY());
As the location is obtained as a text string from the query, the org.postgis.Point object
is providing the parsing from string to double values for the latitude and longitude.
Once all the records have been placed in the list, we can know the size of the array.
3. Returning an array of TrackingUpdate objects with the information about sessions
The last part of this code is the one that returns the array. The code which is shown
below, builds an array of TrackingUpdates using the size of the list for its own size.
After this, it basically iterates over the list, and copies the contents of the list to the
array. If the list is empty, the procedure will return null.
if(!returnList.isEmpty())
{
TrackingUpdate theReturnVector[] = new
TrackingUpdate[returnList.size()];
int i = 0;
for (Iterator it = returnList.iterator(); it.hasNext();)
{
TrackingUpdate theUpdate = (TrackingUpdate) it.next();
theReturnVector[i] = theUpdate;
i++;
}
return theReturnVector;
}
return null;
In order to test the database, use the following username and password to connect to the
lbsclass_lab5 database and set up your connection pool and jdbc resource in the Sun Java
Application Server.
Username: lbsclass
Password: lab5
Set up a connection in the PgAdmin so you can run the “select” query statement from
there. We have populated the database with some information. The result of the query
should be:
424;”phoneuser4”;”POINT(-82.4563676118851
27.9414403438568)”813;”taclan0”;”POINT(-82.411315
28.0601866666667)”848;”ajperez4”;”POINT(-82.41472166666667 28.0598483333333)”
Page 10 of 24
This corresponds to the locations and active sessions in the database that are used to show
the locations in the map.
The lbsclass_lab5 database is the one that you should use for your lab.
Now that we have the implementation developed, the next step is to register the
implementation with the Web application deployment descriptor. To do this, follow the
next steps:
1. Go to the Project panel, click on the + sign of the label Configuration and double
click over the web.xml file
2. A page that contains the configuration of the application appears on the right side.
Click on the Servlets button and click the Add Servlet Element button
3. In the window, write GwtDeviceManager in the Name textfield. In the Servlet
class click on the Browse button and look for the
TrackingServiceManagerImpl.java class. In URL Pattern(s) write
/services/TrackingManager. Click OK and click the File->Save
4. When deployed, the URL of the TrackingManager will be
http://ip_machine:port/lab5/services/TrackingManager. This URL will be used by
the client to invoke the service.
At this point, the server side code can be deployed. To do this, go to the Projects panel,
right click on the project, and choose the Clean and Build option. After the building
process is completed, go again to the Projects panel, right click on the project, and choose
the Deploy option.
Now, we are ready to create the Eclipse GWT project.
Experiment 2 Creating a GWT project in Eclipse and configuring it to use Google
Maps
In this part you will create the Eclipse GWT project to develop a Google Map
application.
To get started, do the following steps:
1. Go to the Windows Command line. (Start button -> Run, in the Open text box
write cmd.exe and click OK
2. Change folder to the folder you have placed the Google Web Toolkit
3. Write the following commands
projectCreator -eclipse Lab5 -out Lab5
Page 11 of 24
and then
applicationCreator -eclipse Lab5 -out Lab5 -overwrite cse.usf.edu.lab5.client.Lab5
4. Open Eclipse, and select your workspace
5. Go to menu File->Import, under General select Existing projects into Workspace
and click Next
6. Select the root directory which in our case is the folder where the GWT was
installed. Click OK
7. Now check the option Copy projects into workspace and click Finish
8. Run the project, to do this right click on the project name in the Package Explorer
(upper right side) Run As -> Run Configurations
9. On the left side of the window, click Java Application and select Lab5. Click Run
10. To close the application, close the Google Web Toolkit Development Shell
Now we have a basic GWT project on which we will develop the visualization of the
sessions.
11. Create a Google Maps key for the http://localhost:8888/ by signing with Google
in the following URL http://code.google.com/apis/maps/signup.html
12. Add the Google Maps library to the project. To do this right click in the project
name in the Package Explorer, then in the menu click Properties. Click in Java
Build Path and in the right panel click in Libraries. Now click Add External JAR,
search and select the gwt-maps.jar file. Click Open and OK.
13. Use the package explorer to find the Lab5.gwt.xml file. This file should be in the
src->cse.usf.edu.lab5 path. Right click in the file and then in the menu click Open
With->Text Editor.
Under the line <inherits name=’com.google.gwt.user.User’/> write the following:
<inherits name=’com.google.gwt.maps.GoogleMaps’/>
Under the line <stylesheet src='Lab5.css' /> write the following line
<script
src="http://maps.google.com/maps?gwt=1&file=api&v=2&key=yo
ur_key"/>
Replace the your_key with the key obtained in step 11 and save the changes to the
file.
Every application developed with GWT has a .gwt.xml file. This file can be seen as the
application descriptor. It contains information that the GWT shell and compiler utilize to
link external JavaScript libraries and start the application.
Page 12 of 24
Experiment 3 Creating a visual interface that uses Google Maps to show the active
sessions in the system
1. Create two packages in your Eclipse project named exactly the same as the ones
of steps 12 and 13 of Experiment 1. To do this, right click in the project’s name in
the Package Explorer, and in the menu click New->Package
2. Create a class as shown in Listing 1 under the package
cse.usf.edu.lab5.client.entities. Copy the contents of Listing 1 to this class
3. Create an interface as shown in Listing 2 under the package
cse.usf.edu.lab5.client.services. Copy the contents of Listing 2 to this
interface
4. Under the package cse.usf.edu.lab5.client.services create an interface called
TrackingServiceManagerAsync
5. Select all the code that appears in the TrackingServiceManager.java screen and
delete it
6. Copy and paste the following code in that area and save it (File->Save)
Listing 4- TrackingServiceManagerAsync.java
package cse.usf.edu.lab5.client.services;
import com.google.gwt.user.client.rpc.AsyncCallback;
import cse.usf.edu.lab5.client.entities.TrackingUpdate;
public interface TrackingServiceManagerAsync {
public void getTrackingUpdates(AsyncCallback callback);
}
7. Create a new class called TrackingWindow under the cse.usf.edu.lab5.client
package. Erase all the code that appears in the TrackingWindow.java and replace
it by the code shown in Listing 5
Listing 5- TrackingServiceManager.java
package cse.usf.edu.lab5.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.*;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
Page 13 of 24
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.control.LargeMapControl;
import com.google.gwt.maps.client.control.MapTypeControl;
import com.google.gwt.maps.client.event.MarkerClickHandler;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.overlay.Marker;
import cse.usf.edu.lab5.client.entities.TrackingUpdate;
import cse.usf.edu.lab5.client.services.TrackingServiceManager;
import cse.usf.edu.lab5.client.services.TrackingServiceManagerAsync;
public class TrackingWindow extends Composite {
private AbsolutePanel backgroundPanel = null;
private MapWidget theMapWidget = null;
private Timer trackingTimer = null;
public TrackingWindow() {
super();
initializeComponents();
setLayout();
setProperties();
}
protected void initializeComponents(){
backgroundPanel = new AbsolutePanel();
theMapWidget = new MapWidget();
backgroundPanel.add(theMapWidget, 1,1);
updateActiveSessions();
trackingTimer = new Timer()
{
public void run()
{
updateActiveSessions();
}
};
trackingTimer.scheduleRepeating(10000);
}
protected void setLayout(){
initWidget(backgroundPanel);
}
protected void setProperties(){
setHeight("600");
Page 14 of 24
setWidth("800");
backgroundPanel.setHeight("600");
backgroundPanel.setWidth("800");
theMapWidget.setHeight("600");
theMapWidget.setWidth("800");
theMapWidget.addControl(new LargeMapControl());
theMapWidget.addControl(new MapTypeControl());
}
public void updateActiveSessions()
{
}
}
8. Replace the updateActiveSessions() method of the above code with the code
shown in Listing 6. Replace the String serviceURL = .... line with the following
line:
String serviceURL = http://ip_machine:port/lab5/services/TrackingManager;
where ip_machine:port corresponds to the ip and HTTP port number where your
server side code is deployed.
9. Open the Lab5.java class which can be found in the cse.usf.edu.lab5.client
package. Modify the onModuleLoad() as shown in Listing 7. Save the code.
Listing 6- The updateActiveSessions method
public void updateActiveSessions()
{
TrackingServiceManagerAsync theTrackingManager =
(TrackingServiceManagerAsync) GWT.create(TrackingServiceManager.class);
ServiceDefTarget endpoint = (ServiceDefTarget) theTrackingManager;
String remoteServiceURL =
"http://localhost:8080/LbsBook/services/TrackingManager";
endpoint.setServiceEntryPoint(remoteServiceURL);
AsyncCallback callback = new AsyncCallback()
{
public void onSuccess(Object result)
{
TrackingUpdate theUpdates[] = (TrackingUpdate[]) result;
if(theUpdates != null)
{
theMapWidget.clearOverlays();
Page 15 of 24
for(int i = 0; i < theUpdates.length; i++)
{
final LatLng coordinates =
LatLng.newInstance(theUpdates[i].getLatitude(), theUpdates[i].getLongitude());
final String theString = "Username:
"+theUpdates[i].getUsername()+"<br>Session id:"+theUpdates[i].getsessionId();
Marker theNewMarker = new Marker(coordinates);
MarkerClickHandler theHandler = new MarkerClickHandler(){
public void onClick(MarkerClickEvent event) {
theMapWidget.getInfoWindow().open(coordinates, new
InfoWindowContent(theString));
}
};
theNewMarker.addMarkerClickHandler(theHandler);
theMapWidget.addOverlay(theNewMarker);
}
}
}
public void onFailure(Throwable caught)
{
Window.alert("An Internal Error has ocurred: " +
caught.getMessage());
trackingTimer.cancel();
}
};
theTrackingManager.getTrackingUpdates(callback);
}
Listing 7- The onModuleLoad method in Lab5.java class
public void onModuleLoad()
{
VerticalPanel vPanel = new VerticalPanel();
vPanel.setWidth("100%");
vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
RootPanel.get().add(vPanel);
TrackingWindow theWindow = new TrackingWindow();
final DialogBox dialogBox = new DialogBox();
Page 16 of 24
dialogBox.setText("Map Example");
dialogBox.setAnimationEnabled(true);
dialogBox.add(theWindow);
dialogBox.center();
dialogBox.show();
}
In order to understand the code, read the following explanation carefully. First take a
look at the TrackingWindow.java file.
There are many imports in this file. The first import that is written in the code is
import com.google.gwt.core.client.GWT;
This line is importing core functionalities from the framework, utilized for creating/loading
classes in runtime. This is used in the code for creating the proxy that will perform the RPC
(Remote Procedure Call).
The next set of imports are needed for the user interface
import com.google.gwt.user.client.*;
import com.google.gwt.user.client.ui.*;
The following imports are needed for the classes that perform the remote procedure call
to the server (to get the session location updates).
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
;
Now this set of imports is needed to utilize the Google Maps classes. The first import in
the set is the MapWidget. This class represents the Google Maps. The second and third
(LargeMapControl and MapTypeControl) provides the map with the controllers to scroll
the map and zoom to it and choose the map type (satellite, physical, etc...). The next two
(MarkerClickHandler and InfoWindowContent) are needed as we will display the session
information in a box when a balloon that represents the location of a session is clicked.
Finally the last two imports of this set (the LatLng and the Marker) are used for the
markers that are shown in the map and the location of such markers.
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.control.LargeMapControl;
import com.google.gwt.maps.client.control.MapTypeControl;
import com.google.gwt.maps.client.event.MarkerClickHandler;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.overlay.Marker;
Page 17 of 24
Finally, the last set of imports for this class are
import cse.usf.edu.lab5.client.entities.TrackingUpdate;
import cse.usf.edu.lab5.client.services.TrackingServiceManager;
import cse.usf.edu.lab5.client.services.TrackingServiceManagerAsync;
These correspond to the class that abstracts the session information (TrackingUpdate) and
the remote service interfaces.
The main idea with this class is to provide a user interface component that every ten
seconds retrieves updates about the sessions in the system and show such information in a
map. In GWT those own UI components can be developed by extending the Composite
class. The Composite class in GWT is provided to wrap user components in a single
window (similar to the Jframe class in J2SE). Look that we do this on this line:
public class TrackingWindow extends Composite
The TrackingWindow class has three private variables, these are:
private AbsolutePanel backgroundPanel = null;
private MapWidget theMapWidget = null;
private Timer trackingTimer = null;
The first variable (backgroundPanel) is utilized as the base panel where the components of the
TrackingWindow will be added. The second (theMapWidget) is the instance of the Google Maps
where the locations will be shown. Finally, the third variable (trackingTimer) provides us with the
functionality to invoke the server every ten seconds.
The TrackingWindow class is made of 5 methods:
public TrackingWindow(): Constructor of the class.
initializeComponents, setLayout, and setProperties methods.
This
method
invokes
the
protected void initializeComponents(): Initializes the three variables. This method is also
utilized to setup the timer to invoke the update of the session information every 10 seconds.
protected void setLayout(): Initializes the background panel.
protected void setProperties(): Set the sizes for the background panel and for the MapWidget.
public void updateActiveSessions(): Invokes the remote server procedure to update the session
information. This method is the one that the timer invokes every 10 seconds.
From these methods, we will explain the updateActiveSessions and the initializeComponents
method as these are the two most important methods of this class.
Page 18 of 24
As it has been stated before, the updateActiveSessions performs the invocation of the remote
procedure in the server. In order to do this, the method performs the following steps:
Proxy creation: The proxy is created by the factory method GWT.create() in the line
TrackingServiceManagerAsync theTrackingManager = (TrackingServiceManagerAsync)
GWT.create(TrackingServiceManager.class);
using the service interface and returning an object that implements the asynchronous
service interface. The proxy transmits the objects using HTTP, hiding the details from the
programmers.
Remote service location set up: A remote service location is set up in the lines
ServiceDefTarget endpoint = (ServiceDefTarget) theTrackingManager;
String remoteServiceURL = "http://localhost:8080/LbsBook/services/TrackingManager";
endpoint.setServiceEntryPoint(remoteServiceURL);
where the URL of the Web object that implements the RPC service is located.
Manager of the response set up: A response manager is set up between the lines
AsyncCallback callback = new AsyncCallback()
{
public void onSuccess(Object result)
{
..
}
public void onFailure(Throwable caught)
{
...
}
};
where the callback object is created. AsyncCallback is an interface that implements two
methods. The first, which is onSuccess(), is executed when the RPC is completed with
success. The other, onFailure(), is executed if there is a communication failure with the
server. Here we are creating an anonymous class that implements the AsyncCallback
interface. In our code, the onSuccess method will be adding the session information to the
Google Map. The onFailure() method will show a dialog box showing that something
went wrong when performing the invocation.
Objects preparation and RPC service invocation: This is done on the line
theTrackingManager.getTrackingUpdates(callback);
which is the line that actually performs the RPC call. In our example, there are no
parameters for the invocation of the RPC. A question that you might be asking now is
Page 19 of 24
why the AsyncCallback object is used to manage the response of the communication. The
answer for this is as programs in JavaScript are single threaded, if there is a blocking call
in the code, your JavaScript application freezes until the code returns. In this perspective,
when you do asynchronous calls, you are avoiding the blocking of RPC calls, and
therefore managing the invocation as events: one event that executes when the invocation
was performed successfully, the other when it is not successful.
Now take a look on the onSuccess of the AsyncCallback object
public void onSuccess(Object result)
{
TrackingUpdate theUpdates[] = (TrackingUpdate[]) result;
if(theUpdates != null)
{
theMapWidget.clearOverlays();
for(int i = 0; i < theUpdates.length; i++)
{
final LatLng coordinates =
LatLng.newInstance(theUpdates[i].getLatitude(), theUpdates[i].getLongitude());
final String theString = "Username:
"+theUpdates[i].getUsername()+"<br>Session id:"+theUpdates[i].getsessionId();
Marker theNewMarker = new Marker(coordinates);
MarkerClickHandler theHandler = new MarkerClickHandler(){
public void onClick(MarkerClickEvent event) {
theMapWidget.getInfoWindow().open(coordinates, new
InfoWindowContent(theString));
}
};
theNewMarker.addMarkerClickHandler(theHandler);
theMapWidget.addOverlay(theNewMarker);
}
}
}
The first line TrackingUpdate theUpdates[] = (TrackingUpdate[]) result; is performing a
casting on result parameter of the onSuccess call. In Java, casting means the
interpretation of an object as another one. To do this, in runtime the system checks the
types for both the object you are casting and the variable that you cast to. If the types do
not correspond, then it throws a runtime exception. In this line, we are casting the Object
Result to a vector of TrackingUpdate objects.
Page 20 of 24
Now the following lines are adding a balloon in the MapWidget object per active session
in the system.
theMapWidget.clearOverlays();
for(int i = 0; i < theUpdates.length; i++)
{
final String theString = "Username:
"+theUpdates[i].getUsername()+"<br>Session id:"+theUpdates[i].getsessionId();
Marker theNewMarker = new Marker(coordinates);
MarkerClickHandler theHandler = new MarkerClickHandler(){
public void onClick(MarkerClickEvent event) {
theMapWidget.getInfoWindow().open(coordinates, new
InfoWindowContent(theString));
}
};
theNewMarker.addMarkerClickHandler(theHandler);
theMapWidget.addOverlay(theNewMarker);
}
The first line theMapWidget.clearOverlays();
is cleaning all the overlays in the map. After this, the code iterates over the array of
TrackingUpdates and for every session it performs the following steps:



Creation of a Map coordinates: This is performed in the line
coordinates
=
theUpdates[i].getLongitude());
final LatLng
LatLng.newInstance(theUpdates[i].getLatitude(),
Creation of a marker based on the coordinates:
Marker theNewMarker = new
Marker(coordinates);
Creation a click handler for the marker: Upon the click the marker, this code will
display a window with information about the session
MarkerClickHandler theHandler = new MarkerClickHandler(){
public void onClick(MarkerClickEvent event) {
theMapWidget.getInfoWindow().open(coordinates, new
InfoWindowContent(theString));
}
};
theNewMarker.addMarkerClickHandler(theHandler);
Page 21 of 24

Adding
the
overlay
to
the
map.
This is performed in the line
theMapWidget.addOverlay(theNewMarker); which finally adds the marker to the
map.
Now go to the initalizeComponents() method of the TrackingWindow class. The
important part of this code is the one that uses a timer to invoke the code that updates the
session information
trackingTimer = new Timer()
{
public void run()
{
updateActiveSessions();
}
};
trackingTimer.scheduleRepeating(10000);
All code that is within the run() method will be executed every certain amount of time, in
this case, such time is setup to be 10 seconds. This is a way to emulate threads in GWT,
however there is no thread concept in GWT, as all the applications in JavaScript are
single threaded.
The final explanation of this lab guide is how to initialize (entry point) a GWT
application. Go to the Lab5.java class. You should have the code shown in Listing 8.
Listing 8- The Lab5.java class
package cse.usf.edu.lab5.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class Lab5 implements EntryPoint {
Page 22 of 24
/**
* This is the entry point method.
*/
public void onModuleLoad()
{
VerticalPanel vPanel = new VerticalPanel();
vPanel.setWidth("100%");
vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
RootPanel.get().add(vPanel);
TrackingWindow theWindow = new TrackingWindow();
final DialogBox dialogBox = new DialogBox();
dialogBox.setText("Map Example");
dialogBox.setAnimationEnabled(true);
dialogBox.add(theWindow);
dialogBox.center();
dialogBox.show();
}
}
In GWT an entry point of a GWT application is defined as a class that implements the
EntryPoint interface. This interface declares the onModuleLoad() method that will be
utilized as the first code that the application will execute when initialized. In this case,
this code is declaring a panel where a DialogBox is added to it, and in the dialog box we
are adding an instance of the TrackingWindow application.
The entry point of the application is referenced in the Lab5.gwt.xml file. Look for this
file on your project tree and you will find a line that says:
<entry-point class='cse.usf.edu.lab5.client.Lab5'/>
This line is configuring you application to declare what will be the entry point, in this
case, this is the cse.usf.edu.lab5.client.Lab5 class.
Now that the client and server codes have been developed, it is time to compile the
application with GWT and deploy it along with the Web Project. The following steps
indicate how to accomplish this:
1. Compile the Eclipse project with GWT: Run the Eclipse project and click on the
Compile/Browse button
2. Copy the compiled files to the Web project application: Using the Windows
Explorer, go to the Eclipse's GWT project location and copy the folder www to
the Web folder of the NetBeans project
3. Build and Deploy: Using NetBeans, build and deploy the Web project
Page 23 of 24
After the Web application has been deployed, it can be executed from a Web browser. In
our case the URL to use would be http://ip_machine:port/lab5/services/TrackingManager;
which consists of the path where the application resides in the server with IP address
ip_machine:port.
Experiment 5 Modify the TrackingWindow in such way that when the user clicks on
the map, it not only shows the marker but also shows a table with the distance in meters
from the coordinate that corresponds to the click to each of the active sessions. You must
show in a text field the location of the click (in lat, long format) and in the table the user,
the location (in lat, long format), and the distance. Hint: use the FlexTable component
for the table and look in the gwt-maps javadocs for the click map listeners for the
MapWidget.
Report
Turn in your software and a written report including:
1. Name of group members
2. Date of the project’s submission
3. Names of all project folders submitted
4. A brief set of instructions for using your application
5. Screen shots of your application, as appropriate
6. A brief summary of the activities and description of any problems you
encountered
Page 24 of 24
Download