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

wvlet.airframe.http.RxRouter.scala Maven / Gradle / Ivy

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package wvlet.airframe.http

import wvlet.airframe.http.router.{RedirectToRxEndpoint, RxRoute}
import wvlet.airframe.surface.{MethodSurface, Surface}

trait RxRouter {
  def name: String
  def filter: Option[RxRouter.FilterNode]
  def children: List[RxRouter]
  def isLeaf: Boolean

  def routes: List[RxRoute]

  def wrapWithFilter(parentFilter: RxRouter.FilterNode): RxRouter

  override def toString: String = printNode(0)

  private def printNode(indentLevel: Int): String = {
    val s  = Seq.newBuilder[String]
    val ws = " " * (indentLevel * 2)
    s += s"${ws}- Router[${name}]"

    if (isLeaf) {
      for (r <- routes) {
        val rstr = r.toString
        rstr.split("\n").map { x =>
          s += s"${ws}  + ${x}"
        }
      }
    }

    for (c <- children) {
      s += c.printNode(indentLevel + 1)
    }
    s.result().mkString("\n")
  }
}

object RxRouter extends RxRouterObjectBase {

  def of(endpoint: RxHttpEndpoint): RxRouter = {
    EndpointNode(
      controllerSurface = Surface.of[RedirectToRxEndpoint],
      methodSurfaces = Surface.methodsOf[RedirectToRxEndpoint],
      controllerInstance = Some(endpoint)
    )
  }

  def of(routers: RxRouter*): RxRouter = {
    if (routers.size == 1) {
      routers.head
    } else {
      StemNode(children = routers.toList)
    }
  }

  /**
    * A collection of multiple routes
    * @param filter
    * @param children
    */
  case class StemNode(
      override val filter: Option[FilterNode] = None,
      override val children: List[RxRouter]
  ) extends RxRouter {
    override def name: String = f"${this.hashCode()}%08x"
    override def wrapWithFilter(parentFilter: FilterNode): RxRouter = {
      this.copy(filter = parentFilter.andThenOpt(filter))
    }

    override def isLeaf: Boolean = false

    override def routes: List[RxRoute] = {
      children.flatMap { c =>
        c.routes.map { r =>
          r.wrapWithFilter(filter)
        }
      }
    }
  }

  /**
    * A single endpoint node without any filter
    * @param filter
    * @param controllerSurface
    * @param methodSurfaces
    */
  case class EndpointNode(
      controllerSurface: Surface,
      methodSurfaces: Seq[MethodSurface],
      controllerInstance: Option[Any] = None
  ) extends RxRouter {
    override def name: String               = controllerSurface.name
    override def filter: Option[FilterNode] = None
    override def children: List[RxRouter]   = Nil
    override def isLeaf: Boolean            = true

    override def wrapWithFilter(parentFilter: FilterNode): RxRouter = {
      StemNode(filter = Some(parentFilter), children = List(this))
    }
    override def routes: List[RxRoute] =
      List(RxRoute(None, controllerSurface, methodSurfaces))
  }

  case class RxEndpointNode(endpoint: RxHttpEndpoint) extends RxRouter {
    override def name: String               = f"${this.hashCode()}%08x"
    override def filter: Option[FilterNode] = None
    override def children: List[RxRouter]   = Nil
    override def isLeaf: Boolean            = true
    override def wrapWithFilter(parentFilter: FilterNode): RxRouter = {
      StemNode(filter = Some(parentFilter), children = List(this))
    }

    override def routes: List[RxRoute] = List.empty
  }

  /**
    * Filter node of RxRouter
    * @param parent
    * @param filterSurface
    */
  case class FilterNode(
      parent: Option[FilterNode],
      filterSurface: Surface,
      filterInstance: Option[RxHttpFilter] = None
  ) extends RxRouteFilterBase {
    def name: String = filterSurface.name

    def andThen(next: FilterNode): FilterNode = {
      next.copy(parent = Some(this))
    }
    def andThenOpt(next: Option[FilterNode]): Option[FilterNode] = {
      next match {
        case Some(f) => Some(this.andThen(f))
        case None    => Some(this)
      }
    }
    def andThen(next: RxHttpEndpoint): RxRouter = {
      of(next).wrapWithFilter(this)
    }

    def andThen(next: RxRouter*): RxRouter = {
      of(next: _*).wrapWithFilter(this)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy