/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. */
  18. package org.fusesource.scalate.rest
  19. import java.io.OutputStream
  20. import java.lang.annotation.Annotation
  21. import java.lang.reflect.Type
  22. import java.net.URL
  23. import javax.ws.rs.ext.{MessageBodyWriter, Provider}
  24. import javax.servlet.ServletContext
  25. import javax.ws.rs.core.{Context, MultivaluedMap, MediaType}
  26. import org.fusesource.scalate.scuery.Transformer
  27. import org.fusesource.scalate.servlet.{ServletHelper, TemplateEngineServlet}
  28. import com.sun.jersey.api.core.ExtendedUriInfo
  29. import com.sun.jersey.api.container.ContainerException
  30. import scala.collection.JavaConversions._
  31. import xml.{XML, NodeSeq}
  32. import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
  33. import org.fusesource.scalate.util.{Log, ResourceNotFoundException}
  34. object TransformerWriter extends Log
  35. /**
  36. * Converts an Scuery [[org.fusesource.scalate.scuery.Transformer]] to output
  37. *
  38. * @version $Revision : 1.1 $
  39. */
  40. @Provider
  41. class TransformerWriter extends MessageBodyWriter[Transformer] {
  42. import TransformerWriter._
  43. @Context
  44. protected var uriInfo: ExtendedUriInfo = _
  45. @Context
  46. protected var _servletContext: ServletContext = _
  47. @Context
  48. protected var request: HttpServletRequest = _
  49. @Context
  50. protected var response: HttpServletResponse = _
  51. protected var errorUris: List[String] = ServletHelper.errorUris()
  52. protected def templateDirectories = TemplateEngineServlet().templateEngine.templateDirectories
  53. def isWriteable(aClass: Class[_], aType: Type, annotations: Array[Annotation], mediaType: MediaType) = {
  54. classOf[Transformer].isAssignableFrom(aClass)
  55. }
  56. def getSize(transformer: Transformer, aClass: Class[_], aType: Type, annotations: Array[Annotation], mediaType: MediaType) = -1L
  57. def writeTo(transformer: Transformer, aClass: Class[_], aType: Type, annotations: Array[Annotation], mediaType: MediaType, httpHeaders: MultivaluedMap[String, Object], out: OutputStream): Unit = {
  58. /*
  59. println("aClass: " + aClass.getName)
  60. println("transformer: " + transformer)
  61. println("uriInfo: " + uriInfo)
  62. */
  63. if (uriInfo != null) {
  64. var viewName = "index"
  65. val matchedTemplates = uriInfo.getMatchedTemplates()
  66. if (!matchedTemplates.isEmpty) {
  67. val lastTemplate = matchedTemplates.head
  68. val pathVariables = lastTemplate.getTemplateVariables()
  69. if (pathVariables.isEmpty) {
  70. val segments = lastTemplate.getTemplate.split("/").filter(_.length > 0)
  71. if (!segments.isEmpty) {
  72. viewName = segments.last
  73. }
  74. }
  75. }
  76. val resources = uriInfo.getMatchedResources
  77. if (!resources.isEmpty) {
  78. val resource = resources.head
  79. val className = resource.getClass.getName
  80. debug("resource class: " + className)
  81. debug("viewName: " + viewName)
  82. try {
  83. val templateName = "/" + className.replace('.', '/') + "." + viewName + ".html"
  84. var answer = render(templateName, transformer).toString
  85. // Ensure headers are committed
  86. out.flush()
  87. out.write(answer.getBytes)
  88. } catch {
  89. case e: Exception =>
  90. // lets forward to the error handler
  91. val servlet = TemplateEngineServlet()
  92. var notFound = true
  93. for (uri <- errorUris if notFound) {
  94. if (servletContext.getResource(uri) != null) {
  95. // we need to expose all the errors property here...
  96. request.setAttribute("javax.servlet.error.exception", e)
  97. request.setAttribute("javax.servlet.error.exception_type", e.getClass)
  98. request.setAttribute("javax.servlet.error.message", e.getMessage)
  99. request.setAttribute("javax.servlet.error.request_uri", request.getRequestURI)
  100. request.setAttribute("javax.servlet.error.servlet_name", request.getServerName)
  101. // TODO how to get the status code???
  102. val status = 500
  103. request.setAttribute("javax.servlet.error.status_code", status)
  104. request.setAttribute("it", e)
  105. servlet.render(uri, request, response)
  106. notFound = false
  107. }
  108. }
  109. if (notFound) {
  110. throw new ContainerException(e)
  111. }
  112. }
  113. }
  114. /*
  115. println("matchedURIs: " + uriInfo.getMatchedURIs)
  116. println("getPath: " + uriInfo.getPath)
  117. println("getPathSegments: " + uriInfo.getPathSegments().map(s => "" + s.getPath + " " + s.getMatrixParameters()))
  118. println("getMatchedResults: " + uriInfo.getMatchedResults())
  119. println("getMatchedTemplates: " + uriInfo.getMatchedTemplates())
  120. println("getPathParameters: " + uriInfo.getPathParameters)
  121. */
  122. }
  123. }
  124. /**
  125. * Renders the given template URI using the given ScQuery transformer
  126. */
  127. protected def render(template: String, transformer: Transformer): NodeSeq = {
  128. // lets load the template as XML...
  129. findResource(template) match {
  130. case Some(u) =>
  131. val xml = XML.load(u)
  132. // TODO report nice errors here if we can't parse it!!!
  133. transformer(xml)
  134. case _ => throw new ResourceNotFoundException(template)
  135. }
  136. }
  137. protected def findResource(path: String): Option[URL] = {
  138. var answer: Option[URL] = None
  139. val paths = for (dir <- templateDirectories if answer.isEmpty) {
  140. val t = dir + path
  141. debug("Trying to find template: " + t)
  142. val u = servletContext.getResource(t)
  143. debug("Found: " + u)
  144. if (u != null) {
  145. answer = Some(u)
  146. }
  147. }
  148. answer
  149. }
  150. /**
  151. * Returns the servlet context injected by JAXRS
  152. */
  153. protected def servletContext: ServletContext = {
  154. if (_servletContext == null) {
  155. throw new IllegalArgumentException("servletContext not injected")
  156. }
  157. _servletContext
  158. }
  159. }