Scalate, DefaultRenderContext vs ServletRenderContext

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Scalate, DefaultRenderContext vs ServletRenderContext

chris_lewis
Happy first evening of 2011!

I'm working on more of a website app to deploy to GAE. So far the webbiest my apps have been is single, static HTML files populated via JSON (served by unfiletered). This project needs real pages, so I looked into the scalate module. Scalate on GAE requires a couple system props and precompiled templates to avoid sandboxing, so I plundered https://github.com/Yasushi/ (this guy has churned out sbt utils for GAE).

Disclaimer: I'm a scalate newb.

Using the net.stbbs.yasushi.ScalatePlugin plugin, precompilation is cake. The problem is that it compiles to scala that expects a ServletRenderContext instead of a DefaultRenderContext, which blows up at runtime. It seemed logical that scalate in GAE (and unfiltered) should use a ServletRenderContext, but its constructors want things from the javax.servlet API (ServletContext, etc). At a glance, it seems that unfiltered wants to hide the servlet API which, if true, is a problem. Further, getting at the ServletContext via HttpServletRequest seems awkward (getSession.getServletContext). I haven't tested this, but I fear it may fail in a stateless (GAE sans sessions) environment.

The other option is to hack the action exposed via ScalatePlugin, which I've done locally. This does work, but I wanted to seek some advice given that I don't know how DefaultRenderContext and ServletRenderContext differ.

Any input would be greatly appreciated. I will happily contribute code to get the scalate module using ServletRenderContext, if it seems that's the best decision. Thanks!

-chris
Reply | Threaded
Open this post in threaded view
|

Re: Scalate, DefaultRenderContext vs ServletRenderContext

n8han
Administrator
On 01/01/2011 07:28 PM, chris_lewis [via Databinder] wrote:
> Disclaimer: I'm a scalate newb.

Me: more so! Dustin contributed that module, you may know.

> Using the net.stbbs.yasushi.ScalatePlugin plugin, precompilation is
> cake. The problem is that it compiles to scala that expects a
> ServletRenderContext instead of a DefaultRenderContext, which blows up
> at runtime. It seemed logical that scalate in GAE (and unfiltered)
> should use a ServletRenderContext, but its constructors want things
> from the javax.servlet API (ServletContext, etc). At a glance, it
> seems that unfiltered wants to hide the servlet API which, if true,

Not true! :)

> is a problem. Further, getting at the ServletContext via
> HttpServletRequest seems awkward (getSession.getServletContext). I
> haven't tested this, but I fear it may fail in a stateless (GAE sans
> sessions) environment.

I don't know if GAE can support that or not, but the issue with getting
at the servlet API from the Unfilitered scalate module is that it
depends only on unfiltered-library, so that it can be used from a Netty
or other module that doesn't have the servlet API on the classpath.

> The other option is to hack the action exposed via ScalatePlugin,
> which I've done locally. This does work, but I wanted to seek some
> advice given that I don't know how DefaultRenderContext and
> ServletRenderContext differ.

If that plugin doesn't need the ServletRenderContext perhaps forking it
and having it depend on a higher level interface, if there is one, is
the best solution? I'm sure the changes would be merged in, seems like a
pretty straightforward and useful improvement.

> Any input would be greatly appreciated. I will happily contribute code
> to get the scalate module using ServletRenderContext, if it seems
> that's the best decision. Thanks!

I see two options for handling it in unfiltered, if need be:

1. Create the DefaultRenderContext in an overridable method, so that in
an app you can create the type of context it wants. I just pushed a
change to the Scalate case class giving a type parameter, so that
request.underlying will be a HttpServletRequest if that's what you pass
into it.

2. Create a new module that depends on scalate and unfiltered-filter, so
that the ServletRenderContext can be created in the library code. I
think this is probably not worth doing as there is not that much library
code in the first place.

Nathan
Reply | Threaded
Open this post in threaded view
|

Re: Scalate, DefaultRenderContext vs ServletRenderContext

