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

skinny.micro.SkinnyMicroServletBase.scala Maven / Gradle / Ivy

package skinny.micro

import javax.servlet.http.{ HttpServlet, HttpServletRequest, HttpServletResponse }
import javax.servlet._
import skinny.micro.context.ThinServletBaseConfig.BaseConfigType
import skinny.micro.context.{ SkinnyContext, ThinServletBaseConfig }
import skinny.micro.implicits.{ RicherStringImplicits, ServletApiImplicits }
import skinny.micro.util.UriDecoder

import scala.util.control.Exception._

/**
 * Base trait for SkinnyMicroServlet implementations.
 */
trait SkinnyMicroServletBase extends HttpServlet with SkinnyMicroBase {

  override def service(request: HttpServletRequest, response: HttpServletResponse): Unit = {
    // NOTICE: Keep this method invocation here
    // When doing this in SKinnyMicroBase, www-form-urlencoded body request makes its included multi-byte chars garbled at least on Tomcat 7.
    setRequestCharacterEncodingAsDefaultIfAbsent(request)
    handle(request, response)
  }

  /**
   * Defines the request path to be matched by routers.  The default
   * definition is optimized for `path mapped` servlets (i.e., servlet
   * mapping ends in `/*`).  The route should match everything matched by
   * the `/*`.  In the event that the request URI equals the servlet path
   * with no trailing slash (e.g., mapping = `/admin/*`, request URI =
   * '/admin'), a '/' is returned.
   *
   * All other servlet mappings likely want to return request.getServletPath.
   * Custom implementations are allowed for unusual cases.
   */
  override def requestPath(implicit ctx: SkinnyContext): String = {
    SkinnyMicroServletBase.requestPath(ctx.request)
  }

  override protected def routeBasePath(implicit ctx: SkinnyContext): String = {
    require(config != null, "routeBasePath requires the servlet to be initialized")
    require(ctx.request != null, "routeBasePath requires an active request to determine the servlet path")

    if (ctx.servletContext != null) {
      ctx.servletContext.getContextPath + ctx.request.getServletPath
    } else {
      // servletContext can be null when test environment
      ctx.request.getServletPath
    }
  }

  /**
   * Invoked when no route matches.  By default, calls `serveStaticResource()`,
   * and if that fails, calls `resourceNotFound()`.
   *
   * This action can be overridden by a notFound block.
   */
  protected var doNotFound: Action = () => {
    serveStaticResource()(skinnyContext)
      .getOrElse(resourceNotFound()(skinnyContext))
  }

  /**
   * Attempts to find a static resource matching the request path.
   * Override to return None to stop this.
   */
  protected def serveStaticResource()(
    implicit
    ctx: SkinnyContext): Option[Any] = {
    servletContext.resource(ctx.request) map { _ =>
      servletContext.getNamedDispatcher("default").forward(ctx.request, ctx.response)
    }
  }

  /**
   * Called by default notFound if no routes matched and no static resource could be found.
   */
  protected def resourceNotFound()(
    implicit
    ctx: SkinnyContext): Any = {
    ctx.response.setStatus(404)
    if (isDevelopment()) {
      val error = "Requesting \"%s %s\" on servlet \"%s\" but only have: %s"
      ctx.response.getWriter println error.format(
        ctx.request.getMethod,
        Option(ctx.request.getPathInfo) getOrElse "/",
        ctx.request.getServletPath,
        routes.entryPoints.mkString("
  • ", "
  • ", "
")) } } override def init(config: ServletConfig): Unit = { super.init(config) initialize(new ThinServletBaseConfig { override def getServletContext(): ServletContext = config.getServletContext override def getInitParameter(name: String): String = config.getInitParameter(name) override def getInitParameterNames(): java.util.Enumeration[String] = config.getInitParameterNames override def getBaseConfigType: BaseConfigType = BaseConfigType.ServletConfig override def getServletConfig: Option[ServletConfig] = Some(config) }) // see Initializable.initialize for why } override def initialize(config: ThinServletBaseConfig): Unit = { super.initialize(config) } override def destroy(): Unit = { shutdown() super.destroy() } } object SkinnyMicroServletBase { import ServletApiImplicits._ import RicherStringImplicits._ val RequestPathKey = "skinny.micro.SkinnyMicroServlet.requestPath" def requestPath(request: HttpServletRequest): String = { require(request != null, "The request can't be null for getting the request path") def startIndex(r: HttpServletRequest) = r.getContextPath.blankOption.map(_.length).getOrElse(0) + r.getServletPath.blankOption.map(_.length).getOrElse(0) def getRequestPath(r: HttpServletRequest) = { val u = (catching(classOf[NullPointerException]) opt { r.getRequestURI } getOrElse "/") requestPath(u, startIndex(r)) } request.get(RequestPathKey) map (_.toString) getOrElse { val rp = getRequestPath(request) request(RequestPathKey) = rp rp } } def requestPath(uri: String, idx: Int): String = { val u1 = UriDecoder.firstStep(uri) val u2 = (u1.blankOption map { _.substring(idx) } flatMap (_.blankOption) getOrElse "/") val pos = u2.indexOf(';') if (pos > -1) u2.substring(0, pos) else u2 } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy