Quinton McCombs wrote:
-----Original Message-----
From: Bill [mailto:[EMAIL PROTECTED] Sent: Wednesday, June 18, 2003 8:15 AM
To: Henning P. Schmiedehausen
Cc: turbine-user
Subject: Re: Decimal Number support



Henning


I think working on Freemarker support would be a waste of the developers valuable time.


It would not be a waste of time is people are interested in using it.


However, divorcing Turbine from Velocity to allow more flexibility not only seems like a good idea, it seems absolutely necessary if the I understand the path to Avalonization.


I agree with you that the flexibility would be a very good thing.

Our view architecture is really not very plugable.  The problem is that
once you start writing your actions and screen classes which accept
RunData and Context as parameters, you are become tied to the view
implementation.  This was very much a shortcoming of the core design of
Turbine.

What you say is interesting, Quinton. In terms of the discussion at hand, I think a clear distinction really ought to be made. I mean, there's the question of whether it is *inherently* desirable to support other view technologies (such as FM) as well as Velocity.


Then there is the question of whether it is pragmatic given the current architecture. Now, one trap I think you guys should avoid is arguing that it is *inherently* undesirable to support FM simply because, given the current architecture, it is messy or a lot of work to do so. Because that's really a separate issue that should not be confused.

But anyway, I have a technical point to make about this. I suspect that, at least in terms of FM integration, even the inflexible architecture you describe does not pose much of a problem. FM is currently architected flexibly enough that there are fairly straightforward solutions.



Hennings idea to create a proxy class to represent the context type object of the underlying view is indeed a good way to solve this problem. It would require deprecating the methods that everyone normally overrides in the screen and action classes. The replacement would be virtually the same interface replacing Context with the new class.

Even if we do not decide to support FreeMarker, I think that it would be
in our best interests to implement the proxy class for the context.
Right now, if your view is JSP and you want to switch to Velocity or
visa-versa, you must modify all of your action and screen classes.  Not
fun.

Yeah, I guess I should throw you guys a bone on this.


Turbine may be poorly architectured in this regard, but FreeMarker is not. Consider the following FreeMarker API:

http://freemarker.org/docs/api/freemarker/template/ObjectWrapper.html

What an ObjectWrapper instance does is that it "wraps" (converts, really) an arbitrary object to a FreeMarker TemplateModel. In fact, the ObjectWrapper API was specifically designed with MVC framework writers in mind. Basically, it provides an extra level of indirection, where you can transparently convert application-level business objects to presentation-level objects. The setting of an ObjectWrapper instance basically is a point at which you can define a policy on that.

There are several default implementations of the ObjectWrapper API that you could use as extension points. Probably you'd use freemarker.template.DefaultObjectWrapper. Like this:

public class CustomWrapper extends DefaultObjectWrapper {
    public TemplateModel wrap(Object obj) throws TemplateModelException
    {
       if (obj instanceof VelocityContext) {
           VelocityContext vc = (VelocityContext) obj;
           SimpleHash result = new SimpleHash(this);
           Object[] keys = vc.getKeys();
           for (int i=0; i<keys.length; i++) {
              result.put(keys[i], vc.get((String) keys[i]);
           }
           return result;
       }
       return super.wrap(obj);
    }
}

The above is a trivial subclass of the default ObjectWrapper implementation that will check whether something is a VelocityContext, convert it to the appropriate FM API, and if it's not that, then it just falls back on the default behavior. You get it, right?

Now, elsewhere, to set the above custom ObjectWrapper implementation as the default used, you would need to do something like:

freemarker.template.Configuration.getDefaultConfiguration().setObjectWrapper(new CustomWrapper());

What this means is that when you expose an object to the template, it will, by default, now use the CustomWrapper. As you can see by eyeballing the source code, the CustomWrapper "knows" how to convert a VelocityContext object to an object that FM can deal with.

In particular, what it also means is that in the process() calls here:

http://freemarker.org/docs/api/freemarker/template/Template.html#process(java.lang.Object,%20java.io.Writer)

you could pass in a VelocityContext as the rootMap object and all the right things would simply happen transparently!

So, you see, FreeMarker has a very flexible architecture that allows you to deal with even this kind of silly rigidity described fairly easily and elegantly.

IOW, if you implement the appropriate ObjectWrapper instance, FreeMarker will deal transparently with whatever data-side objects you throw at it! The little bit of magic above requires about a dozen lines of code.

I hope that's illuminating.

Best Regards,

Jonathan Revusky
--
lead developer, FreeMarker project, http://freemarker.org/
FreeMarker-Velocity comparison, http://freemarker.org/fmVsVel.html




--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to