You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@velocity.apache.org by Fedor Karpelevitch <fa...@excite.com> on 2000/12/13 20:17:50 UTC

[PROPOSAL] new Context stuff.

Hi!

this is a proposal on some changes of Contexts.
the classes of interest are located in whiteboard directory in the cvs
repository.
The proposal actually consists of a few parts (each of them will have
different degree of popularity, i think).
( As always suggestions on better naming, as well as any other suggestions,
are very welcome)
These are the the parts:

1) Make Context an interface so that different implementations can be
provded.
    There will actually be two interfaces: ReadableContext (which provides
read-only access to the context) and Context (whic
h is a read/write context);
    My personal opinion is that ReadableContext should be given preference
since velocity is supposed to provide View functio
nality, e.g. to "interpret" the context and not to modify it. I realize,
though, that many people will not agree with me here
.
    Provide default implementation (DynamicContext - better name is very
welcome) which would have same functionality as exis
ting Context class.
    Since there are now few classes related to contexts it probably makes
sense to move them into a separate package - org.ap
ache.velocity.context;
    Another small change i propose is to change formal parametr names from
"key" to "name" since they are Strings and are cer
tainly names rather than generic keys.
2) more interesting part - enable wrapping or chained contexts. Basic idea
is to allow one context to "wrap" other context, a
nd that context may also be wrapping another context etc..
this will create few interesting possibilities
<what's-in-the-name>
i kinda prefer name "wrapping context" because one context "wraps" another
one proxying access to it, but som people refer to
 them as to "chained contexts" which also makes sense because context are
"chained" together.
</what's-in-the-name>
now to why this is useful. It has few aspects.
First one is creating "scope" contexts, which work cleanly and same stuff is
not being pushed around on each request.
Here is how it works:
 
on app startup you create globalContext and put any stuff which is globally
relevant there. <grrr>some people may place their <evil>context tools</evil>
there </grrr>
then you place globalContext into servlet context (if we are working with
servlets).
when you create a new session you create a new sessionContext which wraps
globalContext and where you can place session-specific stuff (user info
etc.)
then on each request you create a local context which wraps sessionContext
and where you can place objects relevant for this
request only.
 
Another use may be by velocity internally to handle scope issues such as:
when you call a macro it works in the current context this may be a problem,
though,
in the case when a designer uses a library of VMs as a "black box".
If a context var is being set inside a VM it will be visible outside this
macro.
As a result you need to know what var names are used inside VMs and avoid
using them outside.
With wrapping contexts this can bve easily solved by creating a new context
on top of the current one and passing it to VM.
when VM is done this context will go away and current context will stay
untouched.
 
3) Alternative context implementations may be created.
For example:
    PropertyContext - this one hould map to a properties file. This could
work as follows:
        in a props file you have line like:
            project.constants.projectname=YourProjectName;
        You create a PropertyContext and add it to your globalContext:
            ....
            globalContext = new PropertyContext(propsfilename,
"project.constants", innerContext);
            ....
        now in your template you can do:
            ....
            welcome to project $projectname bla-bla
            ....
    FileContext - this one would map to files in a specified dir. Those may
be templates - they would be parsed then, or static files, in which case
their content will be used as-is.
    You can think of DBContext, EJBContext etc., etc... (PLEASE, do not tell
me that these are a bad idea. That's just an example)
 
Implications:
 
 - In VM example above and in some other cases behaviour will change.
     In my opinion this would be more correct behaviour, but it is
different,
     so some templates may stop working as intended.
 
 - Since Context is an interface we can not assume a particular
implementation
     and should not do that. For example we can not assume that lookup is an
inexpensive
     operation. In fact it may be pretty expensive (for example with
FileContext). So we need
     to make sure that lookups are made only when they are actually needed.
Currently if you have
     smth like "on $ale now!" in your template Velocity will attempt to look
$ale in the context every
     time. That may be OK (althogh I would not say so) if you assume context
is fast, but it may be too bad
     if you can't. So this issue needs to be resolved (there will be another
proposal soon, stay tuned!)
 
 - For the same reason ReadableContext does not have contains(), elements()
or keys().
     I do not see much point in having contains(name) becuase 1) it may be
just as expensive as get(name) and 2) I do not see any case where you would
want to do contains() without doing get() anyways, so you only save a trip
through contexts.
     as for elements() and keys(), I did not include them because I do not
see much point in them and also because for some implementations this may be
either impossible at all or too expensive.
 
That's it for this time.
I think I missed a lot, but I hope that's enough to get beaten ;-)
 
fedor.

--
BNTP: Bad News Transfer Protocol





_______________________________________________________
Send a cool gift with your E-Card
http://www.bluemountain.com/giftcenter/



Re: [PROPOSAL] new Context stuff.

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Christoph Reck wrote:

>> [SNIP]
> > on app startup you create globalContext and put any stuff which is globally
> > relevant there. <grrr>some people may place their <evil>context tools</evil>
> > there </grrr>
> 
> +1 for <evil><smile>globalContext</smile></evil>/sessionContext/requestContext.
>    But I agree with Geir, that this should be in the scope of the
>    application to setup (even though VM already does the like,
>    but in my opinion putting them in the wrong #place ;)

But t#at $ymmetry t#at we #ave i$ nice.
 
> I also agree with Geir that there is an issue in VM, where it is needed
> to update (and add -1) the parent context . There must be a notion of local
> and global/parent variables. Geir, the solution I've thought of is using a
> push/pop directive or context tool. After a push all created variables
> are local, and updating works same as a get - so a contains() is essential.

The implementation of VMs on my home machine is exactly that, modulo a
few bugs I am working out : basically a push and pop, but internally,
not at user (mis)direction.  Brought me back to my old assembler days.

> A pop removes all local vars from visiblity. A WM ensures the context is
> stackable (chains one on top if not) does a push when entering and pop
> when exiting. The stackableContext also could provide a getParent() to
> create/update entries there...
> 
> > 3) Alternative context implementations may be created.
> 
> Scope of the application.
> 
> >  - For the same reason ReadableContext does not have contains(), elements()
> > or keys().
> 
> alt least one of them should be in the interface. I see many requirements
> on it... The implementor should take care of caching if it is expensive...
> Geir also handled this point to my satisfaction.
> 
> > I think I missed a lot, but I hope that's enough to get beaten ;-)
> 
> I hope that at least the interface and chaining part goes into Vel.
> 
> :) Christoph

-- 
Geir Magnusson Jr.                               geirm@optonline.com
Velocity : it's not just a good idea. It should be the law.
http://jakarta.apache.org/velocity

Re: [PROPOSAL] new Context stuff.

Posted by Christoph Reck <Ch...@dlr.de>.
I'll keep my responses short ... and snipped the original to get to the 
point.

Fedor Karpelevitch wrote:
> 1) Make Context an interface so that different implementations can be
> provded.

+1 (to bad that the Map interface is to complex to consider taking it up 
    into Vel).

>     There will actually be two interfaces: ReadableContext (which provides
> read-only access to the context) and Context (which is a read/write context);
>     My personal opinion is that ReadableContext should be given preference
> since velocity is supposed to provide View functionality, e.g. to "interpret"
> the context and not to modify it. I realize, though, that many people will 
> not agree with me here

Dito. -0

> 2) more interesting part - enable wrapping or chained contexts. Basic idea
> is to allow one context to "wrap" other context, and that context may also 
> be wrapping another context etc..

+0, +1 for ChainedContext

> on app startup you create globalContext and put any stuff which is globally
> relevant there. <grrr>some people may place their <evil>context tools</evil>
> there </grrr>

+1 for <evil><smile>globalContext</smile></evil>/sessionContext/requestContext. 
   But I agree with Geir, that this should be in the scope of the 
   application to setup (even though VM already does the like,
   but in my opinion putting them in the wrong #place ;)

I also agree with Geir that there is an issue in VM, where it is needed
to update (and add -1) the parent context . There must be a notion of local 
and global/parent variables. Geir, the solution I've thought of is using a
push/pop directive or context tool. After a push all created variables
are local, and updating works same as a get - so a contains() is essential.
A pop removes all local vars from visiblity. A WM ensures the context is
stackable (chains one on top if not) does a push when entering and pop 
when exiting. The stackableContext also could provide a getParent() to 
create/update entries there...

> 3) Alternative context implementations may be created.

Scope of the application.


>  - For the same reason ReadableContext does not have contains(), elements()
> or keys().

alt least one of them should be in the interface. I see many requirements 
on it... The implementor should take care of caching if it is expensive...
Geir also handled this point to my satisfaction.

> I think I missed a lot, but I hope that's enough to get beaten ;-)

I hope that at least the interface and chaining part goes into Vel.

:) Christoph

Re: [PROPOSAL] new Context stuff.

Posted by Rafal Krzewski <Ra...@e-point.pl>.
Fedor Karpelevitch wrote:

> this is a proposal on some changes of Contexts.

Somehow, I can't get rid of the feeling arising from the past
few weeks of more-or-less following Velocity list, that 
you guys are more concerned with building Rocketships To Mars,
than creating a viable replacement for WebMacro.

Which makes me a little bit sad....

Rafal

--
Rafal Krzewski
Senior Internet Developer
mailto:Rafal.Krzewski@e-point.pl
+48 22 8534830 http://e-point.pl

Re: [PROPOSAL] new Context stuff.

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Fedor Karpelevitch wrote:
> 
> Hi!

Howdy!

> 
> this is a proposal on some changes of Contexts.
> the classes of interest are located in whiteboard directory in the cvs
> repository.
> The proposal actually consists of a few parts (each of them will have
> different degree of popularity, i think).
> ( As always suggestions on better naming, as well as any other suggestions,
> are very welcome)
> These are the the parts:
> 
> 1) Make Context an interface so that different implementations can be
> provded.
>     There will actually be two interfaces: ReadableContext (which provides
> read-only access to the context) and Context (whic
> h is a read/write context);
>     My personal opinion is that ReadableContext should be given preference
> since velocity is supposed to provide View functio
> nality, e.g. to "interpret" the context and not to modify it. I realize,
> though, that many people will not agree with me here
> .

I'm one of those people, as allowing the template designer to do things
like using simple math e.g. #set($i = $i + 1)  is helpful for all sorts
of reasons.  Also, since Vel is a general template engine, there are
demonstrated uses where the template will 'communicate' information back
to the calling app.  From what I understand, Torque does this, and I bet
Anakia will eventually :)

So I don't know why one might need a formally specified
'ReadableContext' anyway.  If Context is an interface, you can make your
own context definitions that define their own put() implementations that
don't affect the data, and are loaded some other way.

Then you can strangle your designers as you see fit.

>     Provide default implementation (DynamicContext - better name is very
> welcome) which would have same functionality as exis
> ting Context class.
>     Since there are now few classes related to contexts it probably makes
> sense to move them into a separate package - org.ap
> ache.velocity.context;

or under runtime or util.

>     Another small change i propose is to change formal parametr names from
> "key" to "name" since they are Strings and are cer
> tainly names rather than generic keys.

Not true.  In the InternalContext that is used for internal purposes,
there are non-String references as keys.

> 2) more interesting part - enable wrapping or chained contexts. Basic idea
> is to allow one context to "wrap" other context, a
> nd that context may also be wrapping another context etc..
> this will create few interesting possibilities
> <what's-in-the-name>
> i kinda prefer name "wrapping context" because one context "wraps" another
> one proxying access to it, but som people refer to
>  them as to "chained contexts" which also makes sense because context are
> "chained" together.
> </what's-in-the-name>

I love this idea, as I think there is great potential for application
functionality.  I believe that this would be a good thing to directly
support in a Context interface, (such as a CTOR ->  Context( Context c
) with the chaining delegation in get() up to the implementation) but
strongly feel this is not to be implemented directly as Velocity engine
core code.  For example, I would be very cautious about having Velocity
act as a Context loading and creation engine, controlled perhaps via the
properties
file.  Adding this complexity into the Velocity core is I feel the wrong
place for it, since I think it can be [beautifully] implemented in
app/framework code.

I tend to (mostly) believe that if it can effectively be kept out of the
core, keep it out of the core.

> now to why this is useful. It has few aspects.
> First one is creating "scope" contexts, which work cleanly and same stuff is
> not being pushed around on each request.
> Here is how it works:
> 
> on app startup you create globalContext and put any stuff which is globally
> relevant there. <grrr>some people may place their <evil>context tools</evil>
> there </grrr>
> then you place globalContext into servlet context (if we are working with
> servlets).
> when you create a new session you create a new sessionContext which wraps
> globalContext and where you can place session-specific stuff (user info
> etc.)
> then on each request you create a local context which wraps sessionContext
> and where you can place objects relevant for this
> request only.

Great.  So far, so good.  Perfect.  At all times, you as the programmer
(or the framework) can make an active decision on what goes into the
context based on user access permissions and such.  Or a layered
permissioning/rights model where each layer wraps and adds, covering the
contexts below.  That way, you can implement it so that you don't always
get a 'default' set, like I fear would happen if there was a set of
contexts loaded and chained automatically by Vel core. (You can see I am
worried about the actual implementation proposal :)
 
> Another use may be by velocity internally to handle scope issues such as:
> when you call a macro it works in the current context this may be a problem,
> though,
> in the case when a designer uses a library of VMs as a "black box".
> If a context var is being set inside a VM it will be visible outside this
> macro.
> As a result you need to know what var names are used inside VMs and avoid
> using them outside.
> With wrapping contexts this can bve easily solved by creating a new context
> on top of the current one and passing it to VM.
> when VM is done this context will go away and current context will stay
> untouched.

Mmmm.  Not so sure about this. I've thought about this.  I have been
playing with a new
implementation that takes care of this problem for calling
args, preventing them from 'damaging' the context contents, a problem
critical for successful elegant recursion.  But there are subtleties to
this (as I played
with a context-wrapping approach for a while), as well as you may
indeed *want* to have a VM modify the context.  And with the
template-local context, there is a whole space of tricks and solutions
where 'overriding' globally defined VMs with local ones provides some
interesting power and functionality.

Also, there are solutions to this that can be found in coding
formalisms, such as using a _ at the end of VM-scoped references when
you write VMs, such as #set($foo_ = $blargh + 1 ).  This leaves it to
users choice and control.

> 
> 3) Alternative context implementations may be created.
> For example:
>     PropertyContext - this one hould map to a properties file. This could
> work as follows:
>         in a props file you have line like:
>             project.constants.projectname=YourProjectName;
>         You create a PropertyContext and add it to your globalContext:
>             ....
>             globalContext = new PropertyContext(propsfilename,
> "project.constants", innerContext);
>             ....
>         now in your template you can do:
>             ....
>             welcome to project $projectname bla-bla
>             ....
>     FileContext - this one would map to files in a specified dir. Those may
> be templates - they would be parsed then, or static files, in which case
> their content will be used as-is.
>     You can think of DBContext, EJBContext etc., etc... (PLEASE, do not tell
> me that these are a bad idea. That's just an example)

ToasterContext, PigeonContext,
UpperRightHandDrawerNoTheOtherOneContext...  and I hope you are
intending these to be app-land implementations, like in
applications/frameworks like Turbine or custom frameworks?

> 
> Implications:
> 
>  - In VM example above and in some other cases behaviour will change.
>      In my opinion this would be more correct behaviour, but it is
> different,
>      so some templates may stop working as intended.

That's not good. Even I know that.  :D   And like what?

> 
>  - Since Context is an interface we can not assume a particular
> implementation
>      and should not do that. For example we can not assume that lookup is an
> inexpensive
>      operation. In fact it may be pretty expensive (for example with
> FileContext). So we need
>      to make sure that lookups are made only when they are actually needed.
> Currently if you have
>      smth like "on $ale now!" in your template Velocity will attempt to look
> $ale in the context every
>      time. That may be OK (althogh I would not say so) if you assume context
> is fast, but it may be too bad
>      if you can't. So this issue needs to be resolved (there will be another
> proposal soon, stay tuned!)

But isn't that another app judgement?  I mean, Anakia uses a jdom
document tree in the context for the template to access, and, at least
to this C++ programmer, it's slow.  Damn slow.  But it doesn't matter,
as the application isn't time-critical.  It's an off-line 'worker
task'.  Granted, that isn't a context per se...

So the speed of your own context implementation is a judgement
for the implementor based on application requirements.  Velocity can't
divine the need.

(And your filter thing should do the trick :)

> 
>  - For the same reason ReadableContext does not have contains(), elements()
> or keys().
>      I do not see much point in having contains(name) becuase 1) it may be
> just as expensive as get(name) and 2) I do not see any case where you would
> want to do contains() without doing get() anyways, so you only save a trip
> through contexts.

Well, suppose it was a SendACamelToCairoContext : you might have the
list of keys locally, but need to send that Camel off to Cairo to get
the actual data.  So contains() might make sense.

>      as for elements() and keys(), I did not include them because I do not
> see much point in them and also because for some implementations this may be
> either impossible at all or too expensive.

I think there is a point.  Suppose you were handed a context object from
a higher level, say the global context in a framework.  Wouldn't it be
nice to be able to see whats in there in an iterative way rather than
taking random potshots into get() attempting to find what you need?   Or
in the case where a template communicates with the Java app via the
context, if a template adds  n items of a possible set M to the
context,   I would prefer a iterator to work with to see what's there.

And where it's impossible or expensive, they should return null or
something?  I mean, I figure that these are routines used in java,
rather than in a template, so it's manageable.
 
> That's it for this time.
> I think I missed a lot, but I hope that's enough to get beaten ;-)

If not beaten, a good flogging, I think. :)

> 
> fedor.
> 
> --
> BNTP: Bad News Transfer Protocol
> 
> _______________________________________________________
> Send a cool gift with your E-Card
> http://www.bluemountain.com/giftcenter/

-- 
Geir Magnusson Jr.                               geirm@optonline.com
Velocity : it's not just a good idea. It should be the law.
http://jakarta.apache.org/velocity

Re: [PROPOSAL] new Context stuff.

Posted by Jon Stevens <jo...@latchkey.com>.
on 12/13/2000 11:17 AM, "Fedor Karpelevitch" <fa...@excite.com>
wrote:

> Hi!
> 
> this is a proposal on some changes of Contexts.
> the classes of interest are located in whiteboard directory in the cvs
> repository.
> The proposal actually consists of a few parts (each of them will have
> different degree of popularity, i think).
> ( As always suggestions on better naming, as well as any other suggestions,
> are very welcome)
> These are the the parts:
> 
> 1) Make Context an interface so that different implementations can be
> provded.
> There will actually be two interfaces: ReadableContext (which provides
> read-only access to the context) and Context (whic
> h is a read/write context);
> My personal opinion is that ReadableContext should be given preference
> since velocity is supposed to provide View functio
> nality, e.g. to "interpret" the context and not to modify it. I realize,
> though, that many people will not agree with me here
> .

Does that have an effect on #set then?

> Provide default implementation (DynamicContext - better name is very
> welcome) which would have same functionality as exis
> ting Context class.
> Since there are now few classes related to contexts it probably makes
> sense to move them into a separate package - org.ap
> ache.velocity.context;

Maybe it should be:

org.apache.velocity.runtime.context

> Another small change i propose is to change formal parametr names from
> "key" to "name" since they are Strings and are cer
> tainly names rather than generic keys.

Huh?