chris_lewis
Gah - ServletRenderContext has too many tendrils to the servlet API (it also wants HttpServletResponse). Until a compelling reason can be presented as to why it's superior to DefaultRenderContext, I'm sticking with that (I've pushed the change to my fork: https://github.com/chrislewis/scalate-cli).
Reply | Threaded
Open this post in threaded view
|

Re: Scalate, DefaultRenderContext vs ServletRenderContext

Dustin Whitney
For what it's worth, I chose DefaultRenderContext simply because it's what's used in the Scalate documentation in the "integrating with your web framework" section.  Option 1 in Nathan's proposed options sounds like the most reasonable - I won't have time to get to that this week, so feel free to add it if you've got the time.

D

On Mon, Jan 3, 2011 at 11:35 AM, chris_lewis [via Databinder] <[hidden email]> wrote:
Gah - ServletRenderContext has too many tendrils to the servlet API (it also wants HttpServletResponse). Until a compelling reason can be presented as to why it's superior to DefaultRenderContext, I'm sticking with that (I've pushed the change to my fork: https://github.com/chrislewis/scalate-cli).


View message @ http://databinder.3617998.n2.nabble.com/Scalate-DefaultRenderContext-vs-ServletRenderContext-tp5879227p5880993.html

To start a new topic under Unfiltered, email [hidden email]
To unsubscribe from Unfiltered, click here.

Reply | Threaded
Open this post in threaded view
|

Re: Scalate, DefaultRenderContext vs ServletRenderContext

chris_lewis
Okay, I've pushed a fix to my fork: https://github.com/chrislewis/Unfiltered/commit/63e1951fe7c58f804e9aa55f4d70cc00135508cb

The Scalate responder has a new implicit argument: a function which, given a request, response, and an engine, will produce a RenderContext. ScalateDefaults provides a default implementation of DefaultRenderContext.

The Scalate responder is now parameterized on A, B, which represent the concrete request and response types. It is no longer a ResponseWriter, but a Responder[B]. This allows apps to provide a function that can build the proper RenderContext with static checking. In my app, I'm now successfully using Yasushi's original scalate precompiler, as long as I provide a builder:

import javax.servlet.http.{HttpServletRequest => REQ, HttpServletResponse => RES}

object ServletScalate {
  import org.fusesource.scalate.TemplateEngine
  import org.fusesource.scalate.servlet.ServletRenderContext
 
  implicit def renderContext(req: HttpRequest[REQ], res: HttpResponse[RES], engine: TemplateEngine) =
    new ServletRenderContext(engine, req.underlying, res.underlying, req.underlying.getSession.getServletContext)
}

And of course, import ServletScalate._ for the magic. I like the ability to use the same Scalate responder, as opposed to subclassing / overriding its builder depending on the server environment. Even so, It may still be useful to have a scalate-servlet module to house the implicit. What do you think?

-chris
Reply | Threaded
Open this post in threaded view
|

Re: Scalate, DefaultRenderContext vs ServletRenderContext

n8han
Administrator
On 01/03/2011 02:20 PM, chris_lewis [via Databinder] wrote:

> And of course, import ServletScalate._ for the magic. I like the
> ability to use the same Scalate responder, as opposed to subclassing /
> overriding its builder depending on the server environment.

Yeah, overriding is gross. If we were 2.8-only you could make it a
default argument. Normally I would come at this with an abstract class
or trait that leaves the method undefined, and supply a default
implementation. But I'm cool with the implicit arg too.

> Even so, It may still be useful to have a scalate-servlet module to
> house the implicit. What do you think?

As the guy that does the module publishing, I think that's not worth it. :)

Nathan
Reply | Threaded
Open this post in threaded view
|

Re: Scalate, DefaultRenderContext vs ServletRenderContext

chris_lewis
Isn't the scalate module 2.8 (Only28 trait)? The implicit does have a default value.

On the note of 2.8, if this is the solution I should probably relax the default context. Initially it was effectively type-less because it didn't rely on a server environment - I'll push that to my fork.

The remaining pain is the scalate-cli precompiler (and as a Scalate user Dustin should probably weigh in here). Even with the ability to provide a servlet-specific builder, you're not out of the woods if you precompile. If you don't provide a builder (for a ServletRenderContext) and use the default, you get a DefaultRenderContext while the templates have been compiled for a ServletRenderContext. The devil is in the disjoint. The changes I made are useful *if* one would ever need something other than DefaultRenderContext.

PS pushed https://github.com/chrislewis/Unfiltered/commit/dc1745d9b31a4ff80ef2d078ac825785ce03da43