PageRenderTime 67ms CodeModel.GetById 33ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 1ms

/scalate-core/src/main/scala/org/fusesource/scalate/rest/TransformerWriter.scala

http://github.com/scalate/scalate
Scala | 187 lines | 112 code | 27 blank | 48 comment | 17 complexity | c550822b2167cf63d00e16dc41df7e0b MD5 | raw file
  1/**
  2 * Copyright (C) 2009-2011 the original author or authors.
  3 * See the notice.md file distributed with this work for additional
  4 * information regarding copyright ownership.
  5 *
  6 * Licensed under the Apache License, Version 2.0 (the "License");
  7 * you may not use this file except in compliance with the License.
  8 * You may obtain a copy of the License at
  9 *
 10 *     http://www.apache.org/licenses/LICENSE-2.0
 11 *
 12 * Unless required by applicable law or agreed to in writing, software
 13 * distributed under the License is distributed on an "AS IS" BASIS,
 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15 * See the License for the specific language governing permissions and
 16 * limitations under the License.
 17 */
 18package org.fusesource.scalate.rest
 19
 20import java.io.OutputStream
 21import java.lang.annotation.Annotation
 22import java.lang.reflect.Type
 23import java.net.URL
 24import javax.ws.rs.ext.{MessageBodyWriter, Provider}
 25import javax.servlet.ServletContext
 26import javax.ws.rs.core.{Context, MultivaluedMap, MediaType}
 27
 28import org.fusesource.scalate.scuery.Transformer
 29import org.fusesource.scalate.servlet.{ServletHelper, TemplateEngineServlet}
 30import com.sun.jersey.api.core.ExtendedUriInfo
 31import com.sun.jersey.api.container.ContainerException
 32
 33import scala.collection.JavaConversions._
 34import xml.{XML, NodeSeq}
 35import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
 36import org.fusesource.scalate.util.{Log, ResourceNotFoundException}
 37
 38object TransformerWriter extends Log
 39
 40/**
 41 * Converts an Scuery [[org.fusesource.scalate.scuery.Transformer]] to output
 42 *
 43 * @version $Revision : 1.1 $
 44 */
 45@Provider
 46class TransformerWriter extends MessageBodyWriter[Transformer] {
 47  import TransformerWriter._
 48
 49  @Context
 50  protected var uriInfo: ExtendedUriInfo = _
 51  @Context
 52  protected var _servletContext: ServletContext = _
 53  @Context
 54  protected var request: HttpServletRequest = _
 55  @Context
 56  protected var response: HttpServletResponse = _
 57
 58  protected var errorUris: List[String] = ServletHelper.errorUris()
 59
 60  protected def templateDirectories = TemplateEngineServlet().templateEngine.templateDirectories
 61
 62
 63  def isWriteable(aClass: Class[_], aType: Type, annotations: Array[Annotation], mediaType: MediaType) = {
 64    classOf[Transformer].isAssignableFrom(aClass)
 65  }
 66
 67  def getSize(transformer: Transformer, aClass: Class[_], aType: Type, annotations: Array[Annotation], mediaType: MediaType) = -1L
 68
 69
 70  def writeTo(transformer: Transformer, aClass: Class[_], aType: Type, annotations: Array[Annotation], mediaType: MediaType, httpHeaders: MultivaluedMap[String, Object], out: OutputStream): Unit = {
 71    /*
 72        println("aClass: " + aClass.getName)
 73        println("transformer: " + transformer)
 74        println("uriInfo: " + uriInfo)
 75    */
 76
 77    if (uriInfo != null) {
 78      var viewName = "index"
 79      val matchedTemplates = uriInfo.getMatchedTemplates()
 80      if (!matchedTemplates.isEmpty) {
 81        val lastTemplate = matchedTemplates.head
 82        val pathVariables = lastTemplate.getTemplateVariables()
 83        if (pathVariables.isEmpty) {
 84          val segments = lastTemplate.getTemplate.split("/").filter(_.length > 0)
 85          if (!segments.isEmpty) {
 86            viewName = segments.last
 87          }
 88        }
 89      }
 90
 91      val resources = uriInfo.getMatchedResources
 92      if (!resources.isEmpty) {
 93        val resource = resources.head
 94        val className = resource.getClass.getName
 95        debug("resource class: " + className)
 96        debug("viewName: " + viewName)
 97
 98
 99        try {
100          val templateName = "/" + className.replace('.', '/') + "." + viewName + ".html"
101          var answer = render(templateName, transformer).toString
102          // Ensure headers are committed
103          out.flush()
104          out.write(answer.getBytes)
105
106        } catch {
107          case e: Exception =>
108            // lets forward to the error handler
109            val servlet = TemplateEngineServlet()
110            var notFound = true
111            for (uri <- errorUris if notFound) {
112              if (servletContext.getResource(uri) != null) {
113
114                // we need to expose all the errors property here...
115                request.setAttribute("javax.servlet.error.exception", e)
116                request.setAttribute("javax.servlet.error.exception_type", e.getClass)
117                request.setAttribute("javax.servlet.error.message", e.getMessage)
118                request.setAttribute("javax.servlet.error.request_uri", request.getRequestURI)
119                request.setAttribute("javax.servlet.error.servlet_name", request.getServerName)
120
121                // TODO how to get the status code???
122                val status = 500
123                request.setAttribute("javax.servlet.error.status_code", status)
124
125                request.setAttribute("it", e)
126                servlet.render(uri, request, response)
127                notFound = false
128              }
129            }
130            if (notFound) {
131              throw new ContainerException(e)
132            }
133        }
134      }
135      /*
136
137            println("matchedURIs: " + uriInfo.getMatchedURIs)
138            println("getPath: " + uriInfo.getPath)
139            println("getPathSegments: " + uriInfo.getPathSegments().map(s => "" + s.getPath + " " + s.getMatrixParameters()))
140            println("getMatchedResults: " + uriInfo.getMatchedResults())
141            println("getMatchedTemplates: " + uriInfo.getMatchedTemplates())
142            println("getPathParameters: " + uriInfo.getPathParameters)
143      */
144    }
145
146  }
147
148  /**
149   * Renders the given template URI using the given ScQuery transformer
150   */
151  protected def render(template: String, transformer: Transformer): NodeSeq = {
152    // lets load the template as XML...
153    findResource(template) match {
154      case Some(u) =>
155        val xml = XML.load(u)
156        // TODO report nice errors here if we can't parse it!!!
157        transformer(xml)
158      case _ => throw new ResourceNotFoundException(template)
159    }
160  }
161
162  protected def findResource(path: String): Option[URL] = {
163    var answer: Option[URL] = None
164    val paths = for (dir <- templateDirectories if answer.isEmpty) {
165      val t = dir + path
166      debug("Trying to find template: " + t)
167      val u = servletContext.getResource(t)
168      debug("Found: " + u)
169      if (u != null) {
170        answer = Some(u)
171      }
172    }
173    answer
174  }
175
176
177  /**
178   * Returns the servlet context injected by JAXRS
179   */
180  protected def servletContext: ServletContext = {
181    if (_servletContext == null) {
182      throw new IllegalArgumentException("servletContext not injected")
183    }
184    _servletContext
185  }
186
187}