All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mle.android.http.FutureHttpClient.scala Maven / Gradle / Ivy

The newest version!
package com.mle.android.http

import java.io.{Closeable, File}

import com.loopj.android.http._
import com.mle.android.exceptions.{NotFoundHttpException, UnauthorizedHttpException}
import com.mle.android.util.UtilLog
import com.mle.concurrent.ExecutionContexts.cached
import com.mle.concurrent.Futures
import org.apache.http.Header
import org.apache.http.client.HttpResponseException

import scala.concurrent.{Future, Promise}
import scala.util.Try

/**
 *
 * @author mle
 */
trait FutureHttpClient extends UtilLog with Closeable {
  val httpClient = new AsyncHttpClient()
  httpClient setSSLSocketFactory MySslSocketFactory.allowAllCertificatesSocketFactory()

  //  the max parallel connections count seems capped at 10 per client, and none of the following have an effect on that
  //  httpClient setThreadPool Executors.newCachedThreadPool().asInstanceOf[ThreadPoolExecutor]
  //  httpClient setMaxConnections 256
  //  ConnManagerParams.setMaxTotalConnections(httpClient.getHttpClient.getParams, 256)

  def addHeaders(headers: (String, String)*) = headers.foreach {
    case (key, value) => httpClient.addHeader(key, value)
  }

  /**
   * Gets called before the request is executed.
   *
   * The default implementation trivially returns `uri`.
   *
   * @param uri the user-supplied uri string
   * @return the uri actually used in the request
   */
  def transformUri(uri: String): String = uri

  def getEmpty(uri: String) = get(uri).map(_ => ())

  /**
   * GETs `uri`.
   *
   * The returned [[Future]] fails with an [[java.io.IOException]] if the server cannot be reached, an
   * [[UnauthorizedHttpException]] if authentication fails and a [[NotFoundHttpException]] if the server responds with a
   * 404. For other errors it may fail with a [[HttpResponseException]] containing the appropriate error code.
   *
   * @param uri request uri
   * @return the HTTP response following a successful request
   */
  def get(uri: String): Future[HttpResponse] = get(uri, textResponseHandler)

  def get[T](uri: String, f: Promise[T] => AsyncHttpResponseHandler): Future[T] =
    Futures.promisedFuture[T](p => httpClient.get(transformUri(uri), f(p)))

  def getFile(uri: String, file: File): Future[File] = get[File](uri, p => fileResponseHandler(file, p))

  def postFile(resource: String, file: File): Future[HttpResponse] = postFile(resource, file, textResponseHandler)

  /**
   * Performs a multipart/form-data upload of `file`.
   *
   * @param file file to upload
   */
  def postFile[T](uri: String, file: File, f: Promise[T] => AsyncHttpResponseHandler): Future[T] =
    Futures.promisedFuture[T](p => {
      val params = new RequestParams()
      params.put("file", file)
      httpClient.post(transformUri(uri), params, f(p))
    })

  def textResponseHandler(promise: Promise[HttpResponse]) = new TextHttpResponseHandler() {
    override def onSuccess(statusCode: Int, headers: Array[Header], responseString: String): Unit = {
      promise success HttpResponse(statusCode, Option(responseString))
    }

    override def onFailure(statusCode: Int, headers: Array[Header], responseString: String, throwable: Throwable): Unit = {
      promise failure handleFailure(throwable, Option(responseString))
    }
  }

  def fileResponseHandler(file: File, promise: Promise[File]) = new FileAsyncHttpResponseHandler(file) {
    override def onSuccess(statusCode: Int, headers: Array[Header], file: File): Unit = {
      promise success file
    }

    override def onFailure(statusCode: Int, headers: Array[Header], throwable: Throwable, file: File): Unit = {
      promise failure handleFailure(throwable, None)
    }
  }

  def handleFailure(t: Throwable, maybeContent: Option[String]): Throwable =
    httpFailureHandler.applyOrElse(t, (fail: Throwable) => fail)

  val httpFailureRefiner: PartialFunction[Throwable, Throwable] = {
    case hre: HttpResponseException if hre.getStatusCode == HttpConstants.UNAUTHORIZED =>
      new UnauthorizedHttpException(hre)
    case hre: HttpResponseException if hre.getStatusCode == HttpConstants.NOT_FOUND =>
      new NotFoundHttpException(hre)
  }
  val passThroughHandler: PartialFunction[Throwable, Throwable] = {
    case t: Throwable => t
  }
  val httpFailureHandler = httpFailureRefiner orElse passThroughHandler

  override def close(): Unit =
    Try(httpClient.getHttpClient.getConnectionManager.shutdown())
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy