Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.ecfront.ez.framework.service.rpc.foundation.Router.scala Maven / Gradle / Ivy
package com.ecfront.ez.framework.service.rpc.foundation
import java.util.regex.Pattern
import com.ecfront.common.Resp
import com.typesafe.scalalogging.slf4j.LazyLogging
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
/**
* 路由操作对象
*
* @param requestClass 请求对象的类型
* @param fun 业务方法
* @tparam E 请求对象的类型
*/
case class Fun[E](requestClass: Class[E], private val fun: (Map[String, String], E, EZRPCContext) => Resp[Any]) {
/**
* 执行业务方法
*
* @param parameters 请求参数
* @param body 请求体
* @param context RPC上下文
* @return 执行结果
*/
private[rpc] def execute(parameters: Map[String, String], body: Any, context: EZRPCContext): Resp[Any] = {
fun(parameters, body.asInstanceOf[E], context)
}
}
/**
* 路由表
*/
private[rpc] class Router extends LazyLogging {
/**
* 业务方法容器,非正则
* 结构为:method -> ( path -> 业务方法)
*/
private val funContainer = collection.mutable.Map[String, collection.mutable.Map[String, Fun[_]]]()
funContainer += ("POST" -> collection.mutable.Map[String, Fun[_]]())
funContainer += ("GET" -> collection.mutable.Map[String, Fun[_]]())
funContainer += ("DELETE" -> collection.mutable.Map[String, Fun[_]]())
funContainer += ("PUT" -> collection.mutable.Map[String, Fun[_]]())
funContainer += ("REQUEST" -> collection.mutable.Map[String, Fun[_]]())
/**
* 业务方法容器,正则
* 结构为:method -> 正则对象
*/
private val funContainerR = collection.mutable.Map[String, ArrayBuffer[RouterRContent]]()
funContainerR += ("POST" -> ArrayBuffer[RouterRContent]())
funContainerR += ("GET" -> ArrayBuffer[RouterRContent]())
funContainerR += ("DELETE" -> ArrayBuffer[RouterRContent]())
funContainerR += ("PUT" -> ArrayBuffer[RouterRContent]())
funContainerR += ("REQUEST" -> ArrayBuffer[RouterRContent]())
}
/**
* 正则路由对象
*
* @param originalPath 原始的Path(注册时用的Path)
* @param pattern 正则对象
* @param param 从原始Path中抽取的变量,如 /index/:id/ 则获取到 seq("id")
* @param fun 业务方法
*/
case class RouterRContent(originalPath: String, pattern: Pattern, param: Seq[String], fun: Fun[_])
object Router extends LazyLogging {
// 路由容器 通道-> 路由表
private val ROUTERS = collection.mutable.Map[String, Router]()
/**
* 获取对应的路由信息,先按非正则匹配,匹配再从正则容器中查找
*
* @param channel RPC通道
* @param method 请求方法
* @param path 请求路径
* @param parameters 请求参数
* @param ip 请求的IP
* @return 结果 (是否找到,业务方法,解析后的参数,对应的模板URI)
*/
private[rpc] def getFunction(
channel: String, method: String, path: String,
parameters: Map[String, String], ip: String): (Resp[_], Fun[_], Map[String, String], String) = {
val newParameters = collection.mutable.Map[String, String]()
newParameters ++= parameters
// 格式化path
val formatPath = if (path.endsWith("/")) path else path + "/"
var urlTemplate = formatPath
if (ROUTERS(channel).funContainer.contains(method.toUpperCase)) {
var fun: Fun[_] = ROUTERS(channel).funContainer(method.toUpperCase).get(formatPath).orNull
if (fun == null) {
// 使用正则路由
ROUTERS(channel).funContainerR(method).foreach {
item =>
val matcher = item.pattern.matcher(formatPath)
if (matcher.matches()) {
// 匹配到正则路由
// 获取原始(注册时的)Path
urlTemplate = item.originalPath
fun = item.fun
// 从Path中抽取变量
item.param.foreach(name => newParameters += (name -> matcher.group(name)))
}
}
}
if (fun != null) {
// 匹配到路由
(Resp.success(null), fun, newParameters.toMap, urlTemplate)
} else {
// 没有匹配到路由
logger.warn(s"$method:$path not implemented from $ip")
(Resp.notImplemented(s"$method:$path from $ip"), null, newParameters.toMap, null)
}
} else {
// 没有匹配到路由
logger.warn(s"$method:$path not implemented from $ip")
(Resp.notImplemented(s"$method:$path from $ip"), null, newParameters.toMap, null)
}
}
/**
* 注册路由规则
*
* @param channel 通道
* @param method 请求方法
* @param path 请求路径
* @param requestClass 请求对象的类型
* @param fun 业务方法
*/
private[rpc] def add[E](
channel: String, method: String, path: String, requestClass: Class[E],
fun: => (Map[String, String], E, EZRPCContext) => Resp[Any]): Unit = {
if (!ROUTERS.contains(channel)) {
ROUTERS += channel -> new Router
}
// 格式化path
val formatPath = if (path.endsWith("/")) path else path + "/"
logger.info(s"Register [${channel.toString}] method [$method] path : $formatPath.")
if (formatPath.contains(":")) {
// regular
val r = Router.getRegex(formatPath)
// 注册到正则路由表
ROUTERS(channel).funContainerR(method) += RouterRContent(formatPath, r._1, r._2, Fun[E](requestClass, fun))
} else {
// 注册到非正则路由表
ROUTERS(channel).funContainer(method) += (formatPath -> Fun[E](requestClass, fun))
}
}
private val matchRegex =""":\w+""".r
/**
* 将非规范正则转成规范正则
*
* 如 输入 /index/:id/ 输出 (^/index/(?[^/]+)/$ 的正则对象,Seq("id") )
*
* @param path 非规范正则,用 :x 表示一个变量
* @return (规范正则,变更列表)
*/
private def getRegex(path: String): (Pattern, Seq[String]) = {
var pathR = path
var named = mutable.Buffer[String]()
matchRegex.findAllMatchIn(path).foreach {
m =>
val name = m.group(0).substring(1)
pathR = pathR.replaceAll(m.group(0), """(?<""" + name + """>[^/]+)""")
named += name
}
(Pattern.compile("^" + pathR + "$"), named)
}
}