One of this blog's most visited entries (ranking always around the Top 5 Google results for "HTTP POST" too) elaborated on how to send data across to a server from a J2ME Midlet.
I thought it was high time for bringing this into the new Century, and provide an update as to how to do this from an Android smartphone.
It turns out that (a) the code is relatively straightforward and (b) that there is not so much difference after all from writing the same code for a desktop client: credit for this ought to go to the Android Google team who have done such a superb job of adapting the J2SE API to the Android platform...
THIS BLOG HAS MOVED TO codetrips.com
Please read the rest of this post on codetrips.com
This blog was born as a means of annotating big and small discoveries in my use of Java, Ubuntu/Linux and Android that would be easy to access from anywhere, anytime. It does beat post-it's big time, and it also adds the benefit that others might, eventually, contribute with intelligent insights.
Showing posts with label POST. Show all posts
Showing posts with label POST. Show all posts
Saturday, August 13, 2011
Sunday, April 29, 2007
HTTP POST from a J2ME midlet
NOTE - this blog has now moved to codetrips.com
It is highly recommended that you read the original post there.
-------------
Although there are several examples and tutorials about how to connect to an HTTP server from a J2ME Midlet, I found that they all seem to concentrate a lot on the details of a GET and the POST is always assumed as an "exercise to the reader."
Now, although it is indeed rather straightforward to work out how to send POST requests to a server, I found (the hard way) that there are certain "minor details" that are best not forgotten.
I have thus decided to post here a brief example of how to send a request to a server, using a form-encoded body, so that either a JSP or a servlet can retriever the parameters, but one can benefit from the many advantages of POSTing, as oppposed to GETting.
The source code follows, I believe it is reasonably self-explanatory and comments should guide even the most novice reader through, but please do let me know if you feel that this is still too cryptic:
To test this code, all that is required is a simple Serlvet that runs, for example, in an Apache Tomcat JSP container:
It is highly recommended that you read the original post there.
-------------
Although there are several examples and tutorials about how to connect to an HTTP server from a J2ME Midlet, I found that they all seem to concentrate a lot on the details of a GET and the POST is always assumed as an "exercise to the reader."
Now, although it is indeed rather straightforward to work out how to send POST requests to a server, I found (the hard way) that there are certain "minor details" that are best not forgotten.
I have thus decided to post here a brief example of how to send a request to a server, using a form-encoded body, so that either a JSP or a servlet can retriever the parameters, but one can benefit from the many advantages of POSTing, as oppposed to GETting.
The source code follows, I believe it is reasonably self-explanatory and comments should guide even the most novice reader through, but please do let me know if you feel that this is still too cryptic:
private void OpenConnection(String server)
throws java.io.IOException {
// TODO: the actual "resource" part of the URL (/test in this case)
// should be either passed as a parameter or obtained at application
// level (maybe even set up at runtime).
// To test this code, I have written the simple Servlet below, however
// this would also work with a JSP page that echoes back the contents
// in text/plain format for the midlet to display.
//
String url = "http://"+server+"/test";
byte[] data = null;
InputStream istrm = null;
HttpConnection http = (HttpConnection)Connector.open(url);
http.setRequestMethod(HttpConnection.POST);
// This allows a JSP page to process the parameters correctly
// This format (or content type) is the same as when forms are
// submitted from a web page.
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// You may want to indicate to the server side (eg servlet) that
// this request is coming from a specific application. This would
// allow generation of appropriate format for the content.
http.setRequestProperty("User-Agent", "HttpMidlet/0.2");
// You can send any custom property as part of the HTTP header
// This would matter for the "infrastructure" code, as opposed
// to "body parameters" that would matter to the application
// (eg, user=marco)
http.setRequestProperty("Custom-Property",
"MyCustomProperty/1.0; AnotherProperty/debug_0.1");
// You MUST create the body of the post BEFORE actually opening
// the stream, otherwise you won't be able to set the length of
// the request (see next step).
// In this example, I am sending coordinates to a mapping server
String msg = "x="+location.getX()+"&y="+location.getY();
// THIS is important! without it a JSP won't process the POST data
// it would also appear that CASE MATTERS (using "Content-Length" -note
// the capital 'L'- caused my servlet to return -1 from the
// HttpServletRequest.getContentLenght() method
http.setRequestProperty("Content-length", ""+msg.getBytes().length);
// After this point, any call to http.setRequestProperty() will
// cause an IOException
OutputStream out = http.openOutputStream();
out.write(msg.getBytes());
out.flush();
if (http.getResponseCode() == HttpConnection.HTTP_OK) {
int len = (int)http.getLength();
istrm = http.openInputStream();
if (istrm == null) {
log("Cannot open stream - aborting");
throw new IOException("Cannot open HTTP InputStream, aborting");
}
if (len != -1) {
data = new byte[len];
int bytesRead = istrm.read(data);
addProgressMsg("Read "+bytesRead+" bytes");
} else {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
int ch;
int count = 0;
// This is obviously not particularly efficient
// You may want to use a byte[] buffer to read bytes in chunks
while ((ch = istrm.read()) != -1) {
bo.write(ch);
count++;
}
data = bo.toByteArray();
bo.close();
addProgressMsg("Read "+count+" bytes");
}
response = new String(data);
addProgressMsg("finished");
} else {
log("Response: "+http.getResponseCode()+", "+http.getResponseMessage());
response = null;
addProgressMsg("failed: "+http.getResponseMessage());
}
// This is critical, unless you close the HTTP connection, the application
// will either be consuming needlessly resources or, even worse, sending
// 'keep-alive' data, causing your user to foot unwanted bills!
http.close();
}
To test this code, all that is required is a simple Serlvet that runs, for example, in an Apache Tomcat JSP container:
public class ConnectivityDiag extends HttpServlet {
private static final String REVISION = "0.0.04";
private static Logger log;
public ConnectivityDiag() {
if (log == null) {
log = Logger.getLogger(getClass().getName());
BasicConfigurator.configure();
}
}
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doProcessRequest(req, res);
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doProcessRequest(req, res);
}
public void doProcessRequest(HttpServletRequest req, HttpServletResponse res) {
BufferedReader reader = null;
Writer writer = null;
try {
// Note this call seems to be case-sensitive
// if the midlet does not set exactly "Content-length"
// as the property, -1 will be returned
int len = req.getContentLength();
String contentType = req.getContentType();
log.debug("Len: " + len);
log.debug("Type: "+contentType);
int bytesRead = 0;
String remoteHost = req.getRemoteHost();
String userAgent = req.getHeader("user-agent");
log.info("Accessed at " + (new Date()) + " from " + remoteHost
+ ", using " + userAgent);
// This simply echoes the parameters back to the client.
// A JSP would use these in a tag
// and the ${param} macro.
ArrayList strings = new ArrayList();
Enumeration e = req.getParameterNames();
while (e.hasMoreElements()) {
String param = (String)e.nextElement();
String value = (String)req.getParameter(param);
strings.add(param+" = "+value);
}
res.setContentType("text/plain");
// This is a custom property, that the remote client
// could query
res.setHeader("Sent-at", new Date().toString());
writer = res.getWriter();
writer.write("Diagnostic servlet - Rev. "+REVISION);
writer.write("\nBytes received: " + len);
writer.write("\nFrom: " + remoteHost);
writer.write("\nUsing: " + userAgent);
writer.write("\n=== Parameters ===\n");
for(String s:strings) {
writer.write(s);
writer.write('\n');
}
writer.write("=== Parameters end here ===\n");
writer.flush();
} catch (IOException e) {
log.error(e.getMessage());
} finally {
try {
if (reader != null)
reader.close();
if (writer != null)
writer.close();
} catch (IOException ex) {
log.error(ex.getMessage());
}
}
}
}
Subscribe to:
Posts (Atom)
