blob: db3998ffce0a94b232facaf411bd4ea3236ed392 [file] [log] [blame]
<?xml version="1.0"?>
<!--
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<document>
<properties>
<title>Unified Templating Service Proposal</title>
</properties>
<body>
<section name="Unified Templating Service">
<p>
There are multiple templating services that provide similar functionality, but
have different API. This is due to different types of "Context" objects. All
these types main"Map" semantics (question: is there any other important
functionality in the Contexts?). We could define a single service interface
that all of the templating services (WebMacro, Velocity, FreeMarker and JSP at
the moment) would implement. Its methods would use Map type to represent a
Context or another interface extending or similar to map. The service would
include the following methods:
</p>
<pre>
public interface TemplatingService
extends Service
{
public boolean templateExists( String name );
public Map createContext( RunData data );
public Map createContext( );
public Strinq merqeTemplate( String name, Map context );
}
</pre>
<p>
Definition of this common interface would allow creation of new base Modules
(Screen, Navigation, Layout and Page) that would take advantage of the
templating abstraction provided by the Service. This would make the modules
(esp. Screens) contained in the application independent of the particular
templating mechanism.
</p>
<p>
I don't know enough about FreeMarker to tell if it can fit into this model.
If not, I would even suggest dropping the support for it, as it's user base
seems nonexistent.
</p>
<p>
There is one important special case to consider. JSP service is unable to return
the results of template merging as a String - they are written to the Response
stream directly. To encompass this case in our framework, we could declare that
the return value of merge template in this case is a null. The Modules would be
subject to the same semantics: a null returned from build() method would mean that
data was written to the response directly, and the caller should act accordingly.
(an example of such case is the interaction of the Layout and the RawScreen).
</p>
<p>
The special semantics of JSP templating lead in turn to a special Page and Layout
module behavior. While the "normal" Layout module executes the Screen module
and merges its template before merging it's own template ("prefix" rendering),
the JSP Layout needs to wrap Screen rendering in a context tool so that it is
executed in the appropriate place in the Layout's markup. ("infix" rendering).
The same patterns apply to Page-Layout interaction. We have the option to define
JSPPage and JSPLayout Modules, or define InfixPage, InfixLayout and the
LayoutRenderer and ScreenRenderer context tools, that will be used with those
templating services that write the merging results directly to the Response
stream. Note that during the normal Layout processing, the Navigations are
subject to "infix" rendering, and the current TemplateNavigation class is a
prototype of *Renderer.
</p>
<p>
The unified interface and the Infix* Modules will make adding support for other
templating engines easy. This will also make porting applications easier -
templates in one templating language can be created, then supporting Turbine
modules are created. Later the templates can be converted to another language,
and the only change to support that on the code side of things is switching a
property in TR.props
</p>
<p>
The template lookup functionality that is currently contained in
TemplateService, probably should be contained in the service I'm describing here,
probably in an abstract base class.
</p>
<p>
Another class that would be affected by the changes mentioned here is the
TempateInfo class. Right now it uses a HashTable to store it's data.
Now, thanks to defining the common Context type (or using the Map type
in its place), it's possible to turn the runtime typed HashTable entries into
compile time typed instance variables.
</p>
<p>
The amount of work needed to port an existing application should not be very large.
The applications following the Pull MVC design model would not be affected at all.
The traditional Push applications would require changes in the Screen and Navigation
classes regarding the names of the Context type and the parent type of the
Screen/Navigation in question. These changes can be effectively introduced using an
automated tool.
</p>
<p>
The Page and Layout classes would require more in-depth modifications, but a typical
application would contain single customized Page and Layout classes, if any.
</p>
</section>
</body>
</document>