com.koushikdutta.ion.IonRequestBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ion Show documentation
Show all versions of ion Show documentation
Android Asynchronous Networking Made Easy
package com.koushikdutta.ion;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ProgressDialog;
import android.app.Service;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.util.Base64;
import android.widget.ImageView;
import android.widget.ProgressBar;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.koushikdutta.async.AsyncServer;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.DataSink;
import com.koushikdutta.async.DataTrackingEmitter;
import com.koushikdutta.async.DataTrackingEmitter.DataTracker;
import com.koushikdutta.async.FilteredDataEmitter;
import com.koushikdutta.async.Util;
import com.koushikdutta.async.callback.CompletedCallback;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.async.future.SimpleFuture;
import com.koushikdutta.async.future.TransformFuture;
import com.koushikdutta.async.http.AsyncHttpGet;
import com.koushikdutta.async.http.AsyncHttpPost;
import com.koushikdutta.async.http.AsyncHttpRequest;
import com.koushikdutta.async.http.Multimap;
import com.koushikdutta.async.http.body.AsyncHttpRequestBody;
import com.koushikdutta.async.http.body.DocumentBody;
import com.koushikdutta.async.http.body.FileBody;
import com.koushikdutta.async.http.body.FilePart;
import com.koushikdutta.async.http.body.MultipartFormDataBody;
import com.koushikdutta.async.http.body.StreamBody;
import com.koushikdutta.async.http.body.StringBody;
import com.koushikdutta.async.http.body.UrlEncodedFormBody;
import com.koushikdutta.async.http.libcore.RawHeaders;
import com.koushikdutta.async.http.server.AsyncHttpServer;
import com.koushikdutta.async.parser.AsyncParser;
import com.koushikdutta.async.parser.DocumentParser;
import com.koushikdutta.async.parser.StringParser;
import com.koushikdutta.async.stream.FileDataSink;
import com.koushikdutta.async.stream.OutputStreamDataSink;
import com.koushikdutta.ion.Loader.LoaderEmitter;
import com.koushikdutta.ion.builder.Builders;
import com.koushikdutta.ion.builder.FutureBuilder;
import com.koushikdutta.ion.builder.LoadBuilder;
import com.koushikdutta.ion.future.ResponseFuture;
import com.koushikdutta.ion.gson.GsonBody;
import com.koushikdutta.ion.gson.GsonParser;
import com.koushikdutta.ion.gson.GsonSerializer;
import com.koushikdutta.ion.gson.PojoBody;
import org.apache.http.NameValuePair;
import org.w3c.dom.Document;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by koush on 5/21/13.
*/
class IonRequestBuilder implements Builders.Any.B, Builders.Any.F, Builders.Any.M, Builders.Any.U, LoadBuilder {
Ion ion;
WeakReference context;
Handler handler = Ion.mainHandler;
String method = AsyncHttpGet.METHOD;
String uri;
public IonRequestBuilder(Context context, Ion ion) {
this.ion = ion;
this.context = new WeakReference(context);
}
@Override
public IonRequestBuilder load(String url) {
return loadInternal(AsyncHttpGet.METHOD, url);
}
private IonRequestBuilder loadInternal(String method, String url) {
this.method = method;
this.uri = url;
return this;
}
boolean methodWasSet;
@Override
public IonRequestBuilder load(String method, String url) {
methodWasSet = true;
return loadInternal(method, url);
}
RawHeaders headers;
private RawHeaders getHeaders() {
if (headers == null) {
headers = new RawHeaders();
AsyncHttpRequest.setDefaultHeaders(headers, uri == null ? null : URI.create(uri));
}
return headers;
}
@Override
public IonRequestBuilder userAgent(String userAgent) {
return setHeader("User-Agent", userAgent);
}
@Override
public IonRequestBuilder setHeader(String name, String value) {
getHeaders().set(name, value);
return this;
}
@Override
public IonRequestBuilder addHeader(String name, String value) {
getHeaders().add(name, value);
return this;
}
boolean noCache;
@Override
public Builders.Any.B noCache() {
noCache = true;
return setHeader("Cache-Control", "no-cache");
}
Multimap query;
@Override
public IonRequestBuilder addQuery(String name, String value) {
if (query == null)
query = new Multimap();
query.add(name, value);
return this;
}
@Override
public IonRequestBuilder addQueries(Map> params) {
if (query == null)
query = new Multimap();
query.putAll(params);
return this;
}
int timeoutMilliseconds = AsyncHttpRequest.DEFAULT_TIMEOUT;
@Override
public IonRequestBuilder setTimeout(int timeoutMilliseconds) {
this.timeoutMilliseconds = timeoutMilliseconds;
return this;
}
@Override
public IonRequestBuilder setHandler(Handler handler) {
this.handler = handler;
return this;
}
AsyncHttpRequestBody body;
private IonRequestBuilder setBody(AsyncHttpRequestBody body) {
if (!methodWasSet)
method = AsyncHttpPost.METHOD;
this.body = body;
return this;
}
@Override
public IonRequestBuilder setJsonObjectBody(JsonObject jsonObject) {
return setBody(new GsonBody(ion.configure().getGson(), jsonObject));
}
@Override
public IonRequestBuilder setJsonArrayBody(JsonArray jsonArray) {
return setBody(new GsonBody(ion.configure().getGson(), jsonArray));
}
@Override
public IonRequestBuilder setStringBody(String string) {
return setBody(new StringBody(string));
}
boolean followRedirect = true;
@Override
public IonRequestBuilder followRedirect(boolean follow) {
followRedirect = follow;
return this;
}
private static boolean isServiceRunning(Service candidate) {
ActivityManager manager = (ActivityManager)candidate.getSystemService(Context.ACTIVITY_SERVICE);
List services = manager.getRunningServices(Integer.MAX_VALUE);
if (services == null)
return false;
for (ActivityManager.RunningServiceInfo service: services) {
if (candidate.getClass().getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
static boolean checkContext(WeakReference contextWeakReference) {
Context context = contextWeakReference.get();
if (context == null)
return false;
return checkContext(context);
}
static boolean checkContext(Context context) {
if (context instanceof Activity) {
Activity activity = (Activity)context;
if (activity.isFinishing())
return false;
}
else if (context instanceof Service) {
Service service = (Service)context;
if (!isServiceRunning(service))
return false;
}
return true;
}
private boolean checkContext() {
return checkContext(context);
}
private void postExecute(final EmitterTransform future, final Exception ex, final T value) {
final Runnable runner = new Runnable() {
@Override
public void run() {
// check if the context is still alive...
if (!checkContext()) {
future.initialRequest.logd("context has died");
return;
}
// unless we're invoked onto the handler/main/service thread, there's no frakking way to avoid a
// race condition where the service or activity dies before this callback is invoked.
if (ex != null)
future.setComplete(ex);
else
future.setComplete(value);
}
};
if (handler == null)
ion.httpClient.getServer().post(runner);
else
AsyncServer.post(handler, runner);
}
private URI prepareURI() {
URI uri;
try {
if (query != null) {
Uri.Builder builder = Uri.parse(this.uri).buildUpon();
for (String key: query.keySet()) {
for (String value: query.get(key)) {
builder = builder.appendQueryParameter(key, value);
}
}
uri = URI.create(builder.toString());
}
else {
uri = URI.create(this.uri);
}
}
catch (Exception e) {
uri = null;
}
if (uri == null || uri.getScheme() == null)
return null;
return uri;
}
private AsyncHttpRequest prepareRequest(URI uri, AsyncHttpRequestBody wrappedBody) {
AsyncHttpRequest request = ion.configure().getAsyncHttpRequestFactory().createAsyncHttpRequest(uri, method, headers);
request.setFollowRedirect(followRedirect);
request.setBody(wrappedBody);
request.setLogging(ion.logtag, ion.logLevel);
if (logTag != null)
request.setLogging(logTag, logLevel);
request.enableProxy(proxyHost, proxyPort);
request.setTimeout(timeoutMilliseconds);
request.logd("preparing request");
return request;
}
static interface LoadRequestCallback {
boolean loadRequest(AsyncHttpRequest request);
}
LoadRequestCallback loadRequestCallback;
private void getLoaderEmitter(final EmitterTransform ret) {
URI uri = prepareURI();
if (uri == null) {
ret.setComplete(new Exception("Invalid URI"));
return;
}
AsyncHttpRequestBody wrappedBody = body;
if (uploadProgressHandler != null || uploadProgressBar != null || uploadProgress != null || uploadProgressDialog != null) {
wrappedBody = new RequestBodyUploadObserver(body, new ProgressCallback() {
@Override
public void onProgress(final int downloaded, final int total) {
assert Thread.currentThread() != Looper.getMainLooper().getThread();
final int percent = (int)((float)downloaded / total * 100f);
if (uploadProgressBar != null)
uploadProgressBar.setProgress(percent);
if (uploadProgressDialog != null)
uploadProgressDialog.setProgress(percent);
if (uploadProgress != null)
uploadProgress.onProgress(downloaded, total);
if (uploadProgressHandler != null) {
AsyncServer.post(Ion.mainHandler, new Runnable() {
@Override
public void run() {
if (ret.isCancelled() || ret.isDone())
return;
uploadProgressHandler.onProgress(downloaded, total);
}
});
}
}
});
}
AsyncHttpRequest request = prepareRequest(uri, wrappedBody);
ret.initialRequest = request;
resolveAndLoadRequest(request, ret);
}
void resolveAndLoadRequest(final AsyncHttpRequest request, final EmitterTransform ret) {
Future resolved = resolveRequest(request, ret);
if (resolved != null) {
resolved.setCallback(new FutureCallback() {
@Override
public void onCompleted(Exception e, final AsyncHttpRequest result) {
if (e != null) {
ret.setComplete(e);
return;
}
ret.finalRequest = result;
resolveAndLoadRequest(result, ret);
}
});
return;
}
if (Looper.getMainLooper().getThread() != Thread.currentThread()) {
AsyncServer.post(Ion.mainHandler, new Runnable() {
@Override
public void run() {
invokeLoadRequest(request, ret);
}
});
return;
}
invokeLoadRequest(request, ret);
}
void invokeLoadRequest(final AsyncHttpRequest request, final EmitterTransform ret) {
if (loadRequestCallback == null || loadRequestCallback.loadRequest(request))
loadRequest(request, ret);
}
void loadRequest(AsyncHttpRequest request, final EmitterTransform ret) {
// now attempt to fetch it directly
for (Loader loader: ion.loaders) {
Future emitter = loader.load(ion, request, ret);
if (emitter != null) {
request.logi("Using loader: " + loader);
ret.setParent(emitter);
return;
}
}
ret.setComplete(new Exception("Unknown uri scheme"));
}
Future resolveRequest(AsyncHttpRequest request, final EmitterTransform ret) {
// first attempt to resolve the url
for (Loader loader: ion.loaders) {
Future resolved = loader.resolve(ion, request);
if (resolved != null)
return resolved;
}
return null;
}
// transforms a LoaderEmitter, which is a DataEmitter and all associated properties about the data source
// into the final result.
class EmitterTransform extends TransformFuture implements ResponseFuture {
AsyncHttpRequest initialRequest;
AsyncHttpRequest finalRequest;
int loadedFrom;
Runnable cancelCallback;
RawHeaders headers;
DataEmitter emitter;
@Override
public Future> withResponse() {
final SimpleFuture> ret = new SimpleFuture>();
setCallback(new FutureCallback() {
@Override
public void onCompleted(Exception e, T result) {
if (emitter != null) {
Response response = new Response();
response.headers = headers;
response.request = finalRequest;
response.result = result;
response.exception = e;
ret.setComplete(response);
return;
}
ret.setComplete(e, null);
}
});
ret.setParent(this);
return ret;
}
public int loadedFrom() {
return loadedFrom;
}
public EmitterTransform(Runnable cancelCallback) {
this.cancelCallback = cancelCallback;
ion.addFutureInFlight(this, context.get());
if (groups == null)
return;
for (WeakReference
© 2015 - 2025 Weber Informatics LLC | Privacy Policy