您的位置:首页 > 理论基础 > 计算机网络

一个基于http协议的访问网络的封装类

2005-12-31 09:04 489 查看
转一个基于http协议的访问网络的封装类,使用时只需调用

public static synchronized byte[] connect(String url, byte[] data,String method, String contentType, long lowRange, long highRange, boolean disableProxy, boolean detached)

这个函数就可以了.



------------------------------------------
/**
* NetConnection.java
*
* This code is protected under the Apache 2.0 license as mentioned in
* the accompanying license.txt file. The license.txt file MUST be located
* within the same folder as this NetConnection.java source file.
*
* The license file may also be viewed online by
* visiting http://www.apache.org/licenses/
*/

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;



/**
* This class provides robust network connectivity and exception handling
* over an unreliable MIDP HttpConnection.
*
* In addition the caller may perform a combination of any of the below
* functions.
*
* - Proxy-server thwarting
* - HTTP range requests
* - Thread-separated connections
*
* @author Jason Fuerstenberg (http://www.jay-f.jp)
* @version 2004/03/15
*/
public final class NetConnection implements Runnable {

/*
* This class is implemented as a singleton since only
* a single active connection is allowed.
*/
private static NetConnection singleton = new NetConnection();


/*
* The underlying HttpConnection which is managed by this class.
*/
private static HttpConnection httpConn;


/*
* To support multi-threaded network connections a series of
* pass-through members are used/shared across the class' threads.
*/


/*
* The requested URL.
*
* This member serves a second purpose which is to prevent a caller
* from directly calling the run() method which is public to adhere to
* the Runnable interface.
*/
private static String url;


// The HTTP method used to make the connection.
private static String method;

// The posted data if any.
private static byte[] data;

// The content type (if the method is POST)
private static String contentType;

// The lower bound of the requested range.
private static long lowRange;

// The higher bound of the requested range.
private static long highRange;

/*
* The flag to indicate that the request should attempt to thwart
* any proxy servers by appending a timestamp to the request.
*/
private static boolean disableProxy;

/*
* The flag to indicate that the connection should occur in a separate
* thread.
*/
private static boolean detached;

// The response's byte array.
private static byte[] response;


/*
* In the event of an exception occuring in the run() method during
* synchronous or asynchronous execution the exception needs to be
* communicated up the main application thread's call stack. This static
* member will be a reference for any exception that may have occured
* and will be thrown after run() returns.
*
*/
private static Exception exceptionPipe;

/*
* The private constructor to enforce the singleton pattern
* which this class implements.
*/
private NetConnection() {
// singleton
}

/**
* Connects to a target URL.
*
* @param url The target URL
* @param data The data to post (if any)
* @param method HttpConnection.GET or HttpConnection.POST
* @param contentType The content-type of the posted data (if any)
* @param lowRange The byte offset within the requested resource from
* which the response will begin.
* @param highRange The last byte the response will return or 0
* if requesting the entire resource.
* @param disableProxy Attempts to prevent a given server from
* offering a cached proxy version of the
* requested resource.
* @param detached Causes the connection to occur in a thread separate
* from the calling thread. This call will block until
* the connection has ended.
* @return A byte array containing the response from the server.
* @throws IOException If a network error occured.
*/
public static synchronized byte[] connect(String url, byte[] data,
String method, String contentType, long lowRange, long highRange,
boolean disableProxy, boolean detached) throws Exception {


/*
* Set all the pass-through members here.
*/
exceptionPipe = null;
NetConnection.url = url;
NetConnection.data = data;
NetConnection.method = method;
NetConnection.contentType = contentType;
NetConnection.lowRange = lowRange;
NetConnection.highRange = highRange;
NetConnection.disableProxy = disableProxy;
NetConnection.detached = detached;


// Preemptively try to disconnect from a previous connection!
NetConnection.severConnection();


if (detached) {
/*
* The caller has specified that the connection should occur
* in a separate, detached thread.
*/
Thread t = new Thread(singleton);
t.start();

/*
* Enforce a wait here to provide the illusion of synchronous
* execution despite having the connection in another thread.
*/
singleton.forceWait();

} else {
/*
* Call run() directly without creating a thread to launch it.
*/
singleton.run();
}

/*
* Reset the URL to null to prevent direct
* calling of the run() method.
*/
NetConnection.url = null;

if (exceptionPipe != null) {
/*
* During the course of the connection an exception occured
* and was communicated here by the exceptionPipe member.
* Throw it from this location.
*/
throw exceptionPipe;
}

// successful connection, return response!
return response;
}


/**
* Performs the actual connection logic.
* The connection may occur in a separate thread from that of the caller.
*
* @throws IllegalStateException if called directly by any class
* other than this one.
*/
public void run() {

if (url == null) {
/*
* The URL is used as a means to ascertain whether or not the
* caller of this method was the connect() method. Since it is
* null the caller is directly calling run() so throw an exception.
*/
throw new IllegalStateException("Cannot invoke this method!");
}


DataOutputStream dos = null;
DataInputStream dis = null;
StringBuffer buffer = null;


/*
* IMPLEMENTATION NOTE:
*
* From this section on, a series of try/catch/finally statements
* is used to ensure the proper flow of the connection under a
* wide variety of circumstances. This seemingly verbose logic
* is important for the proper exception handling and object
* reclamation required to make subsequent connections
* possible in the future.
*
* In addition, the catching of exception is not too particular
* regarding the type of exception being thrown for a few reasons...
*
* 1. The handling of each exception type is identical
* 2. Implementations may vary in which exceptions they throw
*
* In the interest of stability it is highly recommended to
* leave this as is, even if it goes against orthodox practices.
*/

try {

int permissions = 0;

// Setup the permissions
if (HttpConnection.GET.equals(method)) {
permissions = Connector.READ;
} else if (HttpConnection.POST.equals(method)) {
permissions = Connector.READ_WRITE;
}


if (disableProxy) {
/*
* To thwart the a given server's proxy cache
* the logic will attach a query parameter to the
* end of the URL with a millisecond timestamp which
* will hopefully force the server to see this request as one
* which has never previously occured for this client
* and therefore entitled to a fresh copy of the requested
* resource.
*/
boolean hasQueryParams = false;

char[] ca = url.toCharArray();

for (int loop = 0; loop < url.length(); loop++) {

if (ca[loop] == '?') {
hasQueryParams = true;
break;
}
}

StringBuffer noProxyUrl = new StringBuffer();
noProxyUrl.append(url);

if (hasQueryParams) {
noProxyUrl.append("&");
} else {
noProxyUrl.append("?");
}
noProxyUrl.append("no-proxy=");
noProxyUrl.append(System.currentTimeMillis()); // timestamp

/*
* Reset the URL to include the "no-proxy" query
* parameter.
*/
url = noProxyUrl.toString();
}



// Open the connection and set the request method.
httpConn = (HttpConnection) Connector.open(url, permissions, true);
httpConn.setRequestMethod(method);

//if (HttpConnection.GET.equals(method)) {
if (permissions == Connector.READ) {
// GET request

if (lowRange > -1 && lowRange < highRange) {
/*
* The caller is requesting a specific range within
* the resource.
*
* The logic will insert the appropriate HTTP header to
* implement the request.
*/
StringBuffer range = new StringBuffer();

range.append("bytes=");
range.append(lowRange);
range.append("-");
range.append(highRange);

httpConn.setRequestProperty("Range", range.toString());
}
} else if (permissions == Connector.READ_WRITE) {
// POST request
httpConn.setRequestProperty("Content-Type", contentType);
dos = httpConn.openDataOutputStream();
dos.write(data);
}

} catch (Exception e) {
/*
* An exception occured either during the opening of the connection
* or during the POSTing of data. In either case the logic cannot
* continue and will quit here.
*/
exceptionPipe = e;

if (detached) {
forceNotify();
}

return;

} finally {

try {
try {
if (dos != null) {
// Close the DataOutputStream.
dos.close();
}
} catch (Exception e) {
// Failure to close the DataOutputStream!
if (exceptionPipe == null) {
exceptionPipe = e;

if (detached) {
forceNotify();
}
return;
}
} finally {
// Force the dereferencing of the DataOutputStream.
dos = null;
}

// Get the response code.
int responseCode = httpConn.getResponseCode();

if (responseCode != HttpConnection.HTTP_OK
&& responseCode != HttpConnection.HTTP_PARTIAL) {

/*
* The response code does not match HTTP_OK (200)
* or HTTP_PARTIAL (206). The logic cannot proceed to
* treat the response as one holding the requested
* resource and therefore will report the response code
* via an exception to the caller.
*/
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;
}
}

dis = httpConn.openDataInputStream();

/*
* Cycle through all the bytes provided
* in the response and append them to a
* StringBuffer for later use.
*/
int ch;
buffer = new StringBuffer();
while ((ch = dis.read()) != -1) {
buffer.append((char) ch);
}

/*
* Convert the StringBuffer to an array using
* the ISO-8859-1 encoding to preserve the byte
* encoding of the characters.
*/
response = buffer.toString().getBytes("ISO8859_1");

if (detached) {
forceNotify();
}

/*
* All OK, now returning.
*/
return;

} catch (Exception e) {
/*
* An exception occured either during the usage of the
* connection object (such as a NullPointerException) or during
* the reading of the data. In either case the logic cannot
* continue.
*/
if (exceptionPipe == null) {
exceptionPipe = e;

if (detached) {
forceNotify();
}

return;
}
} finally {

try {
if (dis != null) {
// Close the DataInputStream.
dis.close();
}
} catch (Exception e) {
// Failure to close the DataInputStream!
if (exceptionPipe == null) {
exceptionPipe = e;

if (detached) {
forceNotify();
}
return;
}
} finally {
// force the dereferencing of the DataInputStream.
dis = null;
}

try {
if (httpConn != null) {
// Close the HttpConnection.
httpConn.close();

/*
* Only dereference the HttpConnection if the
* closing actually succeeded!
*/
httpConn = null;
}
} catch (Exception e) {
// Failure in closing the HttpConnection!
if (exceptionPipe == null) {
exceptionPipe = e;

if (detached) {
forceNotify();
}
return;
}
}
}
}
}

/*
* Provides the synchronized context against the singleton's instance
* for the wait() method call to properly execute. Not all implementations
* of the JVM support the concept of synchronized contexts other than
* that of an entire method. As such the inner call to wait must be
* embedded in this synchronized method.
*/
private synchronized void forceWait() {

try {
wait();
} catch (InterruptedException ie) {
// Ignore this exception
ie = null;
}
}


/*
* Provides the synchronized context against the singleton's instance
* for the notify() method call to properly execute. Not all
* implementations of the JVM support the concept of synchronized
* contexts other than that of an entire method. As such the inner
* call to notify must be embedded in this synchronized method.
*/
private synchronized void forceNotify() {
notify();
}

/*
* Severs an ongoing connection.
*/
private static void severConnection() {

try {
if (httpConn == null) {
/*
* No connection is in progress so simply return
* to the caller.
*/
return;
}

// Close the connection.
httpConn.close();

} catch (Exception e) {
/*
* If the handset's implementation of the HttpConnection
* interface is solid it will not be possible for
* an exception to occur.
*/
e = null;
} finally {
// Force the dereferencing of the connection.
httpConn = null;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: