/**
* Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.tsz.afinal.http;
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.protocol.HttpContext;
import com.mfh.comna.comn.logic.IPublishProgressAble;
import android.os.SystemClock;
import net.tsz.afinal.http.entityhandler.EntityCallBack;
import net.tsz.afinal.http.entityhandler.FileEntityHandler;
import net.tsz.afinal.http.entityhandler.StringEntityHandler;
/**
* 同步http请求处理
*
* @author zhangyz created on 2013-5-15
* @since Framework 1.0
*/
public class SyncRequestHandler implements EntityCallBack {
private final AbstractHttpClient client;
private final HttpContext context;
private final StringEntityHandler mStrEntityHandler = new StringEntityHandler();
private final FileEntityHandler mFileEntityHandler = new FileEntityHandler();
private int executionCount = 0;
private String charset;
private long time;
private String targetUrl = null; //下载的路径
private boolean isResume = false; //是否断点续传
private IPublishProgressAble<Object> procCallback;//用于回调通知目前的进度
public SyncRequestHandler(AbstractHttpClient client, HttpContext context, String charset) {
this.client = client;
this.context = context;
this.charset = charset;
}
public SyncRequestHandler(AbstractHttpClient client, HttpContext context,
String charset, IPublishProgressAble<Object> procCallback) {
this.client = client;
this.context = context;
this.charset = charset;
this.procCallback = procCallback;
}
/**
* 执行http请求
* @param params 第一个参数是HttpUriRequest,后面两个参数用于支持断点续传
* @return
* @author zhangyz created on 2013-5-15
*/
public Object sendRequest (Object... params) {
if(params!=null && params.length == 3){
targetUrl = String.valueOf(params[1]);
isResume = (Boolean) params[2];
}
try {
return makeRequestWithRetries((HttpUriRequest)params[0]);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private Object makeRequestWithRetries(HttpUriRequest request) throws IOException {
if (isResume && targetUrl != null) {
File downloadFile = new File(targetUrl);
long fileLen = 0;
if (downloadFile.isFile() && downloadFile.exists()) {
fileLen = downloadFile.length();
}
if (fileLen > 0)
request.setHeader("RANGE", "bytes=" + fileLen + "-");
}
boolean retry = true;
IOException cause = null;
HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler();
while (retry) {
try {
HttpResponse response = client.execute(request, context);
return handleResponse(response);
}
catch (UnknownHostException e) {
cause = new IOException("unknownHostException:can't resolve host" + e.getMessage());
break;
}
catch (IOException e) {
cause = e;
retry = retryHandler.retryRequest(cause, ++executionCount, context);
}
catch (NullPointerException e) {
// HttpClient 4.0.x 之前的一个bug
// http://code.google.com/p/android/issues/detail?id=5255
cause = new IOException("NPE in HttpClient" + e.getMessage());
retry = retryHandler.retryRequest(cause, ++executionCount, context);
}
catch (Exception e) {
cause = new IOException("Exception" + e.getMessage());
retry = retryHandler.retryRequest(cause, ++executionCount, context);
}
}
if (cause != null)
throw cause;
else
throw new IOException("未知网络错误");
}
private Object handleResponse(HttpResponse response) throws Exception {
StatusLine status = response.getStatusLine();
if (status.getStatusCode() >= 300) {
String errorMsg = "response status error code:" + status.getStatusCode();
if (status.getStatusCode() == 416 && isResume) {
errorMsg += " \n maybe you have download complete.";
}
throw new HttpResponseException(status.getStatusCode(), status.getReasonPhrase() + "-" + errorMsg);
}
else {
HttpEntity entity = response.getEntity();
Object responseBody = null;
if (entity != null) {
time = SystemClock.uptimeMillis();
if (targetUrl != null) {
responseBody = mFileEntityHandler.handleEntity(entity, this, targetUrl, isResume);
}
else {
responseBody = mStrEntityHandler.handleEntity(entity, this, charset);
}
}
return responseBody;
}
}
@Override
public void callBack(long count, long current, boolean mustNoticeUI) {
if (procCallback != null && procCallback.isProgress()) {
if (mustNoticeUI) {
procCallback.publishProgressByService(count, current);
}
else {
long thisTime = SystemClock.uptimeMillis();
if (thisTime - time >= procCallback.getRate()) {
time = thisTime;
procCallback.publishProgressByService(count, current);
}
}
}
}
}