//
// Copyright (c) 2014 VK.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
package com.vk.sdk.api.httpClient;
import com.vk.sdk.api.VKError;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.zip.GZIPInputStream;
/**
* Class for loading any data by HTTP request
*/
public class VKHttpOperation extends VKAbstractOperation {
/**
* Request initialized this object
*/
private final HttpUriRequest mUriRequest;
/**
* Last exception throws while loading or parsing
*/
protected Exception mLastException;
/**
* Bytes of HTTP response
*/
private byte[] mResponseBytes;
/**
* Stream for output result of HTTP loading
*/
public OutputStream outputStream;
/**
* Standard HTTP response
*/
public HttpResponse response;
/**
* String representation of response
*/
private String mResponseString;
/**
* Create new operation for loading prepared Http request. Requests may be prepared in VKHttpClient
*
* @param uriRequest Prepared request
*/
public VKHttpOperation(HttpUriRequest uriRequest) {
mUriRequest = uriRequest;
}
/**
* Start current prepared http-operation for result
*/
@Override
public void start() {
setState(VKOperationState.Executing);
try {
if (mUriRequest.isAborted()) return;
response = VKHttpClient.getClient().execute(mUriRequest);
InputStream inputStream = response.getEntity().getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
inputStream = new GZIPInputStream(inputStream);
}
if (outputStream == null) {
outputStream = new ByteArrayOutputStream();
}
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1)
outputStream.write(buffer, 0, bytesRead);
inputStream.close();
outputStream.flush();
if (outputStream instanceof ByteArrayOutputStream) {
mResponseBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
}
outputStream.close();
} catch (Exception e) {
mLastException = e;
}
setState(VKOperationState.Finished);
}
@Override
public void finish() {
postExecution();
super.finish();
}
/**
* Calls before providing result, but after response loads
* @return true is post execution succeed
*/
protected boolean postExecution() {
return true;
}
/**
* Cancel current operation execution
*/
@Override
public void cancel() {
VKHttpClient.cancelHttpOperation(this);
super.cancel();
}
/**
* Returns request associated with current operation
* @return URI request
*/
public HttpUriRequest getUriRequest() { return mUriRequest; }
/**
* Get operation response data
* @return Bytes of response
*/
public byte[] getResponseData() {
return mResponseBytes;
}
/**
* Get operation response string, if possible
* @return Encoded string from response data bytes
*/
public String getResponseString() {
if (mResponseBytes == null)
return null;
if (mResponseString == null) {
try {
mResponseString = new String(mResponseBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
mLastException = e;
}
}
return mResponseString;
}
/**
* Generates VKError about that request fails
* @param e Exception for error
* @return New generated error
*/
protected VKError generateError(Exception e) {
VKError error;
if (state() == VKOperationState.Canceled) {
error = new VKError(VKError.VK_CANCELED);
} else {
error = new VKError(VKError.VK_REQUEST_HTTP_FAILED);
}
if (e != null) {
error.errorMessage = e.getMessage();
if (error.errorMessage == null)
error.errorMessage = e.toString();
error.httpError = e;
}
return error;
}
/**
* Set listener for current operation
* @param listener Listener subclasses VKHTTPOperationCompleteListener
*/
public void setHttpOperationListener(final VKHTTPOperationCompleteListener listener) {
this.setCompleteListener(new VKOperationCompleteListener() {
@Override
public void onComplete() {
if (VKHttpOperation.this.state() != VKOperationState.Finished || mLastException != null) {
listener.onError(VKHttpOperation.this, generateError(mLastException));
} else {
listener.onComplete(VKHttpOperation.this, mResponseBytes);
}
}
});
}
/**
* Class representing operation listener for VKHttpOperation
*/
public static abstract class VKHTTPOperationCompleteListener extends VKAbstractCompleteListener<VKHttpOperation, byte[]>
{
@Override
public void onComplete(VKHttpOperation operation, byte[] response) {
}
@Override
public void onError(VKHttpOperation operation, VKError error) {
}
}
}