For location-based services, the open frameworks of J2ME and J2EE create
interesting opportunities in the fields of software development and applied
statistics. Traditionally, the software industry in these services has been
closed and, as a result, the industry has suffered stagnation, particularly
in the area of distributed systems and integration.
Just look at this most recent example – U.S. cell phone carriers didn’t
meet the FCC October 2001 mandate for automatic location-based tracking for
911 calls over their networks. The most common reasons the carriers gave
for missing the deadline were high costs and an inability to install the
network infrastructure. With J2ME, XML, J2EE, and GPS, you can use the existing
infrastructure (the Internet and your computer) to build and run such services
from your garage, all for a very low cost (free).
With Java’s open architecture, you can build more exciting applications.
GPS data contains the altitude and speed of a target, allowing the extraction
of 3D information and vector coordinates. This can lead to interesting implementations,
such as topographic position tracking of multiple targets or predicting the
time two targets will intersect.
The use of wireless GPS and J2ME also allows more accurate tracking
of targets because the historical GPS data can be stored in a database, enabling
the integration of stochastic models and applications to monitor, predict,
and correct movements before sending this information to a mobile device.
Because of the limited graphical capability of mobile devices, there’s also
a need for applications to convey location-based information through the
use of colors, a feature of the more recent mobile devices.
The GPS application covered in this article tracks the user on a graphical
plot and gives the distance of another target connected to the network. The
target can also track the user. By going through the application, you can
build a foundation to develop your own GPS services. We’ll discuss how to
set up the test environment and show how to parse and handle GPS data on
a mobile device and transfer GPS information back and forth between the device
and a J2EE server. Thus, by integrating J2EE and J2ME, the mobile device
harnesses the power of the server, allowing the development of intelligent,
location-based applications.
Setting Up the Test Environment
Setting Up a GPS Receiver
A GPS receiver must meet two requirements for the application to work.
First, it should be able to output NMEA 0183 (version 2.0 or higher) data
as text; second, it shouldn’t require the receipt of an initialization string
before sending data. eTrex from Garmin meets both requirements. Since the
receiver hooks into the serial port on a PC (desktop or laptop), you need
to obtain a GPS-to-serial-port adapter. Once connected, GPS data will flow
through the communication port. Keep in mind that most GPS receivers don’t
work indoors, so place the PC near a window where the receiver has clear
access to the open sky. The receiver will need to get signals from at least
three satellites to determine its position.
For those who don’t wish to go through the trouble and expense of dealing
with a GPS receiver, the source code for this article includes a Java class
file (HttpReader) that functions as a GPS data stream. (Listings 1–3 and
the source code for this article can be downloaded from below.) This class instance reads an HTML page that contains actual GPS data and
returns its input stream. While this method is easier than using a GPS receiver,
watching a plot of the author driving to his local grocery store is not nearly
as much fun.
HTTP Connection
Since MIDP requires the implementation of a subset of HTTP 1.1, this protocol
should work for all implementations of J2ME. Therefore the application uses
HTTP to communicate with the server.
The server may reside on the local machine or on a LAN. For the server
to be accessible over the Web, you need a wired or wireless Internet connection.
However, a wireless connection provides the most usability for testing in
a real production environment. This may be set up in a number of ways. A
mobile phone with Internet access can hook up through a connector to a port
on the laptop. Obtaining a wireless modem or doing a direct dial-up to a
server hosting the server-side GPS application are other options.
Software Requirements
The GPS application requires the J2ME Wireless Toolkit from Sun and JDK
1.3 or higher. You also need the kXML package from Enhydra to handle XML
on the MIDP device, as well as the xspsoft class files that are included
in the download.
For the server-side applications, this article uses JBoss/Tomcat J2EE,
which can be freely downloaded from www.jboss.org. Of course, you
can also use any commercial J2EE implementation. You also need JAXB and JDK
1.4 from Sun.
The server application allows the user to transmit the GPS coordinates
and to retrieve other people’s coordinates. If the you don’t wish to bother
with EJBs and don’t care about tracking multiple targets, the server-side
application can be eliminated without affecting the core GPS functionality
on the MIDP device or emulator. (The application could also be rewritten
using JSP and JDBC.)
NMEA Format
In the 1980s the National Marine Electronics Association (NMEA) developed
the NMEA 0183 Interface Standard for data exchange between marine electronic
devices. Today, most global positioning systems use the NMEA interface for
data exchange. Thus the J2ME GPS data parser will work on any GPS receiver
that implements this standard. Figure 1 contains a sample of a data stream:
Figure 1:
The $GPGGA sentence contains the target’s topological location information.
The relevant fields are as follows:
Field
1 Message Header ($GPGGA)
3 - 4 Latitude, North/South
5 - 6 Longitude, East/West
10 Altitude in meters
The latitude 3753.667 denotes 37 degrees, 53 minutes, and 66.7 seconds.
There are a couple of problems with this format. First, the longitude and
latitude numbers are not base 10 numbers, so it’s difficult for an application
to determine relative distances. Second, the KVM does not support floating
or double primitive types nor the respective wrappers, making any decimal
value an incorrect numerical format.
The answer is to use fixed-point integer calculations to handle decimal
values. For example, the value of 100.234 is 100234, with a fixed point of
three. The GpsParserImpl class instance normalizes the longitude and latitude
coordinates by using the following code:
int nc = (10000 * k[0]) + (10000 * k[1])/60 +
(1000 * k[2])/3600;
where k[0] denotes the degrees (37), k[1] the minutes (53), and k[2]
the seconds (667). The normalized integer value for this latitude is 379019.
To find the speed and direction of the target, we extract information
from $GPRMC (fields 8 and 9, respectively). If the altitude field is blank,
it means the GPS receiver isn’t able to pick up the signal from a fourth
satellite, which is necessary for 3D tracking.
In this scenario the target is not moving, so the speed and direction
fields contain 0.0. The J2ME application developer may use this information
in interesting ways. For instance, you could display all targets moving over
60 m.p.h. in dark blue, or all targets moving north in green. This type of
color-coding and dimensional reduction of information allows an enormous
amount of location information to be displayed to the user of a limited mobile
device. This will undoubtedly be an important area of future growth, research,
and standardization for the mobile industry.
Accessing GPS Data Through the Serial Port
Opening the InputStream
Plugging the GPS receiver into the laptop or mobile device starts a
stream of GPS data flowing over the serial port. Reading the input stream
from the serial port is no different than reading an input stream from a
file or an HTTP connection. As mentioned previously, you can use either HttpReader,
which functions as a GPS data stream, or SerialReader to open a connection
to an actual GPS receiver. Here’s the only difference in the code:
• SerialReader:
String URI = "comm:1;baudrate=4800;bitsper char=8";
InputConnection inputCon = (InputConnection) Connector.open(URI);
InputStream is = inputCon.openInputStream();
• HttpReader:
String URI = "http://xspsoft:8080/GPS.html";
HttpConnection inputCon = (HttpConnection) Connector.open(URI);
InputStream is = inputCon.openInputStream();
Note that a SerialReader object opens a connection to the stream on
communication port 1; however, your port number may be different. If you
choose the wrong port, the KVM will throw an IOException stating that the
system can’t find the specified file. If the port is occupied, the IOException
states that the handle is invalid.
Each GPS receiver sends data at a certain baud rate. Ensure that the
baud rate in the String URI matches the baud rate of your GPS receiver. If
any of the bytes in the input stream are above 128, the baud rate is incorrect.
The input stream will come through as garbage. Also make sure there are no
spaces between the semicolons or the program will throw an exception.
Parsing the InputStream
The abstract class GpsParser contains the base code to read the GPS
data stream. A concrete, direct subclass instance instantiates either the
SerialReader or HttpReader, depending on the user’s preference. GpsParser
returns an NMEA sentence as a character array, one line at a time, through
the use of the Template Method and an abstract method denoted as com-mand(char[]
c).
The GpsParserImpl class contains an example of a concrete implementation
of the command instance method, which is executed for each NMEA sentence
flowing through the serial port. In the GpsParserImpl class, the match-
Command class method determines whether the current NMEA sentence is the
GPGGA sentence. If it is, the command method scans and tokenizes the data
into a vector.
Invoking the GpsParserImpl constructor causes the GPS data stream to
continually update the Coordinate class with the respective longitude and
latitude information. Now any application can invoke the Coordinate accessor
class methods – getLatitude, getLongitude, getAltitude, getSpeed, and getDirection
– to get the most current position of the target.
Data Access Objects and the Transporting of Information
In this article various data sources, including a relational database,
XML files, MIDP record stores, and GPS data streams, are coming over a serial
port. Dealing with so many data sources can be overwhelming without a systematic
design and structure of the application services. Using data access objects
(DAOs) to access these data sources is a good design practice that will simplify
the application. One example we’ve already discussed is the coordinate data
access object (actually a class) that returns the most current location information
of the target.
This application has three primary data access objects on the MIDP device
that can marshal and unmarshal XML: SerialDataObject, EntityDataObject, and
RecordDataObjectImpl. The SerialDataObject handles the unidirectional transfer
of information from the serial port (through Coordinate DAO) to the server
database. The EntityDataObject handles the unidirectional transfer from the
database to class methods of CoordinateTarget on the MIDP device. The RecordDataObjectImpl
handles the bidirectional transfer of information between the server database
and the MIDP record store. While transferring data to the record store may
be slow, it is, however, a vital component to building enterprise applications
involving an MIDP device.
These data objects can be returned by invoking the getDataObject (String
DAO) class method of the factory DataObjectFactory. IGps is a superinterface
of all these classes, so these class instances are assured of having accessor
instance methods for the GPS data. The SessionMinibean object will take care
of the marshaling and unmarshaling as well as choosing the correct data access
object. For example, to transfer GPS data from the serial port to the server
database merely requires the following lines of code:
SessionMinibean smb = new SessionMinibean("SERIAL");
smb.marshal();
The database server will now contain the user’s longitude, latitude,
altitude, speed, and direction. Another user, with the following lines of
code, can retrieve this user’s latitude:
SessionMinibean smb = new
SessionMinibean("ENTITY");
smb.unmarshal();
int latitude =
CoordinateTarget.
getLatitude();
Note that the unmarshal method unmarshals the XML message and populates
the class methods of Coord-
inateTarget, so any application has access to the target’s location through
CoordinateTarget. Class methods are extremely useful for J2ME applications
because of the expense of packing, unpacking, and searching for information
within the persistent record store.
If you’d like a local record store copy of the data from the database
server, use the following lines of code:
SessionMinibean smb = new
SessionMinibean("RECORD");
smb.unmarshal();
You could also invoke the marshal method and update a database on the
server.
In short, we have the basis for wireless hot sync capability between
the record store on the mobile device and the database server. Thus the user
could set his or her GPS and target tracking preferences, upload the information
to the database, and then hot sync from any other mobile device. Hot synchronization
could also allow multiple people to synchronize their tracking of a single
target or group of targets. Although the record store is not used in this
article, the functionality exists within the GPS application download.
A Brief Digression on the MIDP Record Store
The J2ME services on the mobile device access persistent data through
the Record Management System (RMS) API. In this example, we avoid the overhead
of RMS by accessing location-based information through the use of accessor
class methods. However, record store access is critical to any enterprise
production application. We’ll briefly cover some of the basics.
In the mainframe era space was at a premium, so the flat file was packed
in binary and other formats. As a result, programmers built data-access components
that packed and unpacked flat files. The same design principle applies to
the somewhat more limited mobile devices that use byte records in a flat-file
RMS.
The application needs packing and unpacking functionality to store the
GPS byte information in a record store. The packBytes instance method in
the RecordDataObjectImpl (see Listing 1) writes the values from the getter
methods into a DataOutputStream and then converts the stream to a byte array.
The setRecord instance method invokes the packBytes method and adds the bytes
to the record store.
One issue with the MIDP record store is which record to pack and unpack.
In container-managed persistence, the container automatically generates a
findByPrimaryKey instance method for the EJB, which returns the object given
by the primary key. The GPS application’s DAO on the mobile device includes
a similar instance method denoted as setPrimaryKey. This is an important
method because accessing the data by the record ID creates program-data dependence
on the storage structure, resulting in a poor design of the record store.
The trick to locating records by the primary key, rather than key index,
is to implement the data access object (RecordDataObjectImpl) as a RecordFilter.
This allows the use of a RecordEnumeration on the current object to unpack
the record bytes for the record that contains the primary key. By invoking
the setPrimaryKey method, a RecordEnumeration returns those records (only
one) that are true for the match method (see Listing 2). It then unpacks
the correct record, giving access to the record information through the accessor
methods. This process is invisible to the business object that instantiates
RecordDataObjectImpl.
It’s a lot of work to look up and access data from a record store. However,
notice that the use of the data access object is almost identical to the
CMP entity bean in this GPS application. In a sense, the application uses
a MiniEJB entity bean on the mobile device. For example, consider the code
fragments in Listing 3. For both the MIDP and EJB code, we create a RecordDataObject
and set the primary key to an integer that contains the value of 3. In both
cases we invoke the accessor methods. The only difference is that in MIDP
we must invoke setRecord, which is primarily needed for efficiency.
Note that in both cases the business object doesn’t need to know the
record ID on which it is operating. By using a similar design for the MIDP
and EJB process, the code is considerably reduced in the business object
layer.
• MIDP
com.xspsoft.j2me.db.GpsDataObject gdo = new GpsDataObject();
gdo.setPrimaryKey(new Integer(3));
gdo.setId(new Integer(10));
gdo.setName("Mr. X");
gdo.setRecord();
• EJB
com.xspsoft.gps.bean.GpsDataObject gdo = new GpsDataObject();
gdo.getEntityBeanByKey(new Integer(3));
gdo.setId(new Integer(10));
gdo.setName("Mr. X");
XML and Data Binding in J2ME
It’s worth looking into how the SessionMinibean marshals and unmarshals
XML data for the transfer of tabular information. Note that the following
method for dealing with XML will also be useful for the serialization of
Java objects. The lack of MIDP support for RMI will make XML (and SOAP) a
critical component for enterprise applications involving J2ME. Therefore,
it’s a good idea for the J2ME developer to become proficient in using and
manipulating XML.
The SessionMinibean class instance handles the transfer of GPS information
between one of the data objects returned by DataObjectFactory and the RootXml
and ClientXml objects, which are discussed later. First, we’ll demonstrate
how the kXML package from Enhydra can read and write XML from the mobile
device to a servlet. To write the <client myName="Mr. X" myLatitude="320854"/>
tag to the SOAP servlet requires the following lines of code:
String URI = "http://xspsoft:
8080/xspsoft/SOAP";
HttpConnection ic =
(HttpConnection) Connector.open(URI);
OutputStream os =
ic.openOutputStream();
OutputStreamWriter
writer = new
OutputStream-
Writer(os);
org.kxml.io.XmlWriter w =
new XmlWriter(
(Writer) writer);
w.startTag("client");
w.attribute("myName",
"Mr. X");
w.attribute("myLatitude",
"320854");
w.endTag();
ic.close();
The XmlWriter instance requires a Writer parameter, which can be obtained
by wrapping the OutputStream with an OutputStreamWriter. Now, writing to
the XmlWriter instance will write directly to the servlet.
Reading from the SOAP servlet is very similar. Consider the following
code:
InputStream is = ic.openInputStream();
InputStreamReader reader = new InputStreamReader(is);
XmlReader xr = new XmlReader(reader);
String myName = xr.getValue("myName");
String myLatitude = xr.getValue("myLatitude");
ic.close();
Two classes, ClientXml and RootXml, handle the primary work of marshaling
and unmarshaling the data. ClientXml has accessor instance methods to set
and get GPS information for the class instance. Consider the marshal method
from the ClientXml class:
public void marshal(XmlWriter writer) throws Exception {
XmlWriter w = writer;
w.startTag("client");
w.attribute("id", this.getId().toString());
w.attribute("name", this.name);
w.attribute("latitude", this.getLatitude().toString());
w.attribute("longitude", this.getLongitude().toString());
w.attribute("altitude", this.getAltitude().toString());
w.attribute("speed", this.getSpeed().toString());
w.attribute("direction", this.getDirection().toString());
w.endTag();
}
To write an XML document to the servlet, use the following code:
ClientXml cx = new ClientXml();
cx.setName("Mr. X");
cx.setLatitude(new Integer(327890));
<<more set methods>>
cx.setDirection(new Integer(11));
cx.marshal(anXmlWriter);
The output looks like:
<client name="Mr. X" latitude="327890" ….direction="11"/>
The application can marshal any data access object that implements the
IGps interface, which is a two-step process. First, invoke the set methods
of a ClientXml instance, passing the return values from the DAO get methods
as parameters. Second, invoke the ClientXml marshaling method. The unmarshal
instance method is similar and can be viewed in the downloaded code. The
purpose of the RootXml class instance is to enumerate through a vector of
ClientXml objects, invoking its marshal or unmarshal method. In this specific
case the application automatically writes (or reads) a complete XML document
that contains multiple rows of clients and their respective locations.
The general case is more interesting. We now have a powerful technique:
any object with accessor methods can marshal and unmarshal XML data without
ever directly parsing XML data.
Plotting Target Location
MainDriver is the core class that runs the MIDlet application. This
section gives a brief overview of the process and shows how all the previous
programs fit together. The application starts with the following lines of
code:
public void startApp() throws MIDletStateChangeException
{
new GpsParserImpl();
GpsPlot gp = new GpsPlot();
display.setCurrent(gp);
}
Invoking the GpsParserImpl constructor begins a thread that starts updating
the Coordinate class accessor methods from the GPS receiver. Next we begin
another thread by instantiating the GpsPlot inner class. In its constructor,
this GpsPlot object starts a TimerTask thread called MiniServlet:
public class MiniServlet extends TimerTask {
public MiniServlet() {
Timer t = new Timer();
t.scheduleAtFixedRate(this, 1000, 10000);
}
public void run() {
SessionMinibean serial = new SessionMinibean("SERIAL");
serial.marshal();
SessionMinibean entity = new SessionMinibean("ENTITY");
entity.unmarshal();
}
MiniServlet schedules its run method to invoke every 10,000 milliseconds.
The run method marshals XML data from the Coordinate class to the servlet
by invoking serial.marshal(). The servlet then updates the database on the
server through the use of JAXB and container-managed persistence.
The run method from MiniServlet then invokes entity.marshal(). This
unmarshals XML data from the server database (through the same servlet),
updating the CoordinateTarget class accessor methods. In short, we’ve passed
our coordinates to the server database and retrieved the target’s coordinates.
The target is going through the same process, passing its information to
the server and retrieving our GPS information.
The GpsPlot object run method stays alive indefinitely with the following
code:
while (true) {
try { Thread.sleep
(100);
repaint();
}
catch
(Exception e){}
}
The repaint method invokes the drawMan method, given below:
1. private void drawMan(Graphics g) {
2. int lt = Coordinate.getLatitude() - CENTER_Y + CENTER_SCREEN;
3. int ln = Coordinate.getLongitude() - CENTER_X + CENTER_SCREEN;
4. int speed = Coordinate.getSpeed();
6. g.fillRect(ln - 2, lt - 4, 4, 4);
7. g.fillRect(ln - 3, lt - 8, 6, 4);
8. g.fillRect(ln - 2, lt - 9, 4, 1);
9. g.fillRect(ln - 1, lt - 10, 2, 1);
10. g.fillRect(ln - 2, lt - 11, 4, 1);
11. g.fillRect(ln - 1, lt - 12, 2, 1);
12. g.fillRect(ln, lt, 2, 2);
14. int deltaLat=Coordinate.getLatitude()- CoordinateTarget.getLatitude();
15. int deltaLong=Coordinate.getLongitude()- CordinateTarget.getLongitude();
16. int distance=com.xspsoft.j2me.util.Math.dist(deltaLat,deltaLong);
18. g.drawString(new String("Speed:"+speed),5,76,Graphics.TOP|Graphics.LEFT);
19. g.drawString(new String("Target Dist: " + distance), 5, 86, 16|4);
20. }
Before the plot is started, the program finds the first latitude and
assigns the value to CENTER_Y and the value of the first longitude to CENTER_X.
The center of the screen is coordinate pair (50, 50), although this will
change depending on the device. On line 2, we calculate the latitude position
by invoking the getLatitude method to find the current latitude. Next we
subtract the initial latitude. This gives us the latitude movement, centered
at zero. We add 50 to center the plot to the middle of the screen. A similar
calculation is used for longitude. The fillRect methods plot the pixels that
represent a man-shaped figure. As we move, the figure will move from the
center coordinate.
We’d also like to display our current speed (lines 4 and 18) and the
distance to another target (lines 14–16, 19). Since distance measurements
involve square roots, a function not directly supported by the KVM, the download
contains a Math class file that handles the distance calculations.
Conclusion
J2ME, J2EE, and XML are helping to end the age of mundane location-based
services in the commercial area. The primary advantage is that these technologies
open up the location-based services to a larger, more talented pool of developers.
Gone are the days when we used our GPS system to ask, “Where is the BurgerBoy
exit?” Instead, parents will be tracking their child online or you’ll be
locating that elusive friend. As a consequence, your elusive friend will
be putting a security perimeter around himself to detect other targets so
he can remain elusive.
This article demonstrates a simple application using everyday technologies
that allows a user to determine his or her distance from a moving object.
Its potential is limitless.
Author Bio
Shane Isbell is a founder and lead developer at xspsoft, which specializes in developng wireless, location-based software for the security
industry.
random7@worldnet.att.net
Download Source Files (~ 48.8 KB ~Zip File Format)