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

com.thoughtworks.microbuilder.play.PlayOutgoingJsonService.scala Maven / Gradle / Ivy

The newest version!
package com.thoughtworks.microbuilder.play

import java.io.ByteArrayOutputStream

import jsonStream.io.{PrettyTextPrinter, TextParser}
import jsonStream.rpc.{IJsonResponseHandler, IJsonService}
import jsonStream.{JsonStream, JsonStreamPair}
import com.thoughtworks.microbuilder.core.{CoreSerializer, Failure => MicrobuilderFailure, IRouteConfiguration, IRouteEntry}
import haxe.io.Output
import play.api.http.{HeaderNames, Writeable}
import play.api.libs.ws.{WSAPI, WSRequest}

import scala.concurrent.ExecutionContext
import scala.util.{Failure, Success}


class PlayOutgoingJsonService(urlPrefix: String,
                              routes: IRouteConfiguration,
                              wsAPI: WSAPI, additionalRequestHeaders: (String, String)*)
                             (implicit executionContext: ExecutionContext) extends IJsonService {


  def prepareWSRequest(parameters: WrappedHaxeIterator[JsonStream], pair: JsonStreamPair): WSRequest = {
    val template: IRouteEntry = routes.nameToUriTemplate(pair.key)
    val requestData = template.render(parameters.haxeIterator)
    val request = wsAPI.url(raw"""$urlPrefix${requestData.uri}""").withMethod(requestData.httpMethod)
    val wsRequest = {
      if (parameters.hasNext) {
        val next: JsonStream = parameters.next()
        request.withBody(next)(new Writeable[JsonStream](
          { body =>
            val javaStream = new ByteArrayOutputStream()
            PrettyTextPrinter.print(new Output {
              override def writeByte(b: Int) = {
                javaStream.write(b)
              }
            }, body, 0)
            javaStream.toByteArray
          },
          Option(requestData.contentType))
        )
      } else {
        request
      }
    }
    val requestDataHeaders = for {
      header <- requestData.headers
    } yield header.name -> Option(header.value).getOrElse("")

    val headers = if (template.get_responseContentType == null) {
      requestDataHeaders ++ additionalRequestHeaders
    } else {
      ((HeaderNames.ACCEPT -> requestData.contentType) +: requestDataHeaders) ++ additionalRequestHeaders
    }
    wsRequest.withHeaders(headers: _*)
  }

  def withSerializationExceptionHandling(responseHandler: IJsonResponseHandler, body: String)(func: () => Unit): Unit = {
    try {
      func()
    } catch {
      case e: Exception =>
        val serializationFailure = CoreSerializer.dynamicSerialize(haxe.root.ValueType.TEnum(classOf[MicrobuilderFailure]),
          MicrobuilderFailure.SERIALIZATION_FAILURE("Wrong JSON format: " + body))
        responseHandler.onFailure(JsonStream.OBJECT(Iterator(serializationFailure)))
    }
  }

  def handleResponse(wsRequest: WSRequest, responseHandler: IJsonResponseHandler): Unit = {
    wsRequest.execute().onComplete { response =>
      response match {
        case Success(response) if response.status >= 200 && response.status < 400 =>
          withSerializationExceptionHandling(responseHandler, response.body) { () =>
            responseHandler.onSuccess(TextParser.parseString(response.body))
          }
        case Success(response) =>
          if (routes.get_failureClassName == null) {
            val textFailure = CoreSerializer.dynamicSerialize(
              haxe.root.ValueType.TEnum(classOf[MicrobuilderFailure]),
              MicrobuilderFailure.TEXT_APPLICATION_FAILURE(response.body, response.status))
            responseHandler.onFailure(JsonStream.OBJECT(Iterator(textFailure)))
          } else {
            withSerializationExceptionHandling(responseHandler, response.body) { () =>
              responseHandler.onFailure(
                JsonStream.OBJECT(
                  Iterator(
                    new JsonStreamPair(
                      "com.thoughtworks.microbuilder.core.Failure", JsonStream.OBJECT(
                        Iterator(
                          new JsonStreamPair(
                            "STRUCTURAL_APPLICATION_FAILURE", JsonStream.OBJECT(
                              Iterator(
                                new JsonStreamPair(
                                  "failure", JsonStream.OBJECT(
                                    Iterator(new JsonStreamPair(routes.get_failureClassName, TextParser.parseString(response.body)))
                                  )
                                ),
                                new JsonStreamPair(
                                  "status", JsonStream.INT32(response.status)
                                )
                              )
                            )
                          )
                        )
                      )
                    )
                  )
                )
              )
            }
          }
        case Failure(e) =>
          val nativeFalure = CoreSerializer.dynamicSerialize(haxe.root.ValueType.TEnum(classOf[MicrobuilderFailure]), MicrobuilderFailure.NATIVE_FAILURE(e.getMessage))
          responseHandler.onFailure(JsonStream.OBJECT(Iterator(nativeFalure)))
      }

    }
  }

  def apply(requestParameters: JsonStream, responseHandler: IJsonResponseHandler): Unit = {
    requestParameters match {
      case JsonStreamExtractor.Object(pairs) =>
        val pair = pairs.next()
        pair.value match {
          case JsonStreamExtractor.Array(parameters) =>
            val wsRequest: WSRequest = prepareWSRequest(parameters, pair)

            handleResponse(wsRequest, responseHandler)
        }
      case _ =>
        throw new IllegalArgumentException("parameter should be an array")
    }
  }

  def push(requestParameters: jsonStream.JsonStream): Unit = {
    requestParameters match {
      case JsonStreamExtractor.Object(pairs) =>
        val pair = pairs.next()
        pair.value match {
          case JsonStreamExtractor.Array(parameters) =>
            val wsRequest: WSRequest = prepareWSRequest(parameters, pair)
            handleResponse(wsRequest, PlayOutgoingJsonService.DummyJsonResponseHandler)
        }
      case _ =>
        throw new IllegalArgumentException("parameter should be an array")
    }
  }

}

object PlayOutgoingJsonService {

  def newProxy[Service](urlPrefix: String,
                        wsAPI: WSAPI, additionalRequestHeaders: (String, String)*)
                       (implicit outgoingStub: OutgoingStub[Service],
                        executionContext: ExecutionContext) = {
    outgoingStub.outgoingServiceProxy(
      new PlayOutgoingJsonService(urlPrefix, outgoingStub.routeConfiguration, wsAPI, additionalRequestHeaders: _*)
    )
  }

  private[PlayOutgoingJsonService] object DummyJsonResponseHandler extends IJsonResponseHandler {
    override def onSuccess(stream: JsonStream): Unit = {}

    override def onFailure(stream: JsonStream): Unit = {}
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy