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