... Continued from previous message
* Calling an alien API through the Request interface.
This happens when you are implementing a Renderer or a tag library.
The renderer receives a Request parameter and has to adapt it into
whatever API is required by the underlying technology. The difficult
part is passing the appropriate scopes from the request to the
underlying API.
First of all, there are two algorithms to do it. The first and most
natural one may not be the best:
{code}
List<String> scopes = r.getAvailableScopes();
for (int i = scopes.size() -1; i >= 0; --i) {
Map<String, Object> scope = r.getContext(scopes.get(i));
for(Entry<String, Object> attr: scope.entrySet()) {
// add attribute to the underlying context
}
}
{code}
The better alternative is to write an adapter:
{code}
underlyingContext = new UnderlyingContext() {
public Object getAttribute(String name) {
Object result = null;
List<String> scopes = r.getAvailableScopes();
for (String scopeName: scopes) {
Map<String, Object> scope = r.getContext(scopeName);
result = scope.get(name);
if(result != null) break;
}
return result;
}
};
{code}
Why is it better? The first algorithm accesses all attributes from all
scopes exactly once. The second one only accesses the attributes you
actually use in the template. Even if it may access them several times,
a typical template only does it once, while a typical session may
contain many attributes in a large application (session scoped beans in
spring/JSF, theme-related parameters, ...) that are not used in a
specific template.
This is especially true when using tiles, because your web page is
divided into many small templates that shall each require a separate
call to the renderer.
Another, more serious difficulty is when the underlying API is not
providing all the features of the Request. You may want to pass the
original Request "through" the underlying API, in order to retrieve it
later in a taglib, for instance.
Two schools here: setting an attribute in the underlying API (like
most web-centric technologies: JSP, tomcat, struts, tiles, liferay, ...)
or using a ThreadLocal (like Spring MVC or Spring Security or JSF). I
don't think I've seen a third way, and I really don't know which one is
better.
The ThreadLocal option has the advantage of being "clean": it does not
invade the namespace of the request. But it requires careful coding with
regard to exception management (use try...finally), or if the renderer
in some way has to call itself (i.e. a freemarker template includes
another freemarker template). The ThreadLocal must be restored to its
initial state upon exit from the renderer, no matter what happened. It
may also become awkward when you're trying to implement some
asynchronous processing (comet-like), Spring has had a hard time with that.
The attribute option is inherently safe for asynchonous environments,
and easy to code, but needs to be addressed in a different
implementation for each technology even if the name of the attribute is
standard (I'm using Request.class.getName()), and thus a little more
coding is involved, and maybe some kind of code duplication.
I'd like it if we could choose a single way of doing it here at apache
tiles. What do you think?
TBC...