当前页面: 开发资料首页 → J2ME 专题 → 来自日本程序员的MIDP 1.0 HttpConnection类的robust封装
摘要: 来自日本程序员的MIDP 1.0 HttpConnection类的robust封装
//当前只能由一个线程使用singleton。
private static NetConnection singleton = new NetConnection();
private static HttpConnection httpConn;
private static String url;
private static String method;
private static byte[] data;
private static String contentType;
private static long lowRange;
private static long highRange;
private static boolean disableProxy;
private static boolean detached;
private static byte[] response;
//线程run方法
public void run()
//当前运行的线程执行完毕后,通报给其它的由于等待资源而wait状态的线程
private synchronized void forceNotify()
//当资源正在被其它线程使用时,当前线程进入wait状态
private synchronized void forceWait()
//关闭http连接
private static void severConnection()
/**
* 实现了连接逻辑。
* 调用者可以在分离的线程中使用netConnection类的静态连接。
* @throws IllegalStateException 如果此方法直接其它类调用则抛出该异常
*/
public void run() {
if (url == null) {
throw new IllegalStateException("Cannot invoke this method!");
}
DataOutputStream dos = null;
DataInputStream dis = null;
StringBuffer buffer = null;
try {
int permissions = 0;
//根据method值,设置Connector的权限(READ/READ_WRITE)
if (HttpConnection.GET.equals(method)) {
permissions = Connector.READ;
} else if (HttpConnection.POST.equals(method)) {
permissions = Connector.READ_WRITE;
}
//如果关闭server代理功能,则构造noProxyUrl。
//原理:使用timestamp作为该URL中no-proxy参数值,
// 致使server视其为client发来的新请求。
if (disableProxy) {
boolean hasQueryParams = false;
char[] ca = url.toCharArray();
//判断原URL中是否含有参数
for (int loop = 0; loop < url.length(); loop++) {
if (ca[loop] == '?') {
hasQueryParams = true;
break;
}
}
//由于需要多次字符串拼接,所以使用可提供效率的StringBuffer类
StringBuffer noProxyUrl = new StringBuffer();
//将原URL内容复制到noProxyUrl
noProxyUrl.append(url);
//如果原URL中含有参数,
// 则需要在noProxyUrl中增加"&",
// 否则直接在noProxyUrl中增加"?",
// 这样做为了后面增加no-proxy参数做准备。
if (hasQueryParams) {
noProxyUrl.append("&");
} else {
noProxyUrl.append("?");
}
//增加no-proxy参数
noProxyUrl.append("no-proxy=");
noProxyUrl.append(System.currentTimeMillis()); // timestamp
//将构造好的noProxyUrl复制到原URL
url = noProxyUrl.toString();
}
// 打开Http 连接
httpConn = (HttpConnection) Connector.open(url, permissions, true);
//设置request方法
httpConn.setRequestMethod(method);
//如果request权限为READ(即request方法为GET),
//则需要设置http request属性的Range。
//原理:设置http request属性的Range后的,
// server接收到该request后将把response数据分成小部分发回。
// 从而避免了部分运营商对http response size的限制。
if (permissions == Connector.READ) {
if (lowRange > -1 && lowRange < highRange) {
StringBuffer range = new StringBuffer();
range.append("bytes=");
range.append(lowRange);
range.append("-");
range.append(highRange);
httpConn.setRequestProperty("Range", range.toString());
}
//否则,request权限为READ_WRITE(即request方法为POST),
//那么设置request的Content-Type属性。
} else if (permissions == Connector.READ_WRITE) {
// POST request
httpConn.setRequestProperty("Content-Type", contentType);
dos = httpConn.openDataOutputStream();
dos.write(data);
}
} catch (Exception e) {
exceptionPipe = e;
//如果程序运行在多线程模式,则在异常发生后需要唤醒其它睡眠的线程继续run
if (detached) {
forceNotify();
}
return;
} finally {
try {
try {
if (dos != null) {
// 关闭dos
dos.close();
}
} catch (Exception e) {
// 如果程序运行在多线程模式,则在异常发生后需要唤醒其它睡眠的线程继续run
if (exceptionPipe == null) {
exceptionPipe = e;
if (detached) {
forceNotify();
}
return;
}
} finally {
dos = null;
}
// 读取http连接的回应代码
int responseCode = httpConn.getResponseCode();
//当request方法为GET,并设置了request range时,接收到的回应代码为HTTP_PARTIAL
//当request方法为POST,接收到的回应代码为HTTP_OK
//如果上述两种回应代码均没有收到,则表明连接失败或者出问题
if (responseCode != HttpConnection.HTTP_OK
&& responseCode != HttpConnection.HTTP_PARTIAL) {
if (exceptionPipe == null) {
StringBuffer errorCode = new StringBuffer();
errorCode.append("Response code from server: ");
errorCode.append(responseCode);
errorCode.append("\nMessage: [");
errorCode.append(httpConn.getResponseMessage());
errorCode.append("]");
exceptionPipe = new IOException(errorCode.toString());
if (detached) {
forceNotify();
}
return;
}
}
//如果收到了上述的两种回应代码之一,则可以继续读取server的response数据
dis = httpConn.openDataInputStream();
//循环读取repsonse数据
int ch;
buffer = new StringBuffer();
while ((ch = dis.read()) != -1) {
buffer.append((char) ch);
}
//将response数据进行必要的编码转换
response = buffer.toString().getBytes("ISO8859_1");
//接收到回应后,表明整个http会话过程结束,线程将结束。
//如果程序运行在多线程模式,则此时需要唤醒其它睡眠的线程继续run
if (detached) {
forceNotify();
}
return;
} catch (Exception e) {
if (exceptionPipe == null) {
exceptionPipe = e;
if (detached) {
forceNotify();
}
return;
}
} finally {
try {
if (dis != null) {
// 关闭dis
dis.close();
}
} catch (Exception e) {
// 若关闭dis时发生异常,则进行异常处理
if (exceptionPipe == null) {
exceptionPipe = e;
if (detached) {
forceNotify();
}
return;
}
} finally {
dis = null;
}
try {
if (httpConn != null) {
//关闭http连接
httpConn.close();
httpConn = null;
}
} catch (Exception e) {
if (exceptionPipe == null) {
exceptionPipe = e;
if (detached) {
forceNotify();
}
return;
}
}
}
}
}