Visualizing the Data Dr. Miguel A. Labrador Department of Computer Science & Engineering labrador@csee.usf.edu http://www.csee.usf.edu/~labrador 1 Outline • • • • • • The big picture Google Web Toolkit (GWT) GWT development process AJAX RPC approach Client code Sever code 2 Copyright© Dr. Miguel A. Labrador 2 Visualization • Our tracking application includes a “main control station” connected to the Internet to visualize the position of the users in real time – Google Web Toolkit and Google Maps 3 Copyright© Dr. Miguel A. Labrador 3 The Big Picture • Client code – Runs in main control station – Sends queries to the server asking for the coordinates of all active sessions – Upon reception of coordinates, it shows them in a Google Map • Server code – Implements an interface that listens for queries asking for coordinates – Once a query is received, it connects to the database and retrieves the last coordinates of all active sessions – Sends an array of coordinates back to the client • Key aspect is the communication part – GWT provides an easy approach to make RPC calls to the server • AJAX RPC Approach 4 Copyright© Dr. Miguel A. Labrador 4 Google Web Toolkit • The Google Web Toolkit is a framework to create dynamic and interactive Web applications – Code is written in Java – Parts of a GWT application execute in the Web client (browser) and other parts in the Web server • The part that executes in the Web client runs in JavaScript • The GWT compiles Java into JavaScript • Client code developed in Eclipse and GWT – Once compiled, it has to be copied in the server so it can be deployed in the Internet • Server code developed in NetBeans 5 Copyright© Dr. Miguel A. Labrador 5 GWT Development Process Server Side Client Side 6 Copyright© Dr. Miguel A. Labrador 6 The AJAX RPC Approach GWT Client Application Service Interface related Server Service Interface Asynchronous Interface implements implements Class Service Proxy Implementation (generated by GWT) HTTP Class Service Implementation (written by the programmer) 7 Copyright© Dr. Miguel A. Labrador 7 The AJAX RPC Approach Client Side Code • Service interface – Abstracts the methods that can be invoked by a client – Each service interface defines the functions that the system implements • Asynchronous interface – Abstracts the methods that are actually invoked by the client • It is related to the service interface – Needed not to block the Web browser • Class service proxy or client-side service implementation – Class that actually invokes the RPC procedure – Automatically generated by GWT – Implements the data serialization over HTTP 8 Copyright© Dr. Miguel A. Labrador 8 The AJAX RPC Approach Server Side Code • Class service implementation or server-side service implementation – Class that implements the service interface in the server – Executes in the server when a client invokes a method of the RPC service interface • Two important aspects of the GWT AJAX RPC approach: – GWT serializes the objects for you – GWT transmits the objects back and forth for you 9 Copyright© Dr. Miguel A. Labrador 9 Client Side Project • Creating a new project in Eclipse – Open a cmd line window in directory where GWT was installed and type: projectCreator -eclipse LbsBookGWT -out LbsBookGWT applicationCreator -eclipse LbsBookGWT -out LbsBookGWT cse.usf.edu.book.client.GwtBook • Import project into Eclipse’s workspace – Run it to check it was imported successfully 10 Copyright© Dr. Miguel A. Labrador 10 Client Side Project • Eclipse creates an application skeleton with two packages and several files (see Package Explorer) 11 Copyright© Dr. Miguel A. Labrador 11 Client Side Project Skeleton Files • Eclipse creates a basic application – Skeleton packages and files that need to be modified to make your own application • Package cse.usf.edu.book contains all Web pages and images – Contains GetBook.css file • Cascade Style File with style of all html objects – Contains the GwtBook.html file that loads the GWT module in the browser and invokes the application – Contains GwtBook.gwt.xml file • Contains information that GWT use to compile and link libraries • Defines application entry point • Package cse.usf.edu.book.client contains the Java source code of the client application – File GwtBook.java serves as the entry point of the application • Your application 12 Copyright© Dr. Miguel A. Labrador 12 Configuring a GWT Project • In order to utilize the Google Maps API in GWT, the following steps have to be followed: – Sign up for a Google Maps key for the URL where the application will be deployed • http://code.google.com/apis/maps/ – Download the Google Maps API library for GWT • http://code.google.com/p/wgt-google-apis/ – Import the library into the GWT Eclipse Project • Add gwt-maps.jar file to the GWT project – Open Eclipse, go to Package Explorer, right click on the project’s name and click on Properties – Select Java Build Path and click on the Libraries tab panel – Click on Add external JAR and find the gwt-maps.jar file that you downloaded – Click Open and Ok 13 Copyright© Dr. Miguel A. Labrador 13 Configuring a GWT Project • In order to utilize the Google Maps API in GWT, the following steps have to be followed: – Configure the GWT project .xml file and develop your code • Open the GwtBook.gwt.xml file and include your key <module> <!-- Inherit the core Web Toolkit stuff. <inherits name='com.google.gwt.user.User'/> --> <!-- Inherit the default GWT style sheet. --> <inherits name='com.google.gwt.user.theme.standard.Standard'/> <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> --> <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> --> <inherits name='com.google.gwt.maps.GoogleMaps'/> <!-- Specify the app entry point class. <entry-point class='cse.usf.edu.book.client.GwtBook'/> --> <!-- Specify the application specific style sheet. --> <stylesheet src='GwtBook.css' /> <script src="http://maps.google.com/maps?gwt=1&amp;file=api&amp;v=2&amp;key=Your key"/> </module> 14 Copyright© Dr. Miguel A. Labrador 14 The GwtBook.html File <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!---> <!-- Any title is fine --> <!---> <title>GwtBook</title> <!-- This script loads your compiled module. --> <script type="text/javascript" language="javascript" src="cse.usf.edu.book.GwtBook.nocache.js"></script> </head> <!-<!-- The body can have arbitrary html, or <!-- you can leave the body empty if you want <body> --> --> --> <!-- OPTIONAL: include this if you want history support --> <iframe src="javascript:" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe> </body> </html> 15 Copyright© Dr. Miguel A. Labrador 15 The GwtBook.java File package cse.usf.edu.book.client; import import import import import import import import com.google.gwt.core.client.EntryPoint; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.ClickListener; com.google.gwt.user.client.ui.DialogBox; com.google.gwt.user.client.ui.Image; com.google.gwt.user.client.ui.RootPanel; com.google.gwt.user.client.ui.VerticalPanel; com.google.gwt.user.client.ui.Widget; public class GwtBook implements EntryPoint { public void onModuleLoad() { Image img = new Image("http://code.google.com/webtoolkit/logo-185x175.png"); Button button = new Button("Click me"); // We can add style names button.addStyleName("pc-template-btn"); // or we can set an id on a specific element for styling img.getElement().setId("pc-template-img"); VerticalPanel vPanel = new VerticalPanel(); vPanel.setWidth("100%"); vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER); vPanel.add(img); vPanel.add(button); 16 Copyright© Dr. Miguel A. Labrador 16 The GwtBook.java File // Add image and button to the RootPanel RootPanel.get().add(vPanel); // Create the dialog box final DialogBox dialogBox = new DialogBox(); dialogBox.setText("Welcome to GWT!"); dialogBox.setAnimationEnabled(true); Button closeButton = new Button("close"); VerticalPanel dialogVPanel = new VerticalPanel(); dialogVPanel.setWidth("100%"); dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER); dialogVPanel.add(closeButton); closeButton.addClickListener(new ClickListener(){ public void onClick(Widget sender) { dialogBox.hide(); }}); // Set the contents of the Widget dialogBox.setWidget(dialogVPanel); button.addClickListener(new ClickListener(){ public void onClick(Widget sender) { dialogBox.center(); dialogBox.show(); }}); } } 17 Copyright© Dr. Miguel A. Labrador 17 18 Copyright© Dr. Miguel A. Labrador 18 Client Side Code • You need to modify these skeleton files to make your own application • In our case, we need to develop an application that will query the server (database) for the last positions of the active users and display them in a Google map • The steps are the following: – Main tracking component – Create a serializable object that will contain the information from the database and methods to operate on the object – Create client service interface with the functions or services to be implemented – Create the Asynchronous service interface – Develop the code that will implement the methods – Modify the skeleton files • GWT .xml file, onModuleLoad() 19 Copyright© Dr. Miguel A. Labrador 19 Main Tracking Component package cse.usf.edu.book.client; import import import import import import import com.google.gwt.maps.client.MapWidget; com.google.gwt.maps.client.control.LargeMapControl; com.google.gwt.maps.client.control.MapTypeControl; com.google.gwt.maps.client.geom.LatLng; com.google.gwt.maps.client.overlay.Marker; com.google.gwt.user.client.*; com.google.gwt.user.client.ui.*; public class TrackingWindow extends Composite { private AbsolutePanel backgroundPanel = null; private MapWidget theMapWidget = null; public TrackingWindow() { super(); initializeComponents(); setLayout(); setProperties(); LatLng coordinates = LatLng.newInstance(28.055166, -82.413511); Marker theNewMarker = new Marker(coordinates); theMapWidget.addOverlay(theNewMarker); theMapWidget.setZoomLevel(14); theMapWidget.setCenter(coordinates); } 20 Copyright© Dr. Miguel A. Labrador 20 Main Tracking Component protected void initializeComponents(){ backgroundPanel = new AbsolutePanel(); theMapWidget = new MapWidget(); backgroundPanel.add(theMapWidget,1,1); } protected void setLayout(){ initWidget(backgroundPanel); } protected void setProperties(){ setHeight("600"); 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() { } 21 } Copyright© Dr. Miguel A. Labrador 21 Serializable Object package cse.usf.edu.book.client.entities; import com.google.gwt.user.client.rpc.IsSerializable; public class TrackingUpdate implements IsSerializable{ private double latitude; private double longitude; private int sessionid; private String username; public TrackingUpdate(){} public int getsessionId(){return sessionid;} public String getUsername(){return username;} public double getLatitude(){return latitude;} public double getLongitude(){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;} 22 } Copyright© Dr. Miguel A. Labrador 22 Service and Asynchronous Service Interfaces package cse.usf.edu.book.client.services; import com.google.gwt.user.client.rpc.RemoteService; import cse.usf.edu.book.client.entities.TrackingUpdate; public interface TrackingServiceManager extends RemoteService{ public TrackingUpdate[] getTrackingUpdates(); } package cse.usf.edu.book.client.services; import com.google.gwt.user.client.rpc.AsyncCallback; import cse.usf.edu.book.client.entities.TrackingUpdate; public interface TrackingServiceManagerAsync { public void getTrackingUpdates(AsyncCallback callback); } 23 Copyright© Dr. Miguel A. Labrador 23 Method Implementation public void updateActiveSessions() { TrackingServiceManagerAsync theTrackingManager = (TrackingServiceManagerAsync) GWT.create(TrackingServiceManager.class); ServiceDefTarget endpoint = (ServiceDefTarget) theTrackingManager; String remoteServiceURL = "http://192.168.0.2:8080/Lbsbook/services/TrackingManager"; endpoint.setServiceEntryPoint(remoteServiceURL); AsyncCallback callback = new AsyncCallback(){ public void onSuccess(Object result){ TrackingUpdate theUpdates[] = (TrackingUpdate[]) result; 24 Copyright© Dr. Miguel A. Labrador 24 Method Implementation 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)); } }; 25 Copyright© Dr. Miguel A. Labrador 25 Method Implementation theNewMarker.addMarkerClickHandler(theHandler); theMapWidget.addOverlay(theNewMarker); } } } public void onFailure(Throwable caught){ Window.alert("An Internal Error has ocurred: " + caught.getMessage()); } }; theTrackingManager.getTrackingUpdates(callback); } 26 Copyright© Dr. Miguel A. Labrador 26 Get the Positions Periodically • Need to modify the initializeComponents() method to include a timer to query for the active sessions every 10 seconds // this code assumes that there is a field in the class called trackingTimer. // to do this, add the following field Timer trackingTimer to the class. protected void initializeComponents(){ backgroundPanel = new AbsolutePanel(); theMapWidget = new MapWidget(); backgroundPanel.add(theMapWidget, 1,1); trackingTimer = new Timer() { public void run() { updateActiveSessions(); } }; trackingTimer.scheduleRepeating(10000); } 27 Copyright© Dr. Miguel A. Labrador 27 Server Side Code • Server code consists of the same serializable class and implementation of the service interface and the methods that, upon the invocation from the client, implement the requested functions in the server – All these developed in NetBeans • First step is to create a new project in NetBeans – New Java Web Application • Add GWT Library to your Project – Add the gwt-servelt.jar file in the GWT installation directory 28 Copyright© Dr. Miguel A. Labrador 28 Server Side Code • Next is to create the serializable class TrackingUpdate – Same name and code as the client – Under the same package cse.usf.edu.book.client.entities • Next is to create the corresponding service interface – Create a package with the same name as the package that contains the service interface in the client • cse.usf.edu.book.client.services – Create an interface just as the one created for the client but with the “Impl” suffix • TrackingServiceManagerImpl • Implements the methods defined in the service interface – Only one: getTrackingUpdates() method • This includes the code that upon the client’s request, will query the database and return the list of GPS fixes – The fixes will be sent in the serializable object – The transmission of the object is completely hidden to the programmer!!! 29 Copyright© Dr. Miguel A. Labrador 29 The TrackingServiceManagerImpl Method package cse.usf.edu.book.client.services; import import import import import import import import import import import import import com.google.gwt.user.server.rpc.RemoteServiceServlet; cse.usf.edu.book.client.entities.TrackingUpdate; java.sql.Connection; java.sql.PreparedStatement; java.sql.ResultSet; java.sql.SQLException; java.util.Iterator; java.util.LinkedList; java.util.List; java.util.logging.Level; java.util.logging.Logger; javax.naming.NamingException; org.postgis.Point; public class TrackingServiceManagerImpl extends RemoteServiceServlet implements TrackingServiceManager{ 30 Copyright© Dr. Miguel A. Labrador 30 The TrackingServiceManagerImpl Method public TrackingUpdate[] getTrackingUpdates() { try{ javax.naming.InitialContext ic = new javax.naming.InitialContext(); javax.sql.DataSource dataSource = (javax.sql.DataSource)ic.lookup("jdbc/lbsbook"); Connection 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"); 31 Copyright© Dr. Miguel A. Labrador 31 The TrackingServiceManagerImpl Method 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(); 32 Copyright© Dr. Miguel A. Labrador 32 The TrackingServiceManagerImpl Method 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; } catch (NamingException ex){ Logger.getLogger(DevicerServiceManagerImpl.class.getName()) .log(Level.SEVERE, null, ex); } catch (SQLException ex){ Logger.getLogger(DevicerServiceManagerImpl.class.getName()) .log(Level.SEVERE, null, ex); } return null; } } 33 Copyright© Dr. Miguel A. Labrador 33 Server Side Code • Once the project, classes, packages, interfaces, and implementations are ready, the next step is to register the implementation with the Web application deployment descriptor – Go to the Project panel, click on the + sign of the label Configuration and double click over the web.xml file – 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 – In the window, write GwtTrackingManager 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. – At this point, the server side code can be deployed – 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 34 Copyright© Dr. Miguel A. Labrador 34 Final Step • 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: – Compile the Eclipse project with GWT: Run the Eclipse project and click on the Compile/Browse button – 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 – Build and Deploy • Using NetBeans, build and deploy the Web project • 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. 35 Copyright© Dr. Miguel A. Labrador 35