public interface HttpRequest extends Runnable {

  /**
   * This method runs asynchronously in the same thread as the application and
   * launches a service for further server communication.
   */
  void executeAsync();

  /**
   * Calling this method will prevent the callback to be executed. Good for avoiding memory leaks if you bind callbacks with views that are a part of a
   * lifecycle of an activity or fragment.
   */
  void cancel();

} public class RestClientConfiguration {

  private static Context applicationContext;
  private AuthenticationProvider authenticationProvider;
  int connectionTimeout;
  int readTimeout;
  int writeTimeout;

  private RestClientConfiguration(AuthenticationProvider authenticationProvider, int connectionTimeout, int readTimeout, int writeTimeout) {
    this.authenticationProvider = authenticationProvider;
    this.connectionTimeout = connectionTimeout;
    this.readTimeout = readTimeout;
    this.writeTimeout = writeTimeout;
  }

  private static RestClientConfiguration generateDefaultConfig() {
    return new ConfigurationBuilder().create();
  }

  private static RestClientConfiguration instance;

  public static void init(Context context) {
    applicationContext = context.getApplicationContext();
    AsyncRunners.init(applicationContext);
    instance = generateDefaultConfig();
  }

  public static void init(Context context, RestClientConfiguration restClientConfiguration) {
    applicationContext = context.getApplicationContext();
    AsyncRunners.init(applicationContext);
    instance = restClientConfiguration;
  }

  public static RestClientConfiguration get() {
    if (instance == null) {
      throw new IllegalStateException("You need to call Init on " + RestClientConfiguration.class + " First. Do it in your class extending application");
    }
    return instance;
  }


  public AuthenticationProvider getAuthenticationProvider() {
    return authenticationProvider;
  }

  public int getConnectionTimeout() {
    return connectionTimeout;
  }

  public int getReadTimeout() {
    return readTimeout;
  }

  public int getWriteTimeout() {
    return writeTimeout;
  }

  public Context getContext() {
    return applicationContext;
  }

  public static class ConfigurationBuilder {
    private AuthenticationProvider authenticationProvider;
    private int connectionTimeout = 10000;
    private int readTimeout = 20000;
    private int writeTimeout = 20000;

    public ConfigurationBuilder setAuthenticationProvider(AuthenticationProvider authenticationProvider) {
      this.authenticationProvider = authenticationProvider;
      return this;
    }

    public ConfigurationBuilder setConnectionTimeout(int connectionTimeout) {
      this.connectionTimeout = connectionTimeout;
      return this;
    }

    public ConfigurationBuilder setReadTimeout(int readTimeout) {
      this.readTimeout = readTimeout;
      return this;
    }

    public ConfigurationBuilder setWriteTimeout(int writeTimeout) {
      this.writeTimeout = writeTimeout;
      return this;
    }

    public RestClientConfiguration create() {
      return new RestClientConfiguration(authenticationProvider, connectionTimeout, readTimeout, writeTimeout);
    }
  }
} public interface AuthenticationProvider {

  public void authenticateRequest(RestClientRequest restClientRequest);
} public class ActivityBoundHttpCallback<T> extends BoundCallback<T> {

  private static final String TAG = ActivityBoundHttpCallback.class.getSimpleName();
  WeakReference<Activity> activityWeakReference;

  public ActivityBoundHttpCallback(Activity activity, HttpCallback<T> callback) {
    super(callback);
    this.activityWeakReference = new WeakReference<>(activity);
  }

  @Override
  public boolean isRegistered() {
    Activity activity = activityWeakReference.get();
    return activity != null && activity.isFinishing() == false;
  }

} public class BoundCallback<T> implements HttpCallback<T> {

  private static final String TAG = BoundCallback.class.getSimpleName();
  private HttpCallback<T> callback;
  private boolean isRegistered = true;

  public BoundCallback(HttpCallback<T> callback) {
    this.callback = callback;
  }

  public void unregister() {
    isRegistered = false;
  }

  public boolean isRegistered() {
    return isRegistered;
  }

  @Override
  public void onSuccess(T responseData, ResponseStatus responseStatus) {
    if (isRegistered) {
      callback.onSuccess(responseData, responseStatus);
    } else {
      Log.d(TAG, "callback is unregistered, wont be called");
    }
  }

  @Override
  public void onHttpError(ResponseStatus responseStatus) {
    if (isRegistered) {
      callback.onHttpError(responseStatus);
    } else {
      Log.d(TAG, "callback is unregistered, wont be called");
    }
  }

} public class FragmentBoundHttpCallback<T> extends BoundCallback<T> {

  private static final String TAG = FragmentBoundHttpCallback.class.getSimpleName();
  WeakReference<Fragment> fragmentWeakReference;

  public FragmentBoundHttpCallback(Fragment fragment, HttpCallback<T> callback) {
    super(callback);
    this.fragmentWeakReference = new WeakReference<>(fragment);
  }

  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  @Override
  public boolean isRegistered() {
    Fragment fragment = fragmentWeakReference.get();
    return fragment != null && fragment.isAdded() && fragment.isInLayout();
  }
} public interface HttpCallback<T> {

  /**
   * This method shows that the callback successfully finished. It contains
   * response data which represents the return type of the callback.
   * 
   * @param responseData
   *          It can be of any type.
   */
  void onSuccess(T responseData, ResponseStatus responseStatus);

  /**
   * This method shows that the callback has failed due to server issue, no
   * connectivity or parser error
   * 
   * @param responseStatus
   */
  void onHttpError(ResponseStatus responseStatus);

} public enum RequestMethod {
  GET, POST, PUT, PATCH, DELETE;
} public class ResponseStatus {

  public static final String TAG = ResponseStatus.class.getSimpleName();

  private int statusCode;
  private String statusMessage;

  public ResponseStatus(int statusCode, String statusMessage) {
    this.statusCode = statusCode;
    this.statusMessage = statusMessage;
  }

  public ResponseStatus() {
  }

  public int getStatusCode() {
    return statusCode;
  }

  public void setStatusCode(int statusCode) {
    this.statusCode = statusCode;
  }

  public String getStatusMessage() {
    return statusMessage;
  }

  public void setStatusMessage(String statusMessage) {
    this.statusMessage = statusMessage;
  }

  public static ResponseStatus getConnectionErrorStatus() {
    ResponseStatus status = new ResponseStatus();
    status.setStatusCode(HttpStatus.SC_REQUEST_TIMEOUT);
    status.setStatusMessage("HTTP Connection Error");
    return status;
  }

  public static ResponseStatus getParseErrorStatus() {
    ResponseStatus status = new ResponseStatus();
    status.setStatusCode(HttpStatus.SC_BAD_REQUEST);
    status.setStatusMessage("Parser Error");
    return status;
  }

  @Override
  public String toString() {
    StringBuilder builder = new StringBuilder();
    builder.append("ResponseStatus [statusCode=");
    builder.append(statusCode);
    builder.append(", statusMessage=");
    builder.append(statusMessage);
    builder.append("]");
    return builder.toString();
  }

} public class DefaultResponseStatusHandler implements ResponseStatusHandler {

  public DefaultResponseStatusHandler() {
    super();
  }

  @Override
  public boolean hasErrorInStatus(ResponseStatus status) {
    return (status.getStatusCode() < 200 || status.getStatusCode() >= 300);
  }

} public interface ResponseHandler<T> {

  public HttpCallback<T> getCallback();

  public void handleSuccess(final T responseData, ResponseStatus status);

  public void handleError(final ResponseStatus status);
} public interface ResponseStatusHandler {

  public boolean hasErrorInStatus(ResponseStatus status);

} public class UIThreadResponseHandler<T> extends BackgroundThreadResponseHandler<T>
    implements ResponseHandler<T> {

  public static final String TAG = UIThreadResponseHandler.class.getSimpleName();
  protected static Handler handler;

  public UIThreadResponseHandler(HttpCallback<T> callback) {
    super(callback);
    if (handler == null) {
      handler = new Handler(Looper.getMainLooper());
    }
  }

  @Override
  public void handleSuccess(final T responseData, final ResponseStatus status) {
    handler.post(new Runnable() {

      @Override
      public void run() {
        if (callback != null) {
          callback.onSuccess(responseData, status);
        }
      }
    });
  }

  @Override
  public void handleError(final ResponseStatus status) {
    handler.post(new Runnable() {

      @Override
      public void run() {
        if (callback != null) {
          callback.onHttpError(status);
        }
      }
    });
  }
} public interface HttpResponseParser<T> {

  /**
   * This method is used for parsing JSON response from server. Given a JSON
   * string, returns response data which can be of any type.
   * 
   * @param instream
   *          The JSON string needed for parsing.
   * @return Object of any type returned by the parser.
   * @throws Exception
   *           Thrown when various parsing errors occur.
   */
  public T parse(final InputStream instream) throws Exception;
}
import android.app.Activity;
import android.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
import com.araneaapps.android.libs.asyncrunners.models.RequestOptions;
import com.araneaapps.android.libs.asyncrunners.models.TaskStore;
import com.dg.libs.rest.HttpRequest;
import com.dg.libs.rest.RestClientConfiguration;
import com.dg.libs.rest.authentication.AuthenticationProvider;
import com.dg.libs.rest.callbacks.ActivityBoundHttpCallback;
import com.dg.libs.rest.callbacks.BoundCallback;
import com.dg.libs.rest.callbacks.FragmentBoundHttpCallback;
import com.dg.libs.rest.callbacks.HttpCallback;
import com.dg.libs.rest.client.RequestMethod;
import com.dg.libs.rest.domain.ResponseStatus;
import com.dg.libs.rest.handlers.DefaultResponseStatusHandler;
import com.dg.libs.rest.handlers.ResponseHandler;
import com.dg.libs.rest.handlers.ResponseStatusHandler;
import com.dg.libs.rest.handlers.UIThreadResponseHandler;
import com.dg.libs.rest.parsers.HttpResponseParser;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;
package com.dg.libs.rest.requests;




public abstract class RestClientRequest<T> implements HttpRequest {

  private String TAG = RestClientRequest.class.getSimpleName();

  private HttpResponseParser<T> parser;
  private ResponseHandler<T> handler;
  private ResponseStatusHandler statusHandler;
  private BoundCallback<T> callback;
  private Request.Builder request = new Request.Builder();
  private StringBuilder queryParams;
  private String url;

  RequestOptions requestOptions = null;
  AuthenticationProvider authenticationProvider;

  protected RestClientRequest() {
    authenticationProvider = RestClientConfiguration.get().getAuthenticationProvider();
  }

  public RestClientRequest<T> setAuthenticationProvider(AuthenticationProvider authenticationProvider) {
    this.authenticationProvider = authenticationProvider;
    return this;
  }

  protected HttpCallback<T> getCallback() {
    return callback;
  }

  public RestClientRequest<T> setCallback(HttpCallback<T> callback) {
    BoundCallback<T> boundCallback = new BoundCallback<>(callback);
    this.callback = boundCallback;
    return this;
  }

  public RestClientRequest<T> setActivityBoundCallback(Activity activity, HttpCallback<T> callback) {
    this.callback = new ActivityBoundHttpCallback<>(activity, callback);