J2ME programming best practices - Intranet development
Abstract: In order to the different types of mobile phones transplantation, we have to use HTTP as the preferred network connection agreement so that the server can reuse code.
As wireless devices to support the network protocol is very limited, limited to HTTP, Socket, UDP, etc. Several agreements, different manufacturers may also support other network protocols, but MIDP 1.0 specification, the HTTP protocol is essential to achieve agreement, the realization of other agreements are optional. Therefore, in order to the different types of mobile phones transplantation, we have to use HTTP as the preferred network connection agreement so that the server can reuse code. However, because HTTP is a less efficient text-based agreement, therefore, must be carefully considered and mobile communications server side, as far as possible to improve efficiency.
For MIDP applications, it should be possible to:
1. Send request, the surcharge a User-Agent head, and into their own version of MIDP to the server can identify this request from the MIDP applications, and in accordance with the corresponding versions of the corresponding sent.
2. Connects to the server, show the progress of a download that allows users to download progress can be discontinued at any time and connect.
3. As a wireless network connection speed is still slow, it is therefore necessary to cache some data, and can be stored in memory, can be put in RMS.
The server, its output response should be to accomplish the following:
1. Clear set Content-Length field, in order to MIDP applications to read and judge their own HTTP header has the ability to deal with the length of the data, if not, can be directly connected without having to shut down HTTP continue to read the text.
2. Server should not send HTML content, because it is very difficult analytic applications MIDP HTML, XML While the analytical, but consuming CPU and memory resources and, therefore, should be sent compact binary content with DataOutputStream write directly and set the Content-Type application / octet-stream.
3. Advised not to redirect URL, it will lead to MIDP applications once again connects to the server, increasing the waiting time for users and network traffic.
4. Event of anomalies, such as the request for resources not found, or authentication failure, usually, the server will send a browser to display error pages, and may also include a user login Form, but sent the wrong page to the MIDP face no sense, it should be sent directly 404 or a 401 error, so MIDP application can directly read the first response HTTP error code access to information without having to read the corresponding content.
5. Due to server computing power far exceeded the phone client, therefore, for different clients different version sent in response to the mandate of the server-side should be completed. For example, according to the client transmission User-Agent client version of the first set. In this way, low version of the client upgrade can not continue to use it.
MIDP networking framework agreement defines a variety of network connections, but each vendor must realize HTTP connections, in the MIDP 2.0 has also increased the need for the HTTPS connections. Therefore, in order to guarantee MIDP applications from different vendors in the mobile phone platform transplant, the best use only HTTP connection. While HTTP is a less efficient text-based agreement, but due to extensive use of special, most of the front-end server applications are HTTP-based Web pages, so they can maximize reuse the server-side code. So long as good cache control, there are still a good speed.
SUN of the MIDP provides javax.microediton.io package, to be very easy to achieve HTTP connection. However, we should pay attention to, because a lot of network delay, the network must operate Add to a separate thread, in order to avoid blocking the main thread to stop response to the user interface. In fact, the MIDP runtime environment is the main thread is not allowed to operate a network connection. Therefore, we must achieve a flexible HTTP networking module, a very intuitive and allows users to upload and download to see the current progress, and can cancel at any time connectivity.
A complete HTTP connections: Users connecting through a command initiated the request, and then wait for the system is given a screen is connected, and when connected to normal after the end to advance to the next screen and deal with a download data. If it is unusual process, and suggested that users will return to the previous screen. Users waiting for the process to cancel at any time and return to the previous screen.
We designed a thread of HttpThread responsible for connecting servers in the background, HttpListener interface Observer (observers) mode, observers suggested that in order to HttpThread can download, the download is completed, updating the progress of such. HttpListener interface as follows:
(Public interface HttpListener
Void onSetSize (int size);
Void onFinish (byte [] data, int size);
Void onProgress (int percent);
Void onError (int code, String message);
)
Implementation HttpListener is inherited from the interface of a Form HttpWaitUI screen, it displays a progress bar and some messages, and allows users to connect interrupted:
Public class HttpWaitUI extends Form implements CommandListener, HttpListener (
Private Gauge gauge;
Private Command cancel;
Private HttpThread downloader;
Private Displayable displayable;
Public HttpWaitUI (String url, Displayable displayable) (
Super ( "Connecting");
This.gauge = new Gauge ( "Progress", false, 100, 0);
This.cancel = new Command ( "Cancel" Command.CANCEL, 0);
Append (gauge);
AddCommand (cancel);
SetCommandListener (this);
Downloader = new HttpThread (url, this);
Downloader.start ();
)
Public void commandAction (Command c, Displayable d) (
If (c == cancel) (
Downloader.cancel ();
ControllerMIDlet.goBack ();
)
)
Public void onFinish (byte buffer [], int size) ()…
Public void onError (int code, String message) ()…
Public void onProgress (int percent) ()…
Public void onSetSize (int size) ()…
)
Http HttpThread is responsible for dealing with the thread of connectivity, and its acceptance of a HttpListener URL:
(Class HttpThread extends Thread
Private static final int MAX_LENGTH = 20 * 1024; / / 20K
Private boolean cancel = false;
Private String url;
Private byte buffer [] = null;
Private HttpListener listener;
Public HttpThread (String url, HttpListener listener) (
This.url = url;
This.listener = listener;
)
Public void cancel () (cancel = true;)
)
GET used to access content
We first discuss the most simple GET request. GET request to the server only sends a URL, and then the server in response to be. HttpThread in the run () method to achieve the following:
Public void run () (
HttpConnection hc = null;
InputStream input = null;
Try (
Hc = (HttpConnection) Connector.open (url);
Hc.setRequestMethod (HttpConnection.GET); / / default shall GET
Hc.setRequestProperty ( "User-Agent" USER_AGENT);
/ / Get response code:
Int code = hc.getResponseCode ();
If (code! = HttpConnection.HTTP_OK) (
Listener.onError (code, hc.getResponseMessage ());
Return;
)
/ / Get size:
Int size = (int) hc.getLength (); / / Response size, or -1 if the size can not be determined
Listener.onSetSize (size);
/ / Start Reading response:
Hc.openInputStream input = ();
Int percent = 0; / / percentage
Int tmp_percent = 0;
Int index = 0; / / buffer index
Int reads; / / each byte
If (size! = (-1))
Buffer = new byte [size]; / / size of the known response to determine Buffer Size
Else
Buffer = new byte [MAX_LENGTH]; / / Response unknown size, setting a fixed size buffer zone
While (! Cancel) (
Int len = buffer.length - index;
Len = len> 128? 128: len;
Reads = input.read (buffer, the index, len);
If (reads <= 0)
Break;
+ = Index reads;
If (size> 0) (/ / update progress
Tmp_percent index = 100 * / size;
If (tmp_percent! = Percent) (
= Tmp_percent percent;
Listener.onProgress (percent);
)
)
)
If (! & Input.available cancel ()> 0) / / buffer is full, unable to read
Listener.onError (601, "Buffer overflow.");
If (! Cancel) (
If (size! = (-1) & & Index! = Size)
Listener.onError (102, "Content-Length does not match.");
Else
Listener.onFinish (buffer, the index);
)
)
Catch (IOException ioe) (
Listener.onError (101, "IOException:" + ioe.getMessage ());
)
Finally (/ / liquidation resources
If (input! = Null)
Try (input.close ();) catch (IOException ioe) ()
If (hc! = Null)
Try (hc.close ();) catch (IOException ioe) ()
)
)
When the download is complete, HttpWaitUI acquired data from the server, to convey to the next screen processing, HttpWaitUI must include the application of this screen and through a setData (DataInputStream input) allows a screen to be very easy to read data. Therefore, the definition of a DataHandler Interface:
(Public interface DataHandler
Void setData (DataInputStream input) throws IOException;
)
HttpWaitUI HttpThread response to the incident and call onFinish a screen setData data transfer method to it and display the next screen:
Public void onFinish (byte buffer [], int size) (
Byte [] data = buffer;
If (size! = Buffer.length) (
Data = new byte [size];
System.arraycopy (data, 0, buffer, 0, size);
)
DataInputStream input = null;
Try (
Input = new DataInputStream (new ByteArrayInputStream (data));
If (displayable instanceof DataHandler)
((DataHandler) displayable). SetData (input);
Else
System.err.println ( "[WARNING] Displayable object cannot handle data.");
ControllerMIDlet.replace (displayable);
)
Catch (IOException ioe) ()…
)
To download a news example, a complete HTTP GET request process is as follows:
First, the user by clicking on a screen that the order of a designated reading news, in commandAction incident, we initialize and display data HttpWaitUI NewsUI screen:
Public void commandAction (Command c, Displayable d) (
HttpWaitUI wait = new HttpWaitUI ( "http://192.168.0.1/news.do?id=1" new NewsUI ());
ControllerMIDlet.forward (wait);
)
NewsUI achieve DataHandler interface and is responsible for downloaded data showed:
Public class NewsUI extends Form implements DataHandler (
Public void setData (DataInputStream input) throws IOException (
String title = input.readUTF ();
Date date = new Date (input.readLong ());
String text = input.readUTF ();
Append (new StringItem ( "Title", title));
Append (new StringItem ( "Date" date.toString ()));
Append (text);
)
)
As long as the server-side String, long, String into the order DataOutputStream, MIDP client can be achieved through DataInputStream followed by the corresponding data, and does not require any analysis of the text, such as XML, a very efficient and convenient.
Data networking needs only achieve DataHandler screen interface to the introduction of a URL HttpWaitUI can reuse the code, without being concerned about how to connect to the network and how to deal with user disconnects.
Send data using POST
POST to send data to the server to send a large number of client data, it does not limit the URL. POST request data in the form of a URL encoded on the body of the HTTP, and fields form fieldname = value, each separated by & field. Paying attention to all the fields have been handled as a string. In fact, we have to do is simulate a browser POST form. Following is a landing IE send the POST request form:
POST http://127.0.0.1/login.do HTTP/1.0
Accept: image / gif, image / jpeg, image / pjpeg, * / *
Accept-Language: en-us, zh-cn; q = 0.5
Content-Type: application / x-www-form-urlencoded
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Content-Length: 28
\ R \ n
Username = admin password = 1234 &
MIDP applications to simulate browser POST sent this request, initially at the request of ways HttpConnection POST:
Hc.setRequestMethod (HttpConnection.POST);
Text then constructed HTTP:
Byte [] data = "username = admin password = 1234 &." GetBytes ();
And the length of the text, fill Content-Type and Content-Length:
Hc.setRequestProperty ( "Content-Type", "application / x-www-form-urlencoded");
Hc.setRequestProperty ( "Content-Length" String.valueOf (data.length));
Open Text OutputStream will then write:
OutputStream output = hc.openOutputStream ();
Output.write (data);
It must be noted that data still needs to URL encoding format encoding, as the MIDP in J2SE with no corresponding URLEncoder category, therefore, need to prepare their own hands this encode () method, the reference java.net.URLEncoder.java source. The reader is left server response code consistent with the GET, will not elaborate here.
Using multipart / form-data sent documents
If the MIDP client to upload files to the server, we must simulate a POST multipart / form-data type of request, the Content-Type must be multipart / form-data.
To multipart / form-data POST request format encoding and application / x-www-form-urlencoded completely different multipart / form-data need to first set up an HTTP request first separators, such as ABCD:
Hc.setRequestProperty ( "Content-Type", "multipart / form-data; boundary = ABCD");
Then, each field "- separation" separation, the last "- separation -" the end of that. For example, to upload a title field, "Today" and a file C: \ 1.txt, HTTP text as follows:
— ABCD
Content-Disposition: form-data; name = "title"
\ R \ n
Today
— ABCD
Content-Disposition: form-data; name = "1.txt" filename = "C: \ 1.txt"
Content-Type: text / plain
\ R \ n
<Here is 1. Txt the contents of the documents>
— ABCD –
\ R \ n
Please note that each row must be \ r \ n end, including the last line. If Sniffer detection procedures POST request sent IE, IE separation can be found at similar ————————— 7 d4a6d158c9, it is IE generated a random number, the purpose is to prevent the upload files in a separate lead at the server does not correctly identify the file initial position. We can write a fixed separation, as long as can be complicated enough.
Send documents POST code as follows:
String [] props = … / / field names
String [] values = … / / field values
Byte [] file = … / / the contents of the documents
String BOUNDARY "————————— 7d4a6d158c9 = "/ / separator
StringBuffer sb = new StringBuffer ();
/ / Send each field:
For (int i = 0; i
Sb = sb.append ("–");
Sb = sb.append (BOUNDARY);
Sb = sb.append ( "\ r \ n");
Sb = sb.append ( "Content-Disposition: form-data; name = \" "+ props [i] +" \ "\ r \ n \ r \ n");
Sb = sb.append (URLEncoder.encode (values [i]));
Sb = sb.append ( "\ r \ n");
)
/ / Send documents:
Sb = sb.append ("–");
Sb = sb.append (BOUNDARY);
Sb = sb.append ( "\ r \ n");
Sb = sb.append ( "Content-Disposition: form-data; name = \" 1 \ "filename = \" 1.txt \ "\ r \ n");
Sb = sb.append ( "Content-Type: application / octet-stream \ r \ n \ r \ n");
Byte [] data = sb.toString (). GetBytes ();
End_data byte [] = ( "\ r \ n -" BOUNDARY + + "- \ r \ n"). GetBytes ();
/ / Set up HTTP header:
Hc.setRequestProperty ( "Content-Type" MULTIPART_FORM_DATA + "; boundary =" + BOUNDARY);
Hc.setRequestProperty ( "Content-Length" String.valueOf (file.length data.length + + end_data.length));
/ / Output:
Output = hc.openOutputStream ();
Output.write (data);
Output.write (file);
Output.write (end_data);
/ / Read the server response:
/ / TODO …
Use Cookie maintain Session
Session server usually used to track the session. Session is to use the simple realization Cookie. When the client first connects to the server, client server detected no corresponding Cookie field, it sends a code contains a recognition of Set-Cookie field. In the course of the subsequent conversation, the client sent the request contains the Cookie, a server can identify the client has been connected server.
With the browser to achieve the same effect, MIDP applications must also can identify Cookie, and each request contained in the first Cookie.
Each link in dealing with the response, we are examining the Set-Cookie the first and, if so, is the first server sent Session ID, or server that overtime session, the need to generate a Session ID. If detected Set-Cookie head, it will be preserved, and then each additional request it:
String session = null;
String cookie = hc.getHeaderField ( "Set-Cookie");
If (cookie! = Null) (
Int n = cookie.indexOf (';');
Cookie.substring session = (0, n);
)
Sniffer procedures can be used to capture different Web server sent Session. WebLogic Server 7.0 to return to the Session are as follows:
Set-Cookie: JSESSIONID = CxP4FMwOJB06XCByBWfwZBQ0IfkroKO2W7FZpkLbmWsnERuN5u2L! -1200402410; Path = /
Resin 2.1 and the return of Session is:
Set-Cookie: JSESSIONID = aTMCmwe9F5j9; path = /
IIS running ASP.Net the return of Session:
Set-Cookie: ASPSESSIONIDQATSASQB = GNGEEJIDMDFCMOOFLEAKDGGP; path = /
We need not concern the content of Session ID, the server they will recognize it. We need only in the subsequent request additional Session ID can be on this:
If (session! = Null)
Hc.setRequestProperty ( "Cookie" session);
The URL rewriting to maintain Session way in the PC client may be useful, but it is difficult because of the MIDP procedures URL Session useful information, therefore, do not recommend the use of such methods.
↑ Back






