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

com.ecfront.rpc.http.server.HttpServerProcessor.scala Maven / Gradle / Ivy

package com.ecfront.rpc.http.server

import java.io.File
import java.util.concurrent.{CountDownLatch, Executors}

import com.ecfront.common.{JsonHelper, Resp}
import com.ecfront.rpc.Fun
import com.ecfront.rpc.process.ServerProcessor
import io.vertx.core._
import io.vertx.core.buffer.Buffer
import io.vertx.core.http._

import scala.collection.JavaConversions._

/**
 * HTTP服务处理器
 */
class HttpServerProcessor extends ServerProcessor {

  private val vertx = Vertx.vertx()
  private var server: HttpServer = _
  private val executeThreadPool = Executors.newFixedThreadPool(Runtime.getRuntime.availableProcessors() * 4)

  override protected def init(): Unit = {
    val latch = new CountDownLatch(1)
    server = vertx.createHttpServer(new HttpServerOptions().setHost(host).setPort(port).setCompressionSupported(true))
      .requestHandler(new Handler[HttpServerRequest] {
      override def handle(request: HttpServerRequest): Unit = {
        if (request.method().name() == "OPTIONS") {
          returnContent("", request.response(), "text/html")
        } else {
          if (request.path() != "/favicon.ico") {
            val contentType =
              if (request.headers().contains("content-type")) request.headers().get("content-type").toLowerCase else "application/json; charset=UTF-8"
            val urlParameter = collection.mutable.Map[String, String]()
            request.params().entries().foreach {
              item =>
                urlParameter += (item.getKey -> item.getValue)
            }
            try {
              val (preResult, fun, postFun) = router.getFunction(request.method().name(), request.path(), urlParameter)
              if (preResult) {
                if (request.headers().contains("content-type") && (request.headers.get("content-type").toLowerCase.startsWith("multipart/form-data") || request.headers.get("content-type").toLowerCase.startsWith("application/x-www-form-urlencoded"))) {
                  request.setExpectMultipart(true)
                  request.uploadHandler(new Handler[HttpServerFileUpload] {
                    override def handle(upload: HttpServerFileUpload): Unit = {
                      var path = if (request.params().contains("path")) request.params().get("path") else ""
                      if (path.nonEmpty && !path.endsWith(File.separator)) {
                        path += File.separator
                      }
                      val newName = if (request.params().contains("name")) request.params().get("name")
                      else {
                        if (upload.filename().contains(".")) {
                          upload.filename().substring(0, upload.filename().lastIndexOf(".")) + "_" + System.nanoTime() + "." + upload.filename().substring(upload.filename().lastIndexOf(".") + 1)
                        } else {
                          upload.filename() + "_" + System.nanoTime()
                        }
                      }
                      val tPath = rootUploadPath + path + newName
                      upload.exceptionHandler(new Handler[Throwable] {
                        override def handle(e: Throwable): Unit = {
                          returnContent(Resp.serverError(e.getMessage), request.response(), "application/json; charset=UTF-8")
                        }
                      })
                      upload.endHandler(new Handler[Void] {
                        override def handle(e: Void): Unit = {
                          try {
                            execute(urlParameter.toMap, path + newName, preResult.body, fun, postFun, request.response(), "application/json; charset=UTF-8")
                          } catch {
                            case e: Exception =>
                              logger.error("RPC upload process error.", e)
                              returnContent(Resp.fail("-1", "RPC upload process error : " + e.getMessage), request.response(), contentType)
                          }
                        }
                      })
                      upload.streamToFileSystem(tPath)
                    }
                  })
                } else if (request.method().name() == "POST" || request.method().name() == "PUT") {
                  request.bodyHandler(new Handler[Buffer] {
                    override def handle(data: Buffer): Unit = {
                      try {
                        val body = contentType match {
                          case t if t.contains("json") => JsonHelper.toObject(data.getString(0, data.length), fun.requestClass)
                          case t if t.contains("xml") => scala.xml.XML.loadString(data.getString(0, data.length))
                          case _ => logger.error("Not support content type:" + contentType)
                        }
                        execute(urlParameter.toMap, body, preResult.body, fun, postFun, request.response(), contentType)
                      } catch {
                        case e: Exception =>
                          logger.error("RPC body process error.", e)
                          returnContent(Resp.fail("-1", "RPC body process error : " + e.getMessage), request.response(), contentType)
                      }
                    }
                  })
                } else {
                  execute(urlParameter.toMap, null, preResult.body, fun, postFun, request.response(), contentType)
                }
              } else {
                returnContent(preResult, request.response(), contentType)
              }
            } catch {
              case e: Exception =>
                logger.error("RPC basic process error.", e)
                returnContent(Resp.fail("-1", "RPC basic process error : " + e.getMessage), request.response(), contentType)
            }
          }
        }
      }
    }).listen(new Handler[AsyncResult[HttpServer]] {
      override def handle(event: AsyncResult[HttpServer]): Unit = {
        if (event.succeeded()) {
          latch.countDown()
        } else {
          logger.error("Startup fail.", event.cause())
        }
      }
    })
    latch.await()
  }

  override private[rpc] def destroy(): Unit = {
    val latch = new CountDownLatch(1)
    server.close(new Handler[AsyncResult[Void]] {
      override def handle(event: AsyncResult[Void]): Unit = {
        if (event.succeeded()) {
          latch.countDown()
        } else {
          logger.error("Shutdown failed.", event.cause())
        }
      }
    })
    latch.await()
  }

  private def execute(parameter: Map[String, String], body: Any, preData: Any, fun: Fun[_], postFun: => Any => Any, response: HttpServerResponse, contentType: String) {
    executeThreadPool.execute(new Runnable {
      override def run(): Unit = {
        try {
          returnContent(postFun(fun.execute(parameter, body, preData)), response, contentType)
        }
        catch {
          case e: Exception =>
            returnContent(Resp.serverError(e.getMessage), response, contentType)
        }
      }
    })
  }

  private def returnContent(result: Any, response: HttpServerResponse, contentType: String) {
    val body = contentType match {
      case t if t.contains("json") => JsonHelper.toJsonString(result)
      case t if t.contains("xml") || t.contains("html") => result.toString
      case _ =>
        logger.error("Not support content type:" + contentType)
        ""
    }
    response.setStatusCode(200).putHeader("Content-Type", contentType)
      .putHeader("Cache-Control", "no-cache")
      .putHeader("Access-Control-Allow-Origin", "*")
      .putHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
      .putHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With, X-authentication, X-client")
      .end(body)
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy