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

skinny.controller.feature.TemplateEngineFeature.scala Maven / Gradle / Ivy

There is a newer version: 2.1.2
Show newest version
package skinny.controller.feature

import skinny.Format
import skinny.micro.context.SkinnyContext
import skinny.micro.contrib.json4s.JSONSupport
import skinny.micro.response.ResponseStatus
import skinny.logging.LoggerProvider
import skinny.exception.ViewTemplateNotFoundException

/**
 * TemplateEngine support for Skinny app.
 */
trait TemplateEngineFeature
    extends SkinnyControllerCommonBase
    with RequestScopeFeature
    with JSONSupport
    with LoggerProvider {

  /**
   * Renders body with template.
   *
   * @param path path name
   * @param format format (HTML,JSON,XML...)
   * @return body
   */
  def render(path: String)(implicit ctx: SkinnyContext, format: Format = Format.HTML): String = {
    setContentTypeIfAbsent()(format)

    if (templateExists(path)(format)) {
      // template found, render with it
      renderWithTemplate(path)(ctx, format)
    } else if (format == Format.HTML) {
      // template not found and should be found
      throw new ViewTemplateNotFoundException(s"View template not found. (expected: one of ${templatePaths(path)})")
    } else {
      // template not found, but try to render JSON or XML body if possible
      logger.debug(s"Template for ${path} not found (format: ${format}).")
      val entity = (for {
        resourcesName <- getFromRequestScope[String](RequestScopeFeature.ATTR_RESOURCES_NAME)(ctx)
        resources <- getFromRequestScope[Any](resourcesName)(ctx)
      } yield resources) getOrElse {
        for {
          resourceName <- getFromRequestScope[String](RequestScopeFeature.ATTR_RESOURCE_NAME)(ctx)
          resource <- getFromRequestScope[Any](resourceName)(ctx)
        } yield resource
      }
      // renderWithFormat returns null when body is empty
      Option(renderWithFormat(entity)(format)).getOrElse(haltWithBody(404)(ctx, format))
    }
  }

  /**
   * Returns possible template paths.
   * Result is a list because the template engine may support multiple template languages.
   *
   * @param path path name
   * @param format format (HTML,JSON,XML...)
   * @return actual path
   */
  protected def templatePaths(path: String)(implicit format: Format = Format.HTML): List[String]

  /**
   * Predicates the template exists.
   *
   * @param path path name
   * @param format format (HTML,JSON,XML...)
   * @return true/false
   */
  protected def templateExists(path: String)(implicit format: Format = Format.HTML): Boolean

  /**
   * Renders with template.
   *
   * @param path path name
   * @param format format (HTML,JSON,XML...)
   * @return body
   */
  protected def renderWithTemplate(path: String)(
    implicit
    ctx: SkinnyContext, format: Format = Format.HTML
  ): String

  override protected def haltWithBody[A](httpStatus: Int)(
    implicit
    ctx: SkinnyContext, format: Format = Format.HTML
  ): A = {
    val body: String = format match {
      case Format.HTML => render(s"/error/${httpStatus}")(ctx, format)
      case _ => renderWithFormat(Map("status" -> httpStatus, "message" -> ResponseStatus(httpStatus).message))(format)
    }
    Option(body).map { b =>
      halt(status = httpStatus, body = b)
    }.getOrElse {
      halt(status = httpStatus)
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy