by Sue Spielman and Tom Whitehill 04/01 / 2004In part one of this Java and GIS series, we acquired the vocabulary that surrounds the GIS space. Understanding the terminology is critical when talking about GIS applications. In part two of this three-part series , we are going to take a look at the mobile Java client. We're going to build a simple Location Based Services (LBS) MIDLet to show what needs to happen on a mobile device and how to get that information to a server. Part three of this series will take the location information and show how a map can be created using the location coordinates. We're assuming that you've got some J2ME background (since we are not going to be going into detail on the MIDLet life -CYCLE, AS WELL AS Background On How To Create and Deploy a servlet. for Our Sample, WE Are Working with Midp 2.0, The Motorola Iden i730 SDK, And The Motorola I730 Device.
USING LBS
. First, let's make sure that we understand what an LBS application is Typically, an LBS application is trying to answer the question "Where am I?" And then do something with that information There are a number of ways to answer this question.:
I am on Earth. I'm in the US. I'm in the Rocky Mountains. I'm in Denver, Co. I'm AT 39.7 ° N, 105 ° W.
As you can see, the answer to the question depends on how specific you require your data to be. Being able to determine your current, accurate location can take a few forms. When dealing with a mobile phone, there are also a number of options to determine your location. Typically, some sort of information is available through network operators, using methods that are often made invisible. An example of this is when you travel, and your phone resets its time to the time zone you have entered. All of this is done "under the covers" for you.There are different ways that a phone can determine its location. Using angle of Arrival (AOA) methods, where the angle of the phone to the more than one transmitter is determined, or Time Difference of Arrival (TDOA), where the signal is timed from the handset to the cell transmitters, are just two examples. What we are going to be talking about is Assisted GPS (AGPS) and GPS. In these cases, assistance information is produced by The Cell Network Usin ga simple GPS receiver that is built into the phone handset. This is combined with information from the GPS satellites. What this means is that not only do you need a phone that supports the GPS receiver, but also an AGPS-enabled network. For our development, we've been using the i730 device and the Nextel network, since they provide the service in which we are interested. Using specific location APIs, we are able to access the location information that we need from the device and use it in our GIS Application.
IT IS Helpful To Undrie Going To Look At, Which Is Available At The end of the article. First, we'll Look at The Client Portion. In this case, we are dealing with a cell phone, so we are writing a J2ME MIDLet. The MIDLet allows us to see how the device interacts with the location APIs using canned values. From here, we'll add a little more to the mix and actually do a dynamic location API call. This will show how taking a staged approach is important, so that different parts of the code can be unit-tested in isolation. lastly, we'll look at a simple servlet that will tie the server portion into the picture. Let's start with the MIDLet. The "Where am i?" MIDLET
In general, all MIDLets implement required methods to support certain J2ME life-cycle events. If you'd like to explore all of the methods, you can look at the MIDLet class in the javax.microedition.midlet package. Requests coming into the MIDLet are handled by an inner class, CommandListener, that is set up in the constructor. This MIDLet will tell us what our current lat./long. coordinates are, and then send them to a server using a standard HTTP network connection. Let's take a walk through the MIDLet code. However, keep in mind this is not a MIDP tutorial. While we'll show the complete code, we'll only talk about the parts of interest as they relate to this application. First, let's get our Basic MIDlet set up. Noth We're Just Setting Up Some of Our Local Variables.
Package com.mobilogics.javanet;
Import java.util.vector;
Import java.util.calendar;
Import java.util.date;
Import javax.microedition.lcdui. *;
Import javax.microedition.midlet. *;
Import javax.microedition.io.connector; import javax.microedition.io.httpConnection;
Public Class Whereamimidlet Extends MIDLET
Implements commandListener {
Public Static Final String Not_Set = "Not Set";
Public static final string id = "id:";
Public static final string latitude = "lat:";
Public Static Final String Longitude = "long:";
Public static final string status = "stat:";
Public static string m_surl = not_set;
protected string m_sphoneid = "71";
protected string m_slat = not_set;
protected string m_slong = not_set;
Protected long m_ltimestamp = -1;
Protected string m_sstatus = not_set;
protected string m_sticker = not_set;
Protected string m_saboutmessage = not_set;
protected string m_sabouttitle = not_set;
protected display m_display = null;
protected form m_locationform = null;
protected command m_cmdgetlocationandsubmit;
protected command m_commandexit;
Protected Command M_CommandaBout;
Next We'll Look At Our Constructor:
Public WHEREAMIMIMIDLET () {
m_sabouttitle =
THIS.GetAppproperty ("MIDlet-description")
"
This.GetAppproperty ("MIDlet-Version");
m_surl = this.getAppproperty ("URL");
Here, We are setting our url to be on the localhost (WE HAPPEN to Be Using Tomcat), WHERE The Location Information Will Be Submitted To Our WHEREAMISERVLET.
IF (NULL == m_surl || m_surl.length () == 0) {
m_surl = "http://127.0.0.1:8080/javanet/lbs.do";
}
. Next, we define various screen commands We've intentionally keep this sample simple by just having Submit, Exit, and About commands Typically, you would probably have some type of GUI interaction with the user.m_sAboutMessage = m_sUrl.;
m_cmdgetlocationandsubmit = new command ("Submit",
Command.screen, 0);
m_commandexit = New Command ("exit", command.stop, 3);
m_commandabout = new command ("about", command.ok, 4);
// Location Form //////
// 1) Define Screen Content
Item [] locationItems = new item [3];
LocationItems [0] = New stringItem (ID, m_sphoneid);
LocationItems [1] = new stringItem (latitude, m_slat);
LocationItems [2] = New StringItem (longitude, m_slong);
// 2) construct the displayable object
M_Locationform = New Form ("Summary", LocationItems;
// 3) Add commands
M_Locationform.Addcommand (m_cmdgetlocationandsubmit);
m_locationform.addcommand (m_commandexit);
m_locationform.addcommand (m_commandabout);
The interesting portion of this section is really the CommandListener, which handles the various screen command actions. The command of interest to us is the GetLocationAndSubmit, which is where we are actually getting the location information and then submitting it to the servlet. You'll notice that we are running the location APIs in their own thread. This is required because it could potentially take some time to get a GPS fix, and you do not want the MIDLet to be hanging in the GUI for the user.
// 4) Define and set commandListener
CommandListener CL = New CommandListener () {
Public void CommandAction (Command C,
Displayable d) {
IF (c == m_commandexit) {
DESTROYAPP (TRUE);
NotifyDestroyed ();
}
Else IF (c == m_commandabout) {handleabout (C, D);
Return;
}
ELSE IF (c == m_cmdgetlocationandsubmit) {
// this is a potentially long running
// process and must be run in its oow
// thread. Therefore, WRAP IT IN A
// Thread, Start the Thread and make A
// Quick Return SO this Process Execution
// does not Tie Up The Midlet's Main
// thread.
Thread t = new thread () {
Public void run () {
GetLocationAndSubmit ();
}
}
T.Start ();
}
}
}
M_Locationform.SetCommandListener (CL);
m_display = display.getdisplay (this);
}
The getLocationAndSubmit () method is actually broken down into a couple of sub- methods, for ease of reuse. We give some indication to the user that something is going on by displaying a ticker across the screen, and then both get the location and do The Submit.
Public void getlocationandsubmit () {
m_sticker = "getting location";
System.out.println (m_sticker);
Updateui ();
Thread tgetlocation = new thread () {
Public void run () {
GetLocation ();
}
}
Tgetlocation.start ();
Try {
Tgetlocation.join ();
Alerttype.info.playsound (m_display);
Thread TsubmitLocation = new thread () {
Public void run () {
SubmitLocation ();
}
}
m_sticker = "submitting location";
System.out.println (m_sticker);
Updateui ();
TsubmitLocation.start ();
TsubmitLocation.join ();
Alerttype.info.playsound (m_display);
m_display.setcurrent (m_locationform);
}
Catch (Exception E) {
E.PrintStackTrace ();
}
}
In this first MIDLet, we have implemented the getLocation () method with "dummy" information. This was done intentionally, because we first want to test the MIDLet as a plain vanilla MIDP application, without introducing the various complexities of the location API. After we're done testing our MIDLet and everything is working, we then override this method in the WhereAmIMotorola MIDLet, which will use the Motorola i730 location APIs. We'll look at that code in just a minute.void getLocation () {
// canned Latitude Value for a given location
m_slat = "255515694";
// CANNED Longitude Value for a given location
m_slong = "-428707806";
M_ltimestamp = system.currenttimemillis ();
m_sstatus = "location ok";
M_sticker = "Get Location Status:" m_sstatus;
Updateui ();
}
After We've Got Our Location Information, We can Submit It to the servlet by constructing the appropriate query, and sending it over an http connection.
protected void submitLocation () {
m_sticker = "submitting to server";
Updateui ();
Try {
HttpConnection http = null;
StringBuffer SB = New StringBuffer; M_SURL
sb.append ("?");
sb.append ("id =");
Sb.append (m_sphoneid);
sb.append ("& lat =");
sb.append (m_slat);
sb.append ("& long =");
Sb.append (m_slong);
Sb.append ("& Time =");
sb.append (m_ltimestamp);
System.out.println (sb.toString ());
HTTP = (httpConnection) connector.open (sb.toString ());
Http.setRequestMethod (httpConnection.get);
HTTP.SetRequestProperty ("Connection", "Close");
m_sstatus = http.getResponseMessage ();
Alerttype.info.playsound (m_display);
}
Catch (Exception E) {
M_SSTATUS = "Error Submitting:" E.GetMessage ();
AlertType.error.PlaySound (m_display);
}
M_sticker = "Submit Status:" m_sstatus;
System.out.println (m_sticker);
Updateui ();
}
The various other methods that are contained in the MIDLet implement the MIDP life-cycle events (startApp (), pauseApp (), and destroyApp ()), but are not directly related to the LBS functionality. You can download the sample source files we 'Ve Provided if you want to take a look at them.
You can see in Figure 1 What happens when the midlet is first run.
Figure 2 shows what The location value. Look Like After Weide.
Figure 1. Whereamimidlet in Emulator on Startupfigure 2. Location VALUES AFTER A SUBMIT
Adding in Dynamic Location
Now that we've debugged and tested our WhereAmIMidlet, we are ready to add in the location APIs. Basically, we are just extending the WhereAmIMidlet that we just created and overriding the getLocation () method. The interesting portion is that we are now making calls to the location APIs that are included with the Motorola i730 SDK. Since these APIs are specific to Motorola devices, if you are working with another device you'll need to determine if they supply location APIs in their SDK.
We create a PositionConnection using the Connector (just as we do with the HTTP connection), and then make the position () method call. This will interact with the GPS hardware built into the i730 device. Once we have a fix, we can then access the various pieces of information that we are interested in. in this case, we're simply getting the lat./long. and timestamp information. The updateUI () method is a utility method that you can take a look at in the source Download, if you are interested.package com.mobilogics.javanet;
Import java.util.vector;
Import java.util.calendar;
Import java.util.date;
Import javax.microedition.lcdui. *;
Import javax.microedition.midlet. *;
Import com.motorola.iden.position. *;
Import javax.microedition.io.connector;
Import javax.microedition.io.httpConnection;
Public Class WHEREAMIMOTOROLA
Extends whereamimidlet {
protected void getlocation () {
Try {
PositionConnection PC = NULL;
AggregatePosition AP = NULL;
m_slat = not_set;
m_slong = not_set;
Try {
PC = (positionConnection)
Connector.open ("MPSITION: DELAY = HIGH");
AP = pc.getPosition ();
}
Catch (Exception E) {
m_sstatus = "location error:"
E.getMessage ();
Updateui ();
Return;
}
IF (pc.getstatus ()! =
PositionConnection.Position_RESPONSE_OK &&
ap.getresponsecode ()! =
POSITIONDEVICE.POSITION_OK) {
m_sstatus = "Location Error Code:"
ap.getresponsecode ();
} else {
// Get Units in 1 / 100,000 minute
Irat = ap.getlatitude ();
Il Ilong = ap.getlongITUDE ();
m_slat = "" iv;
m_slong = "" ilong;
M_ltimestamp = ap.gettimestamp ();
m_sstatus = "location ok";
}
}
Catch (Exception E) {
m_sstatus = "location error:"
E.getMessage ();
}
m_sticker = "Get Location Status:"
m_sstatus;
Updateui ();
}
}
WE HAVE OUR MIDLET RUNNING ON OUR I730 Device, Telling US WHERE WEA. NOW What? Let's Take a Peek At What Comes Into The Servlet WHEN We do Our SubmitLocation () Call.
MeanWhile, Back on the Server
As we can see, the MIDLet does the work of getting our current location for us and delivering it to the server. On the server side, we have a simple servlet running that accepts the request and then does something with the information. In a typical application, the servlet would actually be doing a bit more here, such as making a request to a GIS back end. For simplicity's sake, we have the servlet just taking the information and writing it to a text file called latlong.txt. This could Easily Be Stored In a Database or Integrated Into Some Other Business Logic.
The key part of WhereAmIServlet is the doGet () method, which does the work of parsing the incoming query string, writing the request parameters into our OutputStream, and then echoing the information to the response.
Public void doget (httpservletRequest Request,
Httpservletresponse response
Throws servletexception, ioException {
// CGI Query String Will Look Like this:
//? id = 71 & lat = 123456 & long = -123456 & time = 8983719387
System.out.println ("Inside whereAmiservlet.dogether);
String SID, SLAT, SLONG, STIMESTAMP;
SID = Request.getParameter ("ID");
Slat = Request.getParameter ("lat");
Slong = Request.getParameter ("long");
StimeStamp = Request.getParameter ("Time");
StringBuffer SB = New StringBuffer (); sb.append (sID);
Sb.append (",");
sb.append (slat);
Sb.append (",");
Sb.append (slong);
Sb.append (",");
sb.append (stimestamp);
sb.append ("/ r / n");
M_latlongoutputStream.write (sb.toString (). getBytes ());
System.out.println (sb.toString ());
StringBuffer SB2 =
New StringBuffer ("
");sb2.append (sb.toString ());
SB2.Append (" body> html>");
Response.getOutputStream (). Write
sb2.toString (). getBytes ());
}
Note: in part three of this series
................ ..
init-param>
init-param>
init-param>
servlet>
servlet-maping>
web-app>
Wrapping Up Part Two
In this part two, we brought in the LBS portion of an application by writing a simple MIDLet to get location information. We hooked it up to a server portion to demonstrate how the information gets to the server, and then what types of activities can take Place. in part three, We'll Generate A map based on the location information.
Download the Sample Code for this article: gis.zip
SUE SPIELMAN IS PRESIDENT AND SENIOR Consulting Engineer for Switchback Software LLC, Author of a Number of Books, And A Speaker on Various Java Topics Around The Country.
Tom WhiteHill Is The Co-Founder of Mobilogics and Has Been Working with Java Since 1995.