> 2) more interesting part - enable wrapping or chained contexts. Basic idea
> is to allow one context to "wrap" other context, a
> nd that context may also be wrapping another context etc..
> this will create few interesting possibilities
> <what's-in-the-name>
> i kinda prefer name "wrapping context" because one context "wraps" another
> one proxying access to it, but som people refer to
> them as to "chained contexts" which also makes sense because context are
> "chained" together.
> </what's-in-the-name>

-0 on wrapping context
+1 on chained

> now to why this is useful. It has few aspects.
> First one is creating "scope" contexts, which work cleanly and same stuff is
> not being pushed around on each request.
> Here is how it works:
> 
> on app startup you create globalContext and put any stuff which is globally
> relevant there. <grrr>some people may place their <evil>context tools</evil>
> there </grrr>
> then you place globalContext into servlet context (if we are working with
> servlets).

+1

> when you create a new session you create a new sessionContext which wraps
> globalContext and where you can place session-specific stuff (user info
> etc.)
> then on each request you create a local context which wraps sessionContext
> and where you can place objects relevant for this
> request only.

Ok, to be clear, so you have two contexts:

sessionContext which is persistent across requests
requestOnlyContext which is not persistent across requests

right?

> Another use may be by velocity internally to handle scope issues such as:
> when you call a macro it works in the current context this may be a problem,
> though,
> in the case when a designer uses a library of VMs as a "black box".
> If a context var is being set inside a VM it will be visible outside this
> macro.
> As a result you need to know what var names are used inside VMs and avoid
> using them outside.
> With wrapping contexts this can bve easily solved by creating a new context
> on top of the current one and passing it to VM.
> when VM is done this context will go away and current context will stay
> untouched.

I would much rather that the user doesn't have to even know/worry about
context scope. It may be harder to implement this, but I think that we
should work towards that instead of away from it.

> 3) Alternative context implementations may be created.
> For example:
> PropertyContext - this one hould map to a properties file. This could
> work as follows:
> in a props file you have line like:
> project.constants.projectname=YourProjectName;
> You create a PropertyContext and add it to your globalContext:
> ....
> globalContext = new PropertyContext(propsfilename,
> "project.constants", innerContext);
> ....
> now in your template you can do:
> ....
> welcome to project $projectname bla-bla
> ....
> FileContext - this one would map to files in a specified dir. Those may
> be templates - they would be parsed then, or static files, in which case
> their content will be used as-is.
> You can think of DBContext, EJBContext etc., etc... (PLEASE, do not tell
> me that these are a bad idea. That's just an example)

-1 for inclusion in Velocity. I think that this should happen at the
framework level (ie: Turbine).

> Implications:
> 
> - In VM example above and in some other cases behaviour will change.
> In my opinion this would be more correct behaviour, but it is
> different,
> so some templates may stop working as intended.

A proposal would define exactly what and how things would change. :-) You
haven't done that. :-)

> - Since Context is an interface we can not assume a particular
> implementation
> and should not do that. For example we can not assume that lookup is an
> inexpensive
> operation. In fact it may be pretty expensive (for example with
> FileContext). So we need
> to make sure that lookups are made only when they are actually needed.
> Currently if you have
> smth like "on $ale now!" in your template Velocity will attempt to look
> $ale in the context every
> time. That may be OK (althogh I would not say so) if you assume context
> is fast, but it may be too bad
> if you can't. So this issue needs to be resolved (there will be another
> proposal soon, stay tuned!)

cool.

> - For the same reason ReadableContext does not have contains(), elements()
> or keys().
> I do not see much point in having contains(name) becuase 1) it may be
> just as expensive as get(name) and 2) I do not see any case where you would
> want to do contains() without doing get() anyways, so you only save a trip
> through contexts.
> as for elements() and keys(), I did not include them because I do not
> see much point in them and also because for some implementations this may be
> either impossible at all or too expensive.

Ok.

> That's it for this time.
> I think I missed a lot, but I hope that's enough to get beaten ;-)

You missed a LOT. :-) I'm confused by a lot of what you said. :-(

-jon


-- 
Honk if you love peace and quiet.