Network Development Based on best practices of J2EE

Source: Internet
Author: User

 

Core Tip: Write a responsive online prompt interface. Due to the limited network protocols supported by wireless devices, this interface is only applicable to HTTP, socket, UDP, and other protocols, different manufacturers may also support other network protocols. However, the MIDP 1.0 standard stipulates that HTTP is a required protocol, and other protocols are optional. Therefore, in order

Compile a responsive online prompt Interface

Due to the limited network protocols supported by wireless devices, they are limited to HTTP, socket, UDP, and other protocols. Different manufacturers may also support other network protocols. However, MIDP 1.0 specifications stipulate that, HTTP is a required protocol, while other protocols are optional. Therefore, in order to port on different types of mobile phones, we try to use HTTP as the preferred protocol for network connection, so that we can reuse the server code. However, HTTP is a text-based protocol with low efficiency. Therefore, you must carefully consider the communication between the mobile phone and the server to Improve the efficiency as much as possible.

For MIDP applications, try:

1. When sending a request, append a User-Agent header and pass in the MIDP and its version number so that the server can identify the request from the MIDP application and send the corresponding response based on the version number.
2. When connecting to the server, a download progress bar is displayed so that you can see the download progress and interrupt the connection at any time.
3. Due to the slow connection speed of the wireless network, it is necessary to cache some data, which can be stored in the memory or in RMS.

For the server, the output response should be as follows:

1. explicitly set the Content-Length field so that the MIDP application can read the HTTP header and determine whether it can process the data of this length. If it cannot, it can directly close the connection without continuing to read the HTTP body.
2. the server should not send HTML content, because the MIDP application is difficult to parse HTML. Although XML can be parsed, it consumes CPU and memory resources. Therefore, it should send compact binary content, use dataoutputstream to write data directly and set Content-Type to application/octet-stream.
3. Try not to redirect the URL. This will cause the MIDP application to connect to the server again, increasing the user's waiting time and network traffic.
4. if an exception occurs, for example, the requested resource is not found, or the authentication fails, the server usually sends an error page to the browser, which may also contain a user login form. However, sending an error page to MIDP is meaningless. A 404 or 401 error should be sent directly, so that the MIDP application can directly read the response code of the HTTP header to obtain the error information without continuing to read the corresponding content.
5. Because the computing power of the server far exceeds that of the mobile client, the task of sending different responses to different client versions should be completed on the server. For example, determine the client version based on the User-Agent header sent by the client. In this way, clients of earlier versions can continue to be used without upgrading.

The MIDP network framework defines multiple Protocol network connections, but each vendor must implement HTTP connections and add required HTTPS connections in MIDP 2.0. Therefore, to ensure that the MIDP application can be transplanted on mobile platforms of different vendors, it is best to only use HTTP connections. Although HTTP is a text-based protocol with low efficiency, because it is widely used, the front-end of most server applications is based on HTTP web pages, so the server code can be reused to the maximum extent. As long as the cache is well controlled, there is still a good speed.

Sun's MIDP Library provides the javax. microediton. Io package, which can easily implement HTTP connections. However, due to the high network latency, you must put the online operations in a separate thread to avoid blocking the main thread and stop the response on the user interface. In fact, the MIDP runtime environment does not allow network connections in the main thread. Therefore, we must implement a flexible HTTP networking module that allows users to intuitively view the current upload and download progress and cancel the connection at any time.

A complete HTTP connection is: the user initiates a connection request through a command, and then the system gives a waiting screen prompt indicating that the connection is in progress. After the connection ends normally, go to the next screen and process the downloaded data. If an exception occurs during the connection process, a prompt will be sent to the user and returned to the previous screen. The user can cancel and return to the previous screen at any time while waiting.

We designed an httpthread Thread class to connect to the server in the background. The httplistener interface implements the observer (observer) mode so that httpthread can prompt the observer to start download, download ends, update progress bars, and so on. The httplistener interface is 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 );
}

The httplistener interface is implemented on an httpwaitui screen inherited from the form. It displays a progress bar and prompts, and allows you to interrupt the connection at any time:

