Message: java.lang.NoClassDefFoundError: javax/mail/Address
net.liftweb.mapper.MetaMegaProtoUser$class.sendValidationEmail(ProtoUser.scala:213)
com.crap.model.User$.sendValidationEmail(User.scala:9)
net.liftweb.mapper.MetaMegaProtoUser$class.testSignup$1(ProtoUser.scala:227)
net.liftweb.mapper.MetaMegaProtoUser$$anonfun$innerSignup$1$1.apply(ProtoUser.scala:240)
net.liftweb.mapper.MetaMegaProtoUser$$anonfun$innerSignup$1$1.apply(ProtoUser.scala:240)
net.liftweb.http.S$SFuncHolder$$anonfun$apply$42.apply(S.scala:719)
net.liftweb.http.S$SFuncHolder$$anonfun$apply$42.apply(S.scala:719)
scala.List.map(List.scala:724)
net.liftweb.http.S$SFuncHolder.apply(S.scala:719)
net.liftweb.http.LiftSession$$anonfun$buildFunc$1$2.apply(LiftSession.scala:101)
net.liftweb.http.LiftSession$$anonfun$7$$anonfun$apply$8.apply(LiftSession.scala:111)
net.liftweb.http.LiftSession$$anonfun$7$$anonfun$apply$8.apply(LiftSession.scala:111)
scala.List.map(List.scala:724)
net.liftweb.http.LiftSession$$anonfun$7.apply(LiftSession.scala:111)
net.liftweb.http.LiftSession$$anonfun$7.apply(LiftSession.scala:104)
scala.List.flatMap(List.scala:1036)
net.liftweb.http.LiftSession.runParams(LiftSession.scala:104)
net.liftweb.http.LiftSession$$anonfun$processRequest$1.apply(LiftSession.scala:170)
net.liftweb.http.LiftSession$$anonfun$processRequest$1.apply(LiftSession.scala:156)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$wrapQuery$1.apply(S.scala:272)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$.net$liftweb$http$S$$wrapQuery(S.scala:269)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21$$anonfun$apply$22$$anonfun$apply$23$$anonfun$apply$24$$anonfun$apply$25$$anonfun$apply$26.apply(S.scala:292)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21$$anonfun$apply$22$$anonfun$apply$23$$anonfun$apply$24$$anonfun$apply$25.apply(S.scala:291)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21$$anonfun$apply$22$$anonfun$apply$23$$anonfun$apply$24.apply(S.scala:290)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$.net$liftweb$http$S$$initNotice(S.scala:211)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21$$anonfun$apply$22$$anonfun$apply$23.apply(S.scala:289)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21$$anonfun$apply$22.apply(S.scala:288)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21.apply(S.scala:287)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20.apply(S.scala:286)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17$$anonfun$apply$18$$anonfun$apply$19.apply(S.scala:285)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17$$anonfun$apply$18.apply(S.scala:284)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1$$anonfun$apply$17.apply(S.scala:283)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_init$1.apply(S.scala:282)
net.liftweb.http.S$.net$liftweb$http$S$$doAround(S.scala:252)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$doAround$1.apply(S.scala:253)
net.liftweb.util.ThreadLazy.apply(Lazy.scala:83)
net.liftweb.http.S$.net$liftweb$http$S$$doAround(S.scala:253)
net.liftweb.http.S$.net$liftweb$http$S$$_init(S.scala:281)
net.liftweb.http.S$$anonfun$init$2$$anonfun$apply$29.apply(S.scala:338)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$$anonfun$init$2.apply(S.scala:337)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:24)
net.liftweb.http.S$.init(S.scala:336)
net.liftweb.http.LiftSession.processRequest(LiftSession.scala:155)
net.liftweb.http.LiftServlet.doService(LiftServlet.scala:220)
net.liftweb.http.LiftServlet$$anonfun$doIt$1$1.apply(LiftServlet.scala:108)
net.liftweb.http.LiftServlet$$anonfun$doIt$1$1.apply(LiftServlet.scala:106)
net.liftweb.util.Helpers$.calcTime(Helpers.scala:845)
net.liftweb.util.Helpers$.logTime(Helpers.scala:831)
net.liftweb.http.LiftServlet.doIt$1(LiftServlet.scala:106)
net.liftweb.http.LiftServlet.service(LiftServlet.scala:112)
net.liftweb.http.LiftFilter.lift(LiftServlet.scala:749)
net.liftweb.http.LiftFilter.doFilter(LiftServlet.scala:709)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
So I have like 2 ideas:
1) Perhaps have a mechanism that ensures that all dependencies are present upon startup of the webapp
2) An automatic routine that stores debug-information about errors that occur runtime (which user, at what time, with what parameters, giving what error)
Any input on this?
Cheers,
-V
java.lang.Thread.run(Unknown Source)
Reading through the LiftServlet source, I see that David is using the
Development Run Mode to switch between showing the exception and
throwing it away. That's reasonable but it highlights that most of us
don't know the difference between Development and Production mode in
Lift. I guess this means I'm deploying in Development mode.
An error handling method I've used in the past that worked well was to
have a function that determined whether to spit out the error page or
to send it somewhere else based on the HttpRequest. For instance, if
the user was in a special debug mode or was from an internal address
then spit out the exception, otherwise show a clean error page and do
something else with the actual error like email it, send it to a
message queue, etc.
If nobody gets around to cleaning this up, I'll improve it in a few
weeks to work the way I describe.
Steve
This happens with any exception that bubbles to the top.
Reading through the LiftServlet source, I see that David is using the
Development Run Mode to switch between showing the exception and
throwing it away. That's reasonable but it highlights that most of us
don't know the difference between Development and Production mode in
Lift. I guess this means I'm deploying in Development mode.
An error handling method I've used in the past that worked well was to
have a function that determined whether to spit out the error page or
to send it somewhere else based on the HttpRequest. For instance, if
the user was in a special debug mode or was from an internal address
then spit out the exception, otherwise show a clean error page and do
something else with the actual error like email it, send it to a
message queue, etc.
If nobody gets around to cleaning this up, I'll improve it in a few
weeks to work the way I describe.
Fire away. What do you think?
> What's your take on the dependency checking?
For my own app, I'm moving towards a one-jar approach to avoid this
issue and others. I would build a single jar, run my staging tests
using it, and once I'm satisfied, I would push that to production
servers.
Steve
Fire away. What do you think?
On Feb 9, 2008 11:11 AM, Viktor Klang <viktor...@gmail.com> wrote:
> I suggest having a discussion around the subject and see what a
> consensus-situation would look like.
For my own app, I'm moving towards a one-jar approach to avoid this
> What's your take on the dependency checking?
issue and others. I would build a single jar, run my staging tests
using it, and once I'm satisfied, I would push that to production
servers.
Steve
Yeah, I like it. It's easy for people to write their own subclass of
ErrorReporter. A method in LiftServlet can be used to supply the
ErrorReporter.
> > > What's your take on the dependency checking?
> >
> > For my own app, I'm moving towards a one-jar approach to avoid this
> > issue and others. I would build a single jar, run my staging tests
> > using it, and once I'm satisfied, I would push that to production
> > servers.
> >
>
> Agreed, but not having to write tests for it would be even better.
Staging is independent of tests, it's where you look at it with eyeballs,
either your own or your QA teams.
Steve
Yeah, I like it. It's easy for people to write their own subclass of
On Feb 9, 2008 11:31 AM, Viktor Klang <viktor...@gmail.com> wrote:
> On Feb 9, 2008 8:22 PM, Steve Jenson <ste...@gmail.com> wrote:
> >
> >
> > On Feb 9, 2008 11:11 AM, Viktor Klang <viktor...@gmail.com> wrote:
> > > I suggest having a discussion around the subject and see what a
> > > consensus-situation would look like.
> >
> > Fire away. What do you think?
>
> I'm opting for a pluggable strategy pattern so /lift/ users can use whatever
> notification method they see fit. We supply the plumbing and data, and then
> they can provide the plugins.
>
> Something along the lines of:
>
> ErrorReporter
> |
> |----------- EmailErrorReporter
> |----------- XMPPErrorReporter
> |----------- DBErrorReporter
> |----------- FileErrorReporter
> |----------- etc...
ErrorReporter. A method in LiftServlet can be used to supply the
ErrorReporter.
Staging is independent of tests, it's where you look at it with eyeballs,
> > > What's your take on the dependency checking?
> >
> > For my own app, I'm moving towards a one-jar approach to avoid this
> > issue and others. I would build a single jar, run my staging tests
> > using it, and once I'm satisfied, I would push that to production
> > servers.
> >
>
> Agreed, but not having to write tests for it would be even better.
either your own or your QA teams.
Steve
Folks,
In LiftServlet:/**
* The partial function (pattern matching) for handling converting an exception to something to
* be sent to the browser depending on the current RunMode (development, etc.)
*
* The best thing to do is browserResponseToException = { case (...) => } orElse browserResponseToException
* so that your response over-rides the default, but the processing falls through to the default.
*/
var browserResponseToException: PartialFunction[(Props.RunModes.Value, RequestState, Throwable), ResponseIt] = {
So... this is a Partial Function. It defines when is done with Exceptions happen in each runmode.
Anything you want to do can be done here.
You can return different error pages depending on the runmode and the exception type (e.g., an SQL exception might return a certain kind of page, where a MatchError might return something else). You can send the exception information to other sources.
So... what that you guys want to do cannot be achieved with this structure?
What kind of helpers (partial functions that can be composed by application developers) do any of you want to write?
Thanks!
Steve
You even documented that you could use it that way and I still didn't
notice. I will write some customized helpers and document them here in
a few weeks when I need them. It's on my work to-do list.
On Feb 10, 2008 7:12 PM, Steve Jenson <ste...@gmail.com> wrote:
You even documented that you could use it that way and I still didn't
notice. I will write some customized helpers and document them here in
a few weeks when I need them. It's on my work to-do list.
Yeah, and imagine what it's like for a newcomer...
What do you think about a LiftConfig? (Something that exposes the configuration of /lift/ in an easy-acces & sensible way)
On 2/10/08, Viktor Klang <viktor...@gmail.com> wrote:On Feb 10, 2008 7:12 PM, Steve Jenson <ste...@gmail.com> wrote:
You even documented that you could use it that way and I still didn't
notice. I will write some customized helpers and document them here in
a few weeks when I need them. It's on my work to-do list.
Yeah, and imagine what it's like for a newcomer...
Part of the issue is that lift does things "differently" than most other frameworks. lift makes heavy use of partial functions for customization. That's not going to change. Using classes or stuff that implements interfaces a la Java becomes goat rodeo that leads right down the XML path to hell.
As Rails has demonstrated, configurations as in-language DSLs is the best way to go and Partial Functions are an excellent declarative way of structuring a DSL.
I've localized the vast majority of these customization points in LiftServlet. And, yes, the other customizations that one does in Boot should probably happen in LiftServlet or some other conveniently named object rather than the sprawl that's starting to happen.
And also, this stuff needs to get documented. And yes, there needs to be a "cook book" for common operations. Perhaps we can construct the cook book by folks on the list asking questions and I'll answer the questions and someone with a good organizational sense can organize the answers on the wiki.
What do you think about a LiftConfig? (Something that exposes the configuration of /lift/ in an easy-acces & sensible way)
That's what the LiftServlet object is.
On Feb 11, 2008 12:08 AM, David Pollak <feeder.of...@gmail.com> wrote:
On 2/10/08, Viktor Klang <viktor...@gmail.com> wrote:On Feb 10, 2008 7:12 PM, Steve Jenson <ste...@gmail.com> wrote:
You even documented that you could use it that way and I still didn't
notice. I will write some customized helpers and document them here in
a few weeks when I need them. It's on my work to-do list.
Yeah, and imagine what it's like for a newcomer...
Part of the issue is that lift does things "differently" than most other frameworks. lift makes heavy use of partial functions for customization. That's not going to change. Using classes or stuff that implements interfaces a la Java becomes goat rodeo that leads right down the XML path to hell.
As Rails has demonstrated, configurations as in-language DSLs is the best way to go and Partial Functions are an excellent declarative way of structuring a DSL.
Agreed, given that the injection point is intuitive and the amount of code to inject into the PF has few LoC.
Overusage of classes suck major donkey equipment, but as containers of code to distribute they are clearly more suited than the old C-send-a-patch-way of doing it.
(imagine you've written a good XMPPErrorReporter, and you want to send it to DaveB so he can utilize it.
I've localized the vast majority of these customization points in LiftServlet. And, yes, the other customizations that one does in Boot should probably happen in LiftServlet or some other conveniently named object rather than the sprawl that's starting to happen.
Also agreed, configuration should be intuitive and be kept in a single place (or a few places, but they are easily located and are intiutively named).
And also, this stuff needs to get documented. And yes, there needs to be a "cook book" for common operations. Perhaps we can construct the cook book by folks on the list asking questions and I'll answer the questions and someone with a good organizational sense can organize the answers on the wiki.
What do you think about a LiftConfig? (Something that exposes the configuration of /lift/ in an easy-acces & sensible way)
That's what the LiftServlet object is.
Then I suggest we rename it. No Java WedDev is ever going to look to do configuration in something names <X>Servlet. (And other devs might not even know what a Servlet actually is supposed to be)
My suggestion :
* Extensions (widgets lib, error reporter ,...) should have an activate method (like Activator in Eclipse plugin).
* activate method should be call explicitly from Boot (no auto-detection, scan of jar,...)
* activate method are like Boot but at the extension level (where Boot is at application level)
An interesting things could be to define a convention for Extensions'activate (name and location)
Like this extension could be normal jar (with one or several "activators"), and to use an extension add the jar and activate it.
/davidB
Viktor Klang wrote:
>
>
> On Feb 11, 2008 12:08 AM, David Pollak <feeder.of...@gmail.com
> <mailto:feeder.of...@gmail.com>> wrote:
>
>
>
> On 2/10/08, *Viktor Klang* <viktor...@gmail.com
> <mailto:viktor...@gmail.com>> wrote:
>
>
>
> On Feb 10, 2008 7:12 PM, Steve Jenson <ste...@gmail.com
> <mailto:marius...@gmail.com>> wrote:
> > >
> > >
> > >
> > > On Feb 9, 7:25 pm, "Viktor Klang"
> > > > SGS member (Scala Group Sweden)
> > > > SEJUG member (Swedish Java User Group)
> > > > \_____________________________________/
> > >
> > > > >
> > >
> >
>
> /lift/ committer (www.liftweb.net
> SGS member (Scala Group Sweden)
> SEJUG member (Swedish Java User Group)
> \_____________________________________/
>
>
>
>
> --
> lift, the secure, simple, powerful web framework http://liftweb.net
> Collaborative Task Management http://much4.us
>
>
>
>
>
> --
> _____________________________________
> / \
> /lift/ committer (www.liftweb.net <http://www.liftweb.net>)
I've localized the vast majority of these customization points in LiftServlet. And, yes, the other customizations that one does in Boot should probably happen in LiftServlet or some other conveniently named object rather than the sprawl that's starting to happen.
Also agreed, configuration should be intuitive and be kept in a single place (or a few places, but they are easily located and are intiutively named).
And also, this stuff needs to get documented. And yes, there needs to be a "cook book" for common operations. Perhaps we can construct the cook book by folks on the list asking questions and I'll answer the questions and someone with a good organizational sense can organize the answers on the wiki.
What do you think about a LiftConfig? (Something that exposes the configuration of /lift/ in an easy-acces & sensible way)
That's what the LiftServlet object is.
Then I suggest we rename it. No Java WedDev is ever going to look to do configuration in something names <X>Servlet. (And other devs might not even know what a Servlet actually is supposed to be)
I'll think about it.
It means breaking every bit of lift code in existence and that's a big break. I'm not sure of the benefits because all of the configuration that's done in the example code is done on LiftServlet.
actual :
* every "configuration" should drive by code (we all agree)
* Boot class is the location of the configuration/customisation of the webapp
My suggestion :
* Extensions (widgets lib, error reporter ,...) should have an activate method (like Activator in Eclipse plugin).
* activate method should be call explicitly from Boot (no auto-detection, scan of jar,...)
* activate method are like Boot but at the extension level (where Boot is at application level)
An interesting things could be to define a convention for Extensions'activate (name and location)
Like this extension could be normal jar (with one or several "activators"), and to use an extension add the jar and activate it.
IMHO OSGi is heavy (and overdesigned), but there is good ideas.
>
>
>
> An interesting things could be to define a convention for
> Extensions'activate (name and location)
>
> Like this extension could be normal jar (with one or several
> "activators"), and to use an extension add the jar and activate it.
>
>
> hmm, do you have some kind of example to show what you mean?
If I pick the ErrorReporter example provide by DavidP :
In the lib :
package xmpper;
object XmppErrorReporter {
def reportAndContinue(originalPf: ErrorReportingPF): ErrorReportingPF = {
case v @ (_, e, _) => reportWithXmpp(e)
originalPF(v)
}
def reportWithXmpp(e: Throwable) {
// send the report out via XMPP
}
}
object Activator {
def activate_XmppErrorReporter() = {
LiftServlet.browserResponseToException = XmppErrorReporter.reportAndContinue(LiftServlet.browserResponseToException)
}
def dispose_XmppErrorReporter() = {
}
}
In the app that wish to use XmppErrorReporter, instead of read a doc, copy/paste a code (that could change in futur version)
class Boot {
def boot {
//...
xmpper.Activator.activate_XmppErrorReporter()
mywidgets.Activator.activate() // register resources toserve,...
//...
}
}
It is a very simple Lifecycle management.
Now, to be a usable solution, we need to have a common convention about Activator :
* names, location, type (class, object, trait),...
* do we call activate method/function directly or register them (or instance of Activator)
* how to avoid twice activation
...
Is it clearer ? (it's a draft reply to how to package/distribute component (error reporter, widgets,...)
/davidB
>
> -V
>
>
>
>
> /davidB
>
> Viktor Klang wrote:
> >
> >
> > On Feb 11, 2008 12:08 AM, David Pollak
> <feeder.of...@gmail.com <mailto:feeder.of...@gmail.com>
> > <mailto:feeder.of...@gmail.com
> <mailto:feeder.of...@gmail.com>>> wrote:
> >
> >
> >
> > On 2/10/08, *Viktor Klang* <viktor...@gmail.com
> <mailto:viktor...@gmail.com>
> > <mailto:viktor...@gmail.com
> <mailto:viktor...@gmail.com>>> wrote:
> >
> >
> >
> > On Feb 10, 2008 7:12 PM, Steve Jenson <ste...@gmail.com
> <mailto:ste...@gmail.com>
> > <mailto:feeder.of...@gmail.com
> > <mailto:marius...@gmail.com
> <mailto:marius...@gmail.com>>> wrote:
> > > >
> > > >
> > > >
> > > > On Feb 9, 7:25 pm, "Viktor Klang"
> > <viktor.kl...@gmail.com
> <mailto:viktor.kl...@gmail.com> <mailto:viktor.kl...@gmail.com
> <mailto:david.be...@gmail.com>> wrote:IMHO OSGi is heavy (and overdesigned), but there is good ideas.
>
>
> actual :
> * every "configuration" should drive by code (we all agree)
> * Boot class is the location of the configuration/customisation of
> the webapp
>
>
> Don't forget *Bootable*
> It'll allow for extensions
>
>
>
> My suggestion :
> * Extensions (widgets lib, error reporter ,...) should have an
> activate method (like Activator in Eclipse plugin).
> * activate method should be call explicitly from Boot (no
> auto-detection, scan of jar,...)
> * activate method are like Boot but at the extension level (where
> Boot is at application level)
>
>
> Are you referring to an OSGi approach?
Marius wrote:
> forgot about fixHtml so the above becomes:
>
> LiftServlet.browserResponseToException = {
> case (mode, state, ex) => {
> val node = S.session match {
> case Full(s) => (s.fixHtml(s.processSurroundAndInclude("/
> error.html", s.findAnyTemplate("/error.html" :: Nil) openOr
> Text("Error page not found")))) theSeq(0)
> case _ => <br/>
> }
>
> XhtmlResponse(node, ResponseInfo.docType(state), List("Content-
> Type" -> "text/html"), 500)
> }
> }
>
In general, I would not make any S or session related calls in the error
handler. If an exception was thrown, that means that the system is in
an unstable state.
I'd load the error template at object instantiation time (rather than at
exception processing time) and change up any of the context information
(the LiftServlet.context object should be populated when Boot is called,
so you've got the context and can look up resources based on the context.)
If you need some lightweight routines to load resources and parse them
based just on the Context and also to do XHTML bind substitution, I can
separate those routines out for you.