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

.circumflex-web.2.2.source-code.package.scala Maven / Gradle / Ivy

Go to download

Circumflex Web Framework is a lightweight framework for quick and robust application development using Scala programming language.

There is a newer version: 2.5
Show newest version
package ru.circumflex

import core._
import javax.servlet.{FilterChain, FilterConfig}
import collection.Iterator
import javax.activation.MimetypesFileTypeMap
import java.io._
import org.apache.commons.io.IOUtils
import collection.mutable.Map

/*!# The `web` Package

Package `web` contains different shortcuts, utilities and helpers --
the basis of routing DSL of Circumflex Web Framework.

You should import this package to use Circumflex Web Framework in your application:

    import ru.circumflex.web._

If you don't wish to import all helpers into your global scope, then import this
package under an alias:

    import ru.circumflex.{web => cx}    // import under alias "cx"
    cx.request                          // access members
*/
package object web {

  val WEB_LOG = new Logger("ru.circumflex.web")

  /*!# Heplers

  Helpers are tiny methods and structures which provide common functionality
  for web applications like accessing current request, response, session, headers, cookies
  and other stuff.
   */
  def request = ctx("cx.request").asInstanceOf[HttpRequest]
  def response = ctx("cx.response").asInstanceOf[HttpResponse]
  def filterChain = ctx("cx.filterChain").asInstanceOf[FilterChain]
  def filterConfig = cx("cx.filterConfig").asInstanceOf[FilterConfig]
  def servletContext = filterConfig.getServletContext
  def session = request.session

  /*!## The `headers` Helper

  The `headers` object of package `ru.circumflex.web` lets you access request
  headers and set response headers (i.e. mix functionality of `request.headers`
  and `response.headers`).
  */
  object headers extends Map[String, String] {
    def +=(kv: (String, String)): this.type = {
      response.headers + kv
      this
    }
    def -=(key: String): this.type = {
      response.headers - key
      this
    }
    def iterator: Iterator[(String, String)] = request.headers.iterator
    def get(key: String): Option[String] = request.headers.get(key)
  }

  /*!## The `cookies` Helper

  The `cookies` object of package `ru.circumflex.web` lets you access request
  cookies and set response cookies (i.e. mix functionality of `request.cookies`
  and `response.cookies`).
  */
  object cookies extends Map[String, HttpCookie] {
    def +=(kv: (String, HttpCookie)): this.type = {
      response.cookies += kv._2.asInstanceOf[HttpCookie]
      this
    }
    def -=(key: String): this.type = {
      response.cookies.find(_.name == key).map(c => response.cookies -= c)
      this
    }
    def iterator: Iterator[(String, HttpCookie)] =
      request.cookies.iterator.map(c => (c.name -> c))
    def get(key: String): Option[HttpCookie] =
      request.cookies.find(c => c.name == key)
  }

  /*!## The `flash` Helper

  The `flash` object provides a way to pass temporary objects between requests.
  Flash variables are stored in session until first access.
  */
  object flash extends Map[String, Any] with UntypedContainer {
    val SESSION_KEY = "cx.flash"
    protected def flashMap = session
        .getOrElse(SESSION_KEY, Map[String, Any]())
        .asInstanceOf[Map[String, Any]]
    def +=(kv: (String, Any)): this.type = {
      session(SESSION_KEY) = flashMap + (kv)
      this
    }
    def -=(key: String): this.type = {
      session(SESSION_KEY) = flashMap - key
      this
    }
    def iterator: Iterator[(String, Any)] = flashMap.iterator
    def get(key: String): Option[Any] = {
      val m = flashMap
      flashMap.get(key) map { v =>
        session(SESSION_KEY) = m - key
        v
      }
    }
    override def contains(key: String): Boolean = flashMap.contains(key)
  }

  /*!## The `param` Helper

  The `param` object of package `ru.circumflex.web` is a convenient helper to
  retrieve the parameters of current match or current request. The parameters
  are first resolved from `MatchResult` objects found in context. If no
  match result contain a parameter with specified name, then the parameter is
  resolved from request parameters.
  */
  object param extends Map[String, String] {
    def +=(kv: (String, String)): this.type = this
    def -=(key: String): this.type = this
    def iterator: Iterator[(String, String)] = ctx.iterator.flatMap(p => p._2 match {
      case m: MatchResult => m.params.iterator
      case s: String => Seq(p._1 -> s).iterator
      case _ => Iterator.empty
    }) ++ request.params.iterator
    def get(key: String): Option[String] = iterator.find(_._1 == key).map(_._2)
    override def default(key: String): String = ""
    def list(key: String): Seq[String] = iterator.filter(_._1 == key).map(_._2).toList
  }

  /*!## Response Helpers

  Circumflex Web Framework provides following helpers for sending standard
  HTTP responses:

    * `send` writes specified `text` to response buffer and, if specified,
    sets `statusCode`;
    * `sendError` sends an error to the client using specified `statusCode` and
    `message`;
    * `sendRedirect` sends `302 MOVED TEMPORARILY` to the client using specified
    `url` and optional `flashes`;
    * `sendFile` sends specified `file` to the client; if `filename` is provided,
    `Content-Disposition: attachment` is also added to the response with specified
    `filename`;
    * `xSendFile` delegates filesending to the web server; refer to documentation
    of your web server to understand how it works;
    * `sendStream` accepts a function, which uses `OutputStream` to send binary
    data;
    * `sendChars` accepts a function, which uses `Writer` to send character data;
    * `forward` delegates further request processing to another component located
    at specified `url` and immediately flushes the response at the end; note that
    if you want to forward the request to another Circumflex route, you must make
    sure that `CircumflexFilter` is mapped with `FORWARD`
    in `web.xml`;
    * `pass()` sends request and response down the filter chain and then immediately
    flushes response.

  All helpers by convention throw `ResponseSentException` which is caught by
  `CircumflexFilter` to indicate that the response have been processed
  successfully.
  */
  def send(text: String = "", statusCode: Int = -1): Nothing = {
    if (statusCode != -1)
      response.statusCode(statusCode)
    response.body(r => r.getWriter.write(text)).flush()
  }
  def sendError(statusCode: Int, message: String = "No message available."): Nothing =
    response.body(r => r.sendError(statusCode, message)).flush()
  def sendRedirect(url: String, flashes: (String, Any)*): Nothing = {
    flashes.foreach(kv => flash(kv._1) = kv._2)
    response.body(r => r.sendRedirect(url)).flush()
  }
  def sendFile(file: File, filename: String = ""): Nothing = {
    // if filename is provided, add `Content-Disposition` header
    if (filename != "") response.attachment(filename)
    // if not set explicitly, infer content type from extension
    if (response.contentType == "")
      response.contentType(new MimetypesFileTypeMap().getContentType(file))
    // send file by copying streams
    response.body { r =>
      val is = new FileInputStream(file)
      try {
        IOUtils.copy(is, r.getOutputStream)
      } finally {
        is.close()
      }
    } flush()
  }
  def xSendFile(file: File, filename: String = ""): Nothing = {
    // if filename is provided, add `Content-Disposition` header
    if (filename != "") response.attachment(filename)
    val xsf = cx.instantiate[XSendFileHeader]("cx.xSendFile", DefaultXSendFileHeader)
    response.headers(xsf.name) = xsf.value(file)
    send()
  }
  def sendStream(streamFunc: OutputStream => Unit): Nothing =
    response.body(r => streamFunc(r.getOutputStream)).flush()
  def sendChars(writerFunc: Writer => Unit): Nothing =
    response.body(r => writerFunc(r.getWriter)).flush()
  def forward(url: String): Nothing = {
    request.forward(url)
    response.flush()
  }
  def pass(): Nothing = {
    filterChain.doFilter(request.raw, response.raw)
    response.flush()
  }

  /*!## The `matchers` Helper

  The `matchers` helper contains shortcuts for various matchers (for example, by known HTTP headers).
  You should import this object if you want to use it:

      import ru.circumflex.web.{matchers => m}

      get("/" & m.ACCEPT(":mime")) = "You are accepting " + param("mime")
  */
  object matchers {
    val ACCEPT = new HeaderMatcherHelper("Accept")
    val ACCEPT_CHARSET = new HeaderMatcherHelper("Accept-Charset")
    val ACCEPT_ENCODING = new HeaderMatcherHelper("Accept-Encoding")
    val ACCEPT_LANGUAGE = new HeaderMatcherHelper("Accept-Language")
    val ACCEPT_RANGES = new HeaderMatcherHelper("Accept-Ranges")
    val AUTHORIZARION = new HeaderMatcherHelper("Authorization")
    val CACHE_CONTROL = new HeaderMatcherHelper("Cache-Control")
    val CONNECTION = new HeaderMatcherHelper("Connection")
    val CONTENT_LENGTH = new HeaderMatcherHelper("Content-Length")
    val COOKIE = new HeaderMatcherHelper("Cookie")
    val CONTENT_TYPE = new HeaderMatcherHelper("Content-Type")
    val DATE = new HeaderMatcherHelper("Date")
    val EXPECT = new HeaderMatcherHelper("Expect")
    val FROM = new HeaderMatcherHelper("From")
    val HOST = new HeaderMatcherHelper("Host")
    val IF_MATCH = new HeaderMatcherHelper("If-Match")
    val IF_MODIFIED_SINCE = new HeaderMatcherHelper("If-Modified-Since")
    val IF_NONE_MATCH = new HeaderMatcherHelper("If-None-Match")
    val IF_RANGE = new HeaderMatcherHelper("If-Range")
    val IF_UNMODIFIED_SINCE = new HeaderMatcherHelper("If-Unmodified-Since")
    val MAX_FORWARDS = new HeaderMatcherHelper("Max-Forwards")
    val PRAGMA = new HeaderMatcherHelper("Pragma")
    val PROXY_AUTHORIZATION = new HeaderMatcherHelper("Proxy-Authorization")
    val RANGE = new HeaderMatcherHelper("Range")
    val REFERER = new HeaderMatcherHelper("Referer")
    val TE = new HeaderMatcherHelper("TE")
    val UPGRADE = new HeaderMatcherHelper("Upgrade")
    val USER_AGENT = new HeaderMatcherHelper("User-Agent")
    val VIA = new HeaderMatcherHelper("Via")
    val WARNING = new HeaderMatcherHelper("Warning")
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy