package com.mzeat.http;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* 响应,将响应转换为Stream、String、Document、JSONObject、JSONArray、Reader
*
* @author windhuiyi
*
*/
public class Response {
// private final static String TAG = "HttpClient";
private final static String TAG = "Response";
private final static boolean DEBUG = true;
private static ThreadLocal<DocumentBuilder> builders = new ThreadLocal<DocumentBuilder>() {
@Override
protected DocumentBuilder initialValue() {
try {
return DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
} catch (ParserConfigurationException ex) {
throw new ExceptionInInitializerError(ex);
}
}
};
private int statusCode;
private Document responseAsDocument = null;
private String responseAsString = null;
private InputStream is;
private HttpURLConnection con;
private boolean streamConsumed = false;
private HttpResponse response;
private StatusLine statusLine;
private Header[] responseHeader;
/**
* Response构造方法
*/
public Response() {
}
/**
* Response构造方法
*/
public Response(HttpResponse response, String url) throws IOException {
this.response = response;
this.statusLine = response.getStatusLine();
this.statusCode = statusLine.getStatusCode();
this.responseHeader = response.getAllHeaders();
HttpEntity entity = response.getEntity();
this.is = entity.getContent();
Header contentEncoding = entity.getContentEncoding();
if (null != is && contentEncoding != null
&& "gzip".equals(contentEncoding.getValue())) {
// the response is gzipped
is = new GZIPInputStream(is);
}
}
// for test purpose
/* package */Response(String content) {
this.responseAsString = content;
}
/**
* 取得状态码
* @return
*/
public int getStatusCode() {
return statusCode;
}
/**
* 取得响应头
* @param name
* @return
*/
public String getResponseHeader(String name) {
if (response != null) {
Header[] header = response.getHeaders(name);
if (header.length > 0) {
return header[0].getValue();
}
}
return null;
}
/**
* Returns the response stream.返回响应流<br>
* This method cannot be called after calling asString() or asDcoument()这个方法不能在调用asString()或者asDcoument()之后调用<br>
* It is suggested to call disconnect() after consuming the stream.建议在消耗流之后断开连接的时候调用。
*
* Disconnects the internal HttpURLConnection silently.
*
* @return response body stream
* @throws HttpException
* @see #disconnect()
*/
public InputStream asStream() {
if (streamConsumed) {
throw new IllegalStateException("Stream has already been consumed.");
}
return is;
}
/**
* Returns the response body as string.像字符串一样返回响应体<br>
* Disconnects the internal HttpURLConnection silently.
*
* @return response body
* @throws HttpException
*/
public String asString() throws ResponseException {
if (null == responseAsString) {
BufferedReader br;
try {
InputStream stream = asStream();
if (null == stream) {
return null;
}
br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
StringBuffer buf = new StringBuffer();
String line;
while (null != (line = br.readLine())) {
buf.append(line).append("\n");
}
this.responseAsString = buf.toString();
this.responseAsString = unescape(responseAsString);
// log(responseAsString);
stream.close();
streamConsumed = true;
} catch (NullPointerException npe) {
// don't remember in which case npe can be thrown
throw new ResponseException(npe.getMessage(), npe);
} catch (IOException ioe) {
throw new ResponseException(ioe.getMessage(), ioe);
}
}
return responseAsString;
}
/**
* Returns the response body as org.w3c.dom.Document.<br>
* Disconnects the internal HttpURLConnection silently.
*
* @return response body as org.w3c.dom.Document
* @throws HttpException
*/
public Document asDocument() throws ResponseException {
if (null == responseAsDocument) {
try {
// it should be faster to read the inputstream directly.
// but makes it difficult to troubleshoot
this.responseAsDocument = builders.get().parse(
new ByteArrayInputStream(asString().getBytes("UTF-8")));
} catch (SAXException saxe) {
throw new ResponseException(
"The response body was not well-formed:\n"
+ responseAsString, saxe);
} catch (IOException ioe) {
throw new ResponseException(
"There's something with the connection.", ioe);
} catch (DOMException dome) {
throw new ResponseException(
"The response body was not well-formed:\n"
+ responseAsString, dome);
}
}
return responseAsDocument;
}
/**
* Returns the response body as sinat4j.org.json.JSONObject.<br>
* Disconnects the internal HttpURLConnection silently.
*
* @return response body as sinat4j.org.json.JSONObject
* @throws HttpException
*/
public JSONObject asJSONObject() throws ResponseException {
try {
return new JSONObject(asString());
} catch (JSONException jsone) {
throw new ResponseException(jsone.getMessage() + ":"
+ this.responseAsString, jsone);
}
}
/**
* Returns the response body as sinat4j.org.json.JSONArray.<br>
* Disconnects the internal HttpURLConnection silently.
*
* @return response body as sinat4j.org.json.JSONArray
* @throws HttpException
*/
public JSONArray asJSONArray() throws ResponseException {
try {
return new JSONArray(asString());
} catch (Exception jsone) {
throw new ResponseException(jsone.getMessage() + ":"
+ this.responseAsString, jsone);
}
}
/**
* 将InputStream转化成InputStreamReader
* @return
*/
public InputStreamReader asReader() {
try {
return new InputStreamReader(is, "UTF-8");
} catch (java.io.UnsupportedEncodingException uee) {
return new InputStreamReader(is);
}
}
/**
* 断开连接
*/
public void disconnect() {
con.disconnect();
}
private static Pattern escaped = Pattern.compile("([0-9]{3,5});");
/**
* Unescape UTF-8 escaped characters to string.
* 使用UTF-8编码转义字符到字符串
* @author pengjianq...@gmail.com
*
* @param original
* The string to be unescaped.
* @return The unescaped string
*/
public static String unescape(String original) {
Matcher mm = escaped.matcher(original);
StringBuffer unescaped = new StringBuffer();
while (mm.find()) {
mm.appendReplacement(unescaped, Character.toString((char) Integer
.parseInt(mm.group(1), 10)));
}
mm.appendTail(unescaped);
return unescaped.toString();
}
/**
* 重写toString()方法
*/
@Override
public String toString() {
return "Response [statusCode=" + statusCode + ", responseAsDocument="
+ responseAsDocument + ", responseAsString=" + responseAsString
+ ", is=" + is + ", con=" + con + ", streamConsumed="
+ streamConsumed + ", response=" + response + ", statusLine="
+ statusLine + ", responseHeader="
+ Arrays.toString(responseHeader) + "]";
}
/**
* 取得响应字符串
* @return
*/
public String getResponseAsString() {
return responseAsString;
}
/**
* 设置响应字符串
* @param responseAsString
*/
public void setResponseAsString(String responseAsString) {
this.responseAsString = responseAsString;
}
/**
* 设置状态码
* @param statusCode
*/
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
}