Distribution of Scalate processing

54 views
Skip to first unread message

Mike Klein

unread,
May 8, 2013, 5:15:18 PM5/8/13
to scalat...@googlegroups.com
I'm getting an NullPointerException when trying to handle "Jade" templating outside of the built-it routing environment that I'm hoping will be quick answer for someone with scalate/scalatra integration knowledge:

I've created a custom trait is designed to allow scalate processing from with a pojo (poso??) so that routing can look/feel a little less "mvc-is.." Here's a typical usage block within the routing:

  //-----------------> ResourceIdentifiers <----------------------//
  get("/system/utilities/resources/list") { val rid = new RID(); rid.showRegistrationList(request) }
  get("/system/utilities/resources/registration") { val rid = new RID(); rid.showRegistrationForm(request) }
  post("/system/utilities/resources/registration") {val rid = new RID(); rid.processRegistrationForm(request) }

"RID" is the object that inherits a skeleton trait to provide scalate request process (if/when/as needed):

trait EmbeddedScalate extends ScalateSupport {
  def requestPath(implicit request: javax.servlet.http.HttpServletRequest): String =  { null }
  protected def routeBasePath(implicit request: javax.servlet.http.HttpServletRequest): String =  { null }
  protected var doNotFound: Action = () => {
    jade("/resource/not/found/error.jade")
  }
}

In practice, the will throw the NPE in this block of code within org.fusescource.scalata.support.TemplateFinder:

  def findTemplate(path: String): Option[String] = {
    var rc = Option(engine.finderCache.get(path))    <---------------------------------------- error in this line
    if (rc.isEmpty) {
      rc = search(path)
      if (rc.isDefined && !engine.isDevelopmentMode) {
        engine.finderCache.put(path, rc.get)
      }
    }
    rc
  }

Since I know the "path" parameter is pointing to a valid resource (which works in a "non-traited" action), I'm assuming that the reference to "engine" or "finderCache" is not being filled, so how would be the best method to resolve that using the custom trait outlined above? 

Thanks.


 
   

Ivan Porto Carrero

unread,
May 8, 2013, 6:31:22 PM5/8/13
to scalat...@googlegroups.com
Perhaps this? but the integration we use of scalate wants a servlet thing. you can use scalate directly to get the behavior you're after

trait EmbeddedScalate extends ScalateSupport {
  def requestPath(implicit request: javax.servlet.http.HttpServletRequest): String =  { "" }
  protected def routeBasePath(implicit request: javax.servlet.http.HttpServletRequest): String =  { "" }
  protected var doNotFound: Action = () => {
    jade("/resource/not/found/error.jade")
  }
}

-- 
Ivan Porto Carrero

Mike Klein

unread,
May 9, 2013, 9:37:12 AM5/9/13
to scalat...@googlegroups.com
I couldn't get those modifications to work so I wired up Scalate directly. It's producing the output I want, but I'm still having a little trouble getting attributes passed in - so I was wondering if you could tell me how Scalatra manages to get this line of code to function, whereas I get a compiler error stating that getOrEleseUpdate is not a method of request.

    request.getOrElseUpdate (...).

I'm still learning scala but I'm guessing I've overlooked some type of implicit transformation?

Thanks. 

Stefan Ollinger

unread,
May 9, 2013, 10:22:09 AM5/9/13
to scalat...@googlegroups.com
Can you paste your code or project somewhere?
Generally you dont need to initialize Scalate manually.
--
You received this message because you are subscribed to the Google Groups "scalatra-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scalatra-use...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Mike Klein

unread,
May 9, 2013, 11:48:15 AM5/9/13
to scalat...@googlegroups.com
Stefan, unless someone here wants to reuse it (in which case I'd be happy to) I was trying to save time  :) 

In short, I need to break the "scalate" portion out of the scalatra DSL routing context. There are several reasons, but two primary ones are:  1) the ability to alter the implementation of a Route w/o having to modify and/or reload the routes themselves, and 2) our system has an abstraction layer that can reconcile a user's version of a any given resource based upon their access credentials . (So, for example, a given view might have a "full", "limited" and "readonly" version.)

The ideal route/action is one that looks like so:

  get("/system/utilities/resources/list") { val rid = new RID(); rid.showRegistrationList() }

where the method "showRegistrationList()" handles everything for there on out using a combination of implicit request/response parameters and logic layers acting upon the Scentry output. The pojos ("RID" in the example) simply render a text steam for whatever source/mechanism is required: Jade, JSON, XML, direct, or Foo. So far our trait accomplishes what we want except for the Scalate templating, which I'm still trying to get my mind around. Scalatra's solution uses a logic path that includes this method:

protected def templateAttributes(implicit request: HttpServletRequest): mutable.Map[String, Any] =
    request.getOrElseUpdate(TemplateAttributesKey, mutable.Map.empty).asInstanceOf[mutable.Map[String, Any]]

which appears to somehow remap an immutable request object using a MapLike "getOrElseUpdate(...)" function?? With my limited scala knowledge I'm just not able to duplicate due to the error from the previous post.

If you can help me understand how scalatra is able to accomplish that magical call then I think I've got everything else worked out.

If it helps, here is  rid.showRegistrationList() (used in the example route above):

  def showRegistrationForm()(implicit request: HttpServletRequest, response: HttpServletResponse): String = {
    jade("/path/to/view/file/registration.jade")
  } 

(the jade method is a copy of Scalatra's convenience method)









On Wednesday, May 8, 2013 4:15:18 PM UTC-5, Mike Klein wrote:

Ivan Porto Carrero

unread,
May 9, 2013, 12:55:16 PM5/9/13
to scalat...@googlegroups.com

to me it sounds like we should be able to handle this use case, essentially you just want to use templates from a different path right?

-- 
Ivan Porto Carrero

--

Mike Klein

unread,
May 9, 2013, 1:02:30 PM5/9/13
to scalat...@googlegroups.com
Problem solved. Not sure why I didn't think of it before. Adding a callback method in the custom router trait did the trick:


// publicized for route action-workers as an effective "callback" for Scalate templating. This publication is required since the convenience
// methods within ScalateSupport are protected and ActionWorkers are freestanding pojos rather than descendants. 
def process(template:String, path: String, attributes: (String, Any)*)(implicit request: HttpServletRequest, response: HttpServletResponse): String = layoutTemplateAs(Set(template))(path, attributes:_*)

adding this into some form of CustomRouterTrait (or directly):
  implicit val self:SymphonySubRouter = this

lets you hand off rendering to a pojo, which then uses the callback for Scalate purposes:
     SomeClass extends CustomRouter(...) {
        get("/system/utilities/resources/list") { val rid = new RID(); rid.showRegistrationFormt() }    
     }

and finally, this implicit pickup for the publicized callback
     SomeClassCalledRID(...) extends NothingAtAll {
         def showRegistrationForm()(implicit router: SymphonySubRouter, request : HttpServletRequest, response: HttpServletResponse): String = {
             // do whatever...
            // finally:
            router.process("jade", "/some/resource/called/registration.jade")        
          }
      }


HTH. -mjk
   




On Wednesday, May 8, 2013 4:15:18 PM UTC-5, Mike Klein wrote:

Mike Klein

unread,
May 9, 2013, 1:06:45 PM5/9/13
to scalat...@googlegroups.com
Ivan/Stefan, thanks for your help. I ddin't see Ivan's message when I posted the solution, so let me know if anyone wants an implementation of the solution below and I'll post it somewhere.

Cheers,
-mjk


On Wednesday, May 8, 2013 4:15:18 PM UTC-5, Mike Klein wrote:
Reply all
Reply to author
Forward
0 new messages