Jonathan Revusky <[EMAIL PROTECTED]> writes:
From my experience, I think you can basically say that any Context object is a hashtable of some sort. So, it is probably feasible just to use java.util.Map and, if necessary, convert the Map into the concrete class when needed in the concrete implementation. The whole thing looks quite trivial.
// in Velocity-specific concrete class, approximately: void processTemplate(Map someMap, String templateLocation, Writer out) { VelocityContext vc = new VelocityContext(someMap); Template t = Velocity.getTemplate(templateLocation); Velocity.mergeTemplate(templateLocation, vc, out); }
// in FreeMarker-specific concrete class, you just use the Map directly // since the conversion from the Map object occurs transparently. void processTemplate(Map someMap, String templateLocation, Writer out) { Template t = Configuration.getTemplate(templateLocation); t.process(someMap, out); }
I mean, the fundamental pattern of usage is just so similar that abstracting it out and simply using whatever template engine from a common API is really quite a trivial exercise.
This apples to apples comparisons is a natural first step, and provides solid examples. An apples to zucchini comparison is also helpful, since the use cases which don't fit a model are the ones which cause its users the most trouble.
Well, presumably you'd go through a preview or beta part of the release cycle, where such issues would have a chance to come up, and the API is not yet written in stone.
Actually, for example, I think that the API I gave above is lacking in one significant respect. It should take a Locale object as a parameter. Then the FreeMarker implementation would look like:
void processTemplate(Map someMap, String templateLocation, Writer out, Locale locale) {
Template t = Configuration.getTemplate(templateLocation, locale);
t.process(someMap, out);
}
Then the getTemplate() method used would be one that takes the locale as an argument. It also means that the template would have an associated locale, so that decimal numbers and time/date objects get transparently formatted by default locale conventions.
Of course, the extremely streamlined Velocity template engine has no such locale-awareness, so the locale argument would simply be ignored by the Velocity implementation and could perfectly well be null. However, note that, if Velocity development is resumed, and these kinds of i18n features are introduced, then having the extra locale param could be useful for the Velocity service as well. I mean, it is useful to anticipate things that could possibly be necessary at a future point, so that you don't paint yourselves into a corner.
In any case, I think that things like this would likely come up in a preview or beta cycle where things are more subject to change than a release candidate or stable release. And then you'd freeze the API when things got past the beta part of the cycle.
I ran through a few such comparisons, and a Map-based context handles all use cases for the input processing step (objects are simply gloried hashtables). One doesn't always want to involve character encodings in content generation (e.g. for binary output), so using a generic Object interface for output is preferred to coupling the API to Writer. This also handles output of more complex types (e.g. DOM trees, etc.).
>
> public interface ContentGenerationSystem
> {
> /**
> * Performs content generation, converting its inputs to the
> * appropriate CGS-specific types.
> *
> * @param context Contextual information used as inputs to the
> * content generation system. May be <code>null</code>.
> * @param target The target to generate content for. May be
> * <code>null</code> if <code>context</code> contained sufficient state.
> * @param output Where to send the generated content.
> */
> void generateContent(Map context, String target, Object output);
> }
>
>
> If multiple output types are supported, generateContent() can use the
> instanceof operator to choose the appropriate action.
Well, it depends what you think you're abstracting. To my way of thinking, a template engine is a system for generating text. You take a reusable template, and a data model, and from those two things, a procesing job generates a bunch of text. As such, to say that it pipes its output into a Writer seems reasonable to me. In general, I think you're better off using core Java API's, like java.util.Map and java.io.Writer, that java programmers are familiar with. It becomes quite clear immediately to people what is going on: a Map is an object that represents a set of key->value mappings and a Writer is an object through which you can pipe text. It also means that any custom Map or Writer implementations that people come up with should be usable in this spot.
Now, it is true that an XSLT transformation engine is not exactly a template engine. It actually transforms one tree into another tree, and the fact that the tree it creates can be output as text is sort of incidental. However, if you're abstracting away an XSLT transformation engine as if it's purely a text generation tool, i.e. treating it as a template engine, then you could perfectly well have it use the Writer. It simply outputs the serialized text version of the tree into the writer.
And of course, if you have a separate "tree transformation service" of which XSLT is kind of the archetype, then you could have a separate API and have your XSLT-related object implement that interface as well, so it's not as if you're really painting yourself into a corner by saying that a template engine service takes a Writer as an argument and shoves text through it.
Now, there clearly is interest on the part of some users to be able to try FM from Turbine. I've seen signs of that on this list and I have some private email that bears this out. So my earlier offer still stands: Get your house in order on this stuff, and I'll help you get it working. But the ball is currently in your court on this.
Personally, I'd be very happy to see FreeMarker available in Turbine again, so long as its integration is supported by an active developer. The original reason it was dropped was a lack of both developer support and user interest.
Well, frankly, when I look at the sheer scope of Turbine as a project, and compare that with the technical difficulty of keeping a FreeMarkerXXXService.java sort of code synched up with the latest FreeMarker, the latter seems quite trivial.
As for the lack of user interest, I have already stated (perhaps ad nauseam) that this is something of a contrived half-truth. Just given the fact that the last FreeMarker version "supported" was extremely obsolete, it is quite obvious that this would not elicit any end-suer interest. The only way you could say in a fair-minded good-faithed way whether there was significant end-user interest in FreeMarker or anything else would be if the current version were supported on an equal footing.
But look, if there is a clear API to implement with a clear contract, by which you plug a template engine into Turbine -- and if the rest of the framework uses that API and doesn't couple directly with Velocity classes -- i.e. if you have your house in order on this, I guess I would commit to keeping it working. It strikes me as a trivial enough task that I could commit to that.
But until you get things to that state, it's all rather hypothetical.
Regards,
Jonathan Revusky -- lead developer, FreeMarker project, http://freemarker.org/
I'd be even more happy to see a light-weight content generation abstraction (something like what's outlined above), replacing what's in Turbine 3.
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
