New York
University
Computer
Science Department
Courant
Institute of Mathematical Sciences
Session 6:
MIDP Extensions and MIDlets
Course Title: Application Servers
Course Number: g22.3033-011
Instructor: Jean-Claude Franchitti Session: 6
Application Features |
Characteristics |
Standalone applications |
* Small footprint versions of application logic and local processing: thick, intelligent, client/server or smart client applications. * Applications can run on devices with intermittent network coverage. * Intelligent use of wireless bandwidth. |
Rich user interface |
High and low level UI APIs allow for simple but richer user interfaces (when compared to WML) for mobile business applications and games |
Network aware |
* Support for HTTP/XML and other web standards * Direct device-to-device network communications * Client/Server and distributed applications * Occasionally connected |
Reliable messaging |
Guaranteed message delivery ensures transactions are not lost due to lost of network coverage. |
Local persistence |
Local data store allows for persistence at the device. Key to offline functionality and caching and guaranteed message delivery and better utilization of wireless bandwidth. |
End-to-End security |
Small footprint TLS implementation allows for end-to-end security without translations at the network provider |
Data synchronization |
Synchronize data when/as needed |
Notifications |
Real-time asynchronous notifications |
Multi language support |
Target application to different languages |
Cross platform and low cost of development and ownership |
Develop 'once' deploy to any J2ME device w/ appropriate profile |
Access to corporate servers |
|
HTTP is a text-based stateless request/response protocol with messages with the following format:
HTTP message = start-line
(request or status line) CRLF
message-header(a set of
name&values)CRLF
CRLF (empty line)
Optional message-body
1. To open an HTTP
connection invoke javax.microedition.io.Connector class:
import
javax.microedition.io;
HttpConnection hc;
hc =
(HttpConnection)Connector.open(targetURL);
where targetURL
follows the a standard URL format as defined by RFC 2396:
<SCHEME>:<SCHEME-SPECIFIC-PART>, where <SCHEME>
indicates to the implementation the
type of Connection object that must be created/returned and the
<SCHEME-SPECIFIC-PART> indicates the hostname, port and query-string.
For example:
http://www.j2medeveloper.com:8080/emailController?user=enrique&pwd=8dfje3
datagram://www.j2medeveloper.com:7001
2. To set HTTP
request headers before sending the request use setRequestProperty():
hc.setRequestProperty("User-Agent",
"Profile/MIDP-1.0 Configuration/CLDC-1.0" );
The MIDP specification recommends that User-Agent is set to indicate MIDP/CLDC
as shown above.
3. To retrieve
HTTP response headers use getHeaderField():
String cookie = hc.getHeaderField(
"Set-Cookie" );
4. One
possible way to send an HTTP request:
/*
* Set HTTP request method
to POST.
* It is good practice to
always set:
* Content Length, Type,
Language, Accept.
* Send body
*/
hc.setRequestMethod(HttpConnection.POST);
hc.setRequestProperty
("Content-Length", ""+ messageBody.length()
);
hc.setRequestProperty(
"Content-Type",
"application/x-www-form-urlencoded");
hc.setRequestProperty("Content-Language",
"en-US"); // should be config.
hc.setRequestProperty("Accept",
"text/xml");
hc.setRequestProperty("Connection",
"close");
os = hc.openOutputStream();
os.write(messageBody.getBytes());
5. One
possible way to receive an HTTP response:
InputStream is = hc.openInputStream(); // get response
int len = (int)
hc.getLength();
StringBuffer receivebuffer =
new StringBuffer();
if( len != -1) {
// Read exactly Content-Length bytes
for(int i = 0; i < len; i++) {
if((ch = is.read()) != -1) {
receivebuffer.append((char) ch);
}
}
}
else {
//Read until the connection is closed.
while ((ch = is.read()) != -1) {
len = is.available() ;
receivebuffer.append((char)ch);
}
}
response =
receivebuffer.toString();
III. Leveraging XML on the MIDP (see http://www.ericgiguere.com/microjava/cldc_xml.html)
Leveraging XML for data exchange allows for easy
integration with existing systems. There are a number of small, open source XML
parsers available to us including NanoXML, kXML and TinyXML.
The NanoXML (http://nanoxml.sourceforge.net/) and
TinyXML http://www.gibaradunn.srac.org/tiny/index.shtml
are both natively tree-based parsers while kXML (http://kxml.enhydra.org/) is a more
sophisticated pull/event-based parser.
kXML is much larger than NanoXML and TinyXML.
All these parsers are becoming more complete over
time with features such as DTD validation and Java interfaces for both tree and
event-based parsing; of course all these goodies come at a price: memory
footprint.
As a side-note, kSOAP, a small implementation of
SOAP for J2ME is written on top of kXML, meaning that if you are targeting SOAP
you should consider using kXML instead. From the licensing perspective, the
NanoXML licensing is the less restrictive one. Please refer to the individual
web-sites for more information.
The following is a snippet of code that uses the
NanoXML:
EmailMessage em = null;
kXMLElement parser = new
kXMLElement();
parser.parseString(xml); //
xml is an input String
Enumeration children =
parser.enumerateChildren();
// For each element, get tag
and contents
while
(children.hasMoreElements()) {
// allocate an email message object
em = new EmailMessage();
kXMLElement child = (kXMLElement)(children.nextElement());
String tag =
child.getTagName();
String contents = child.getContents();
...... // other code
if ("msgid".equals(tag)) {
em.setId(contents); // get contents Into object
}
...... // test for other tags and retrieve the content
}
if (em != null) return em;
IV. Local
data persistence
The MIDP defines javax.microedition.io.rms for local
data persistence. RMS stands for Record Management System, a simple record
store that allows MIDlets to store records that that persists across MIDlet
executions.
RMS records are stored as array of bytes. Developers
can use java.io.DataInputStream, DataOutputStream to read/write primitive
types and ByteArrayInputStream and ByteArrayOutputStream to manipulate RMS record
streams.
The following is a snippet of code that opens a
record store and reads three fields:
import
javax.microedition.rms.*
recordStore =
RecordStore.openRecordStore("userDB", true);
..... // other code
// create Input streams
ByteArrayInputStream bais =
new
ByteArrayInputStream(recordStore.getRecord(id));
DataInputStream inputStream
= new DataInputStream(bais);
// read Individual fields as
appropriate
String name =
inputStream.readUTF();
String text =
inputStream.readUTF();
String int =
inputStream.readInt();
The RMS also provides the means to list, delete,
enumerate, and filter (sort) records and to keep track (get notified) of
changes to the record store.
V.
Deploying a MIDlet
MIDlets are distributed using standard JAR files as
per the documentation at http://java.sun.com/docs/books/tutorial/jar/basics/index.html.
In addition to the JAR file, a new file called the
Java Application Description File or JAD is used to describe the JAR file.
Knowing the characteristics of the JAR file before download is important
because the JAR might be to big to fit on the device or you do not want to
download huge JAR files over the air (OTA) or there might be some security
concerns. Lets look at an example of a JAD file:
GatewayPort: 80
GatewayURL: www.j2medeveloper.com
MIDlet-1: Email,,
com.j2medeveloper.email.Email
MIDlet-Jar-Size: 34435
MIDlet-Jar-URL: email.jar
MIDlet-Name: Email
MIDlet-Vendor:
J2MEDEVELOPER.COM
MIDlet-Version: 1.0
UserEmail:
xyz@j2medeveloper.com
UserName: xyz
Also, you can use the JAD to store any configuration
information you need (for example web-server or a user name or an email
address). Use the method javax.microedition.midlet.getAppProperties() to access properties or
configuration information stored in JAD (vs. hard coding any values on your
code).
Building
and Running your MIDlet
How to build and run your MIDlet will all depend on the Java environment that you are using. You should consult your IDE or development environment documentation as needed.
You can package more than one MIDlet within a JAR file into what is call a MIDlet suite. Once you have created the JAD file, you must also create a MANIFEST file for your JAR file. The MANIFEST looks very similar to the JAD file, for example:
MIDlet-1: Email,,
com.j2medeveloper.email.Email
MIDlet-Name: Email
MIDlet-Vendor: XYZ
MIDlet-Version: 1.0
MicroEdition-Configuration:
CLDC-1.0
MicroEdition-Profile:
MIDP-1.0
To build and run under the J2ME Wireless toolkit (J2MEWTK) from Sun Microsystems, you need to be aware of the directory structure used by the J2MEWTK. That structure contains two important directories for the following classes:
1) tmpclasses, containing compiled classes that have not being verified
2) 2) classes which contains the pre-verified classes.
Building
steps are as follows:
1. Compile - use javac tool
but override J2SE classes to use MIDP ones
set MIDP_HOME=c:\midp
javac -g:none -bootclasspath
%MIDP_HOME%\classes -d tmpclasses src\*.java
2. Preverify
preverify -d classes
-classpath %MIDP_HOME%\classes tmpclasses
3. Create JAR file
jar cfm
bin\myMidletSuite.jar bin\manifest.mf -C res . -C classes .
4. Running your MIDlet suite
emulator.exe -Xdescriptor:
myMidletSuite.jad -classpath myMidletSuite.jar
-OR-
midp -classpath bin\
myMidletSuite.jar -descriptor bin\ myMidletSuite.jad