Public class httpwaitui extends form implements commandlistener, httplistener {
Private gauge;
Private command cancel;
Private httpthread downloader;
Private displayable;
Public httpwaitui (string URL, 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 ){... }
}

Httpthread is the Thread class responsible for processing HTTP connections. It accepts a URL and httplistener:

Class httpthread extends thread {
Private Static final int max_length = 20*1024; // 20 K
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 content using get

Let's first discuss the simplest GET request. For a GET request, you only need to send a URL to the server and obtain the server response. Implement the following in the run () method of httpthread:

Public void run (){
Httpconnection Hc = NULL;
Inputstream input = NULL;
Try {
Hc = (httpconnection) connector. Open (URL );
HC. setrequestmethod (httpconnection. Get); // The default value is 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 (); // return response size, or-1 if the size cannot be determined
Listener. onsetsize (size );
// Start read response:
Input = HC. openinputstream ();
Int percent = 0; // percentage
Int tmp_percent = 0;
Int Index = 0; // Buffer Index
Int reads; // each byte
If (size! = (-1 ))
Buffer = new byte [size]; // The response size is known to determine the buffer size.
Else
Buffer = new byte [max_length]; // The response size is unknown. Set a fixed buffer size.
While (! Cancel ){
Int Len = buffer. Length-index;
Len = Len> 128? 128: Len;
Reads = input. Read (buffer, index, Len );
If (reads <= 0)
Break;
Index + = reads;
If (size> 0) {// Update Progress
Tmp_percent = Index * 100/size;
If (tmp_percent! = Percent ){
Percent = tmp_percent;
Listener. onprogress (percent );
}
}
}
If (! Cancel & input. Available ()> 0) // the buffer is full and cannot be 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, index );
}
}
Catch (ioexception IOE ){
Listener. onerror (101, "ioexception:" + IOE. getmessage ());
}
Finally {// clear Resources
If (input! = NULL)
Try {input. Close ();} catch (ioexception IOE ){}
If (HC! = NULL)
Try {HC. Close ();} catch (ioexception IOE ){}
}
}

After the download is complete, httpwaitui obtains data from the server and transmits the data to the next screen for processing. httpwaitui must contain a reference to the screen and use a setdata (datainputstream input) the method allows the next screen to easily read data. Therefore, define a datahandler interface:

Public interface datahandler {
Void setdata (datainputstream input) throws ioexception;
}

Httpwaitui responds to the onfinish event of httpthread and calls the setdata method of the next screen to pass the data to it and displays 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 ){... }
}

Taking downloading a news piece as an example, a complete http get request process is as follows:

First, you want to read the specified news by clicking a command on a screen. In the commandaction event, we initialize httpwaitui and the newsui screen that displays data:

Public void commandaction (command C, displayable d ){
Httpwaitui wait = new httpwaitui ("", new newsui ());
Controllermidlet. Forward (wait );
}

Newsui implements the datahandler interface and displays the downloaded data:

Public class newsui extends form implements datahandler {
Public void setdata (datainputstream input) throws ioexception {
String title = input. readutf ();
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 writes data to dataoutputstream in the order of string, long, and string, the MIDP client can use datainputstream to obtain the corresponding data in sequence without parsing text such as XML, very efficient and convenient.

To obtain online data, you only need to implement the datahandler interface and input a URL to httpwaitui to reuse the code. You do not need to worry about how to connect to the network and how to handle user interruption.

Use post to send data

The post method is mainly used to send a large amount of client data to the server, which is not limited by the URL length. The post request places the data in the HTTP body in URL encoding format. The field format is fieldname = value, and each field is separated. Note that all fields are processed as strings. In fact, what we need to do is simulate the browser to post a form. The following is a POST request sent by IE to a login form:

Posthttp/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

To simulate a browser in the MIDP application to send this POST request, first set the HTTP Connection Request Method to post:

HC. setrequestmethod (httpconnection. post );

Then construct the HTTP body:

Byte [] DATA = "username = Admin & Password = 1234". getbytes ();

And calculate the body length, and fill in Content-Type and Content-Length:

HC. setrequestproperty ("Content-Type", "application/X-WWW-form-urlencoded ");
HC. setrequestproperty ("Content-Length", String. valueof (data. Length ));

Enable outputstream to write the body:

Outputstream output = HC. openoutputstream ();
Output. Write (data );

Note that the data still needs to be encoded in URL encoding format. Because the MIDP library does not have the urlencoder class corresponding to j2se, you need to write the encode () method by yourself, for more information, see java.net. urlencoder. java source code. The rest is to read the server response, and the code is consistent with get, so we will not detail it here.

Use multipart/form-data to send files

To upload files to the server on the MIDP client, we must simulate a post multipart/form-data request. The content-type must be multipart/form-data.

The format of post requests encoded with multipart/form-data is completely different from that of application/X-WWW-form-urlencoded. To use multipart/form-data, you must first set a separator in the HTTP request header, for example, ABCD:

HC. setrequestproperty ("Content-Type", "multipart/form-data; boundary = ABCD ");

Then, each field is separated by "-- separator", and the last "-- Separator --" indicates the end. For example, to upload a title field "today" and a file c: \ 1.txt, the HTTP body is 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
<This is the content of the 1.txt File>
-- ABCD --
\ R \ n

Note that each row must end with \ r \ n, including the last row. If you use the sniffer program to check the POST request sent by IE, you can find that the IE separator is similar to ------------------------- 7d4a6d158c9, which is a random number generated by IE, the purpose is to prevent the server from correctly identifying the start position of a file due to a separator in the uploaded file. We can write a fixed separator as long as it is complex enough.

The post code for sending the file is as follows:

String [] props =... // field name
String [] values =... // Field Value
Byte [] file =... // File Content
String boundary = "--------------------------- 7d4a6d158c9"; // delimiter
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 ");
SB = sb. append (urlencoder. encode (Values [I]);
SB = sb. append ("\ r \ n ");
}
// Send the file:
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 ");
Byte [] DATA = sb. tostring (). getbytes ();
Byte [] end_data = ("\ r \ n --" + boundary + "-- \ r \ n"). getbytes ();
// Set the HTTP header:
HC. setrequestproperty ("Content-Type", multipart_form_data + "; boundary =" + boundary );
HC. setrequestproperty ("Content-Length", String. valueof (data. Length + file. 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 to maintain session

Generally, the server uses session to track sessions. The simple implementation of session is to use cookies. When the client connects to the server for the first time, the server detects that the client does not have the corresponding Cookie field, and sends a set-Cookie field containing an identifier. In subsequent sessions, all requests sent by the client contain this cookie. Therefore, the server can identify that the client has been connected to the server.

To achieve the same effect as a browser, the MIDP application must also recognize the cookie and include the cookie in each request header.

In the response to each connection, we check whether the set-Cookie header exists. If yes, it is the session ID sent by the server for the first time, or the server determines that the session times out, you need to regenerate a session ID. If the set-Cookie header is detected, save it and append it to each subsequent request:

String session = NULL;
String cookie = HC. getheaderfield ("Set-cookie ");
If (cookie! = NULL ){
Int n = cookie. indexof (';');
Session = cookie. substring (0, N );
}

You can use the sniffer program to capture sessions sent by different Web servers. The session returned by Weblogic Server 7.0 is as follows:

Set-COOKIE: JSESSIONID = cxp4fmwojb06xcbybwfwzbq0ifkroko2w7fzpklbmwsnerun5u2l! -1200402410; Path =/

The session returned by resin 2.1 is:

Set-COOKIE: JSESSIONID = atmcmwe9f5j9; Path =/

Session returned by IIS running ASP. NET:

Set-COOKIE: aspsessionidqatsasqb = gngeejidmdfcmoofleakdggp; Path =/

We do not need to care about the content of the session ID. The server itself recognizes it. We only need to attach this session ID to the subsequent request:

If (session! = NULL)
HC. setrequestproperty ("cookie", session );

This method may be useful on PC clients for URL rewriting to preserve sessions. However, it is not recommended because the MIDP program is difficult to analyze useful session information in URLs.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.