package com.ta.util.http;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.http.HttpResponse;
import org.apache.http.conn.ConnectTimeoutException;
import com.ta.exception.FileAlreadyExistException;
import com.ta.util.TALogger;
import android.os.Message;
import android.util.Log;
public class FileHttpResponseHandler extends AsyncHttpResponseHandler
{
public final static int TIME_OUT = 30000;
private final static int BUFFER_SIZE = 1024 * 8;
private static final String TAG = "FileHttpResponseHandler";
private static final String TEMP_SUFFIX = ".download";
private File file;
private File tempFile;
private File baseDirFile;
private RandomAccessFile outputStream;
private long downloadSize;
private long previousFileSize;
private long totalSize;
private long networkSpeed;
private long previousTime;
private long totalTime;
private boolean interrupt = false;
private boolean timerInterrupt = false;
private String url;
private Timer timer = new Timer();
private static final int TIMERSLEEPTIME = 100;
public FileHttpResponseHandler(String url, String rootFile, String fileName)
{
super();
this.url = url;
this.baseDirFile = new File(rootFile);
this.file = new File(rootFile, fileName);
this.tempFile = new File(rootFile, fileName + TEMP_SUFFIX);
init();
}
public FileHttpResponseHandler(String rootFile, String fileName)
{
super();
this.baseDirFile = new File(rootFile);
this.file = new File(rootFile, fileName);
this.tempFile = new File(rootFile, fileName + TEMP_SUFFIX);
init();
}
public FileHttpResponseHandler(String filePath)
{
super();
this.file = new File(filePath);
this.baseDirFile = new File(this.file.getParent());
this.tempFile = new File(filePath + TEMP_SUFFIX);
init();
}
private void init()
{
// TODO Auto-generated method stub
if (!this.baseDirFile.exists())
{
this.baseDirFile.mkdirs();
}
}
private void startTimer()
{
timer.schedule(new TimerTask()
{
@Override
public void run()
{
// TODO Auto-generated method stub
while (!timerInterrupt)
{
sendProgressMessage(totalSize, getDownloadSize(),
networkSpeed);
try
{
Thread.sleep(TIMERSLEEPTIME);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}, 0, 1000);
}
private void stopTimer()
{
timerInterrupt = true;
}
public File getFile()
{
return file;
}
public String getUrl()
{
return url;
}
private class ProgressReportingRandomAccessFile extends RandomAccessFile
{
private int progress = 0;
public ProgressReportingRandomAccessFile(File file, String mode)
throws FileNotFoundException
{
super(file, mode);
}
@Override
public void write(byte[] buffer, int offset, int count)
throws IOException
{
super.write(buffer, offset, count);
progress += count;
totalTime = System.currentTimeMillis() - previousTime;
downloadSize = progress + previousFileSize;
if (totalTime > 0)
{
networkSpeed = (long) ((progress / totalTime)/1.024);
}
}
}
public boolean isInterrupt()
{
return interrupt;
}
public void setInterrupt(boolean interrupt)
{
this.interrupt = interrupt;
}
public long getDownloadSize()
{
return downloadSize;
}
public long getTotalSize()
{
return totalSize;
}
public double getDownloadSpeed()
{
return this.networkSpeed;
}
public void setPreviousFileSize(long previousFileSize)
{
this.previousFileSize = previousFileSize;
}
public long getTotalTime()
{
return this.totalTime;
}
public void onSuccess(byte[] binaryData)
{
onSuccess(new String(binaryData));
}
public void onSuccess(int statusCode, byte[] binaryData)
{
onSuccess(binaryData);
}
public void onFailure(Throwable error, byte[] binaryData)
{
onFailure(error);
}
protected void sendSuccessMessage(int statusCode, byte[] responseBody)
{
sendMessage(obtainMessage(SUCCESS_MESSAGE, new Object[]
{ statusCode, responseBody }));
}
@Override
protected void sendFailureMessage(Throwable e, byte[] responseBody)
{
sendMessage(obtainMessage(FAILURE_MESSAGE, new Object[]
{ e, responseBody }));
}
protected void sendProgressMessage(long totalSize, long currentSize,
long speed)
{
sendMessage(obtainMessage(PROGRESS_MESSAGE, new Object[]
{ totalSize, currentSize, speed }));
}
protected void handleSuccessMessage(int statusCode, byte[] responseBody)
{
onSuccess(statusCode, responseBody);
}
protected void handleFailureMessage(Throwable e, byte[] responseBody)
{
onFailure(e, responseBody);
}
@Override
protected void handleMessage(Message msg)
{
Object[] response;
switch (msg.what)
{
case SUCCESS_MESSAGE:
response = (Object[]) msg.obj;
handleSuccessMessage(((Integer) response[0]).intValue(),
(byte[]) response[1]);
break;
default:
super.handleMessage(msg);
break;
}
}
@Override
protected void sendResponseMessage(HttpResponse response)
{
Throwable error = null;
byte[] responseBody = null;
long result = -1;
int statusCode = 0;
// previousTime = System.currentTimeMillis();
try
{
statusCode = response.getStatusLine().getStatusCode();
long contentLenght = response.getEntity().getContentLength();
// -1的解决方式ContentLength 在手机访问的时候出现了问题,返回为-1
if (contentLenght == -1)
{
contentLenght = response.getEntity().getContent().available();
}
totalSize = contentLenght + previousFileSize;
TALogger.v(TAG, "totalSize: " + totalSize);
if (file.exists() && totalSize == file.length())
{
TALogger.v(TAG,
"Output file already exists. Skipping download.");
throw new FileAlreadyExistException(
"Output file already exists. Skipping download.");
} else if (tempFile.exists())
{
// response.addHeader("Range", "bytes=" + tempFile.length()
// +
// "-");
TALogger.v(TAG, "yahooo: "
+ response.getEntity().getContentLength());
previousFileSize = tempFile.length();
TALogger.v(TAG, "File is not complete, download now.");
TALogger.v(TAG, "File length:" + tempFile.length()
+ " totalSize:" + totalSize);
}
outputStream = new ProgressReportingRandomAccessFile(tempFile, "rw");
InputStream input = response.getEntity().getContent();
startTimer();
int bytesCopied = copy(input, outputStream);
if ((previousFileSize + bytesCopied) != totalSize
&& totalSize != -1 && !interrupt)
{
throw new IOException("Download incomplete: " + bytesCopied
+ " != " + totalSize);
}
TALogger.v(TAG, "Download completed successfully.");
result = bytesCopied;
} catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
sendFailureMessage(e, responseBody);
error = e;
} catch (FileAlreadyExistException e)
{
// TODO Auto-generated catch block
// sendSuccessMessage(statusCode, e.getMessage().getBytes());
error = e;
} catch (IllegalStateException e)
{
// TODO Auto-generated catch block
error = e;
// sendFailureMessage(e, responseBody);
} catch (IOException e)
{
// TODO Auto-generated catch block
// sendFailureMessage(e, responseBody);
error = e;
}
// 停止打印
stopTimer();
// 保证timer被关闭
try
{
Thread.sleep(TIMERSLEEPTIME);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
if (result == -1 || interrupt || error != null)
{
if (error != null)
{
Log.v(TAG, "Download failed." + error.getMessage());
if (error instanceof FileAlreadyExistException)
{
sendSuccessMessage(statusCode, "下载成功!".getBytes());
} else
{
sendFailureMessage(error, responseBody);
}
}
return;
}
tempFile.renameTo(file);
sendSuccessMessage(statusCode, "下载成功!".getBytes());
}
public int copy(InputStream input, RandomAccessFile out) throws IOException
{
if (input == null || out == null)
{
return -1;
}
byte[] buffer = new byte[BUFFER_SIZE];
BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
TALogger.v(TAG, "length" + out.length());
int count = 0, n = 0;
long errorBlockTimePreviousTime = -1, expireTime = 0;
try
{
out.seek(out.length());
previousTime = System.currentTimeMillis();
while (!interrupt)
{
n = in.read(buffer, 0, BUFFER_SIZE);
if (n == -1)
{
break;
}
out.write(buffer, 0, n);
count += n;
if (networkSpeed == 0)
{
if (errorBlockTimePreviousTime > 0)
{
expireTime = System.currentTimeMillis()
- errorBlockTimePreviousTime;
if (expireTime > TIME_OUT)
{
throw new ConnectTimeoutException(
"connection time out.");
}
} else
{
errorBlockTimePreviousTime = System.currentTimeMillis();
}
} else
{
expireTime = 0;
errorBlockTimePreviousTime = -1;
}
}
} finally
{
try
{
out.close();
// 无法关闭 inputstram
// input.close();
// in.close();
} catch (IOException e)
{
// TODO: handle exception
}
}
return count;
}
public File getTempFile()
{
// TODO Auto-generated method stub
return tempFile;
}
}