Carsten Ziegeler skrev:
Daniel Fagerstrom wrote:
Can you give some specific examples where you need this?
We often have the problem to get the current service manager. The whole
code base contains various calls to the EnvironmentHelper class to get
this service manager.
For those in the audience that don't know all about Cocoon internals:
The environment helper contains a thread local stack. Each time a
sitemap is entered the current environment and processor (containing a
reference to the local service manager of the sitemap) are pushed on the
stack. The information is poped when the sitemap is left.
The reason for using the environment helper is that we need to lookup
some components relative to the service manager of the sitemap that
currently is executed, rather than relative to the service manager that
the currently executed component happened to be defined in.
The most prominent example of where we need this is for the source resolver.
The way it works today is that the component calls e.g. the static
method EnvironmentHelper.getSitemapServiceManager(). While this works it
breaks IOC and makes it much harder to unit test the component or to
reuse it outside the Cocoon sitemap. It also makes the code really hard
to follow.
========
A more abstract way to express the above is that we want some (uses of)
components, e.g. the current source resolver, to have *sitemap scope*.
E.g. what source resolver we get depends on what sitemap that currently
is executed.
In Spring 2.0 there is a mechanism called bean scopes that solves this
problem. There are a number of provided bean scopes: singleton,
prototype, request, session and global session
(http://static.springframework.org/spring/docs/2.0.x/reference/beans.html#beans-factory-scopes).
It also allows for custom scopes. We could implement a sitemap scope
(and a block scope). With this we could define the sitemap scoped source
resolver as:
<bean id="oac...currentSourceResolver"
class="oac...CocoonSourceResolver"
scope="sitemap">
<!-- dependecies ... -->
<aop:scoped-proxy/>
</bean>
Then e.g. a pipeline can depend on it:
<bean id="oac...pipeline"
class="oac...CachingProcessingPipeline"
scope=prototype">
<property name="currentSourceResolver"
ref="oac...currentSourceResolver"/>
<!-- dependencies ... -->
</bean>
The element "aop:scoped-proxy" creates a proxy for the current source
resolver that delegates to the actual current source resolver when a
dependent component use it.
Behind the scene the implementation of a sitemap scope will still use a
thread local call stack that needs to be pushed while entering a sitemap
and poped while leaving. But the components does not have to know
anything about this anymore, they are pure DI components that are easy
to understand, reuse and unit test.
The above (probably) requires that we deavalonize the affected beans and
make the DI POJOs instead. But IMO we should start do deavalonize Cocoon
core anyway.
One main reason for this are utility methods like
we have in the SourceUtil class. A caller of these utility classes
should not need to get the container just in order to call the utility
stuff.
I agree that it is more convenient to not need to use the container, but
I don't think the consequences make it worthwhile in the end.
Another problem in this area is that components might be able to
get the container they were declared in, but not the current container.
This is for example important when you're running in a sub sitemap.
sitemap scope!
Then we have various occasions were someone needs some information from
the request object, like the current uri or some request parameter or to
use this to create an http servlet request wrapper to call some other
stuff. Now, one solution is of course to pass the request object down to
the place where you need it, but this of course would mean that your
implementation might have an impact on your interfaces which is not
really nice.
You might guess my opinion about this by now ;) Anyway Spring has a
RequestContextListener, RequestContextHolder combo that might be reused
for this. It just handles the request attributes, but the needed parts
of the request object could be put in some attributes.
Spring has some kind of request scope for beans together with a servlet
filter for setting up the scope it has also mechanisms for keeping
dependencies on request scoped beans up to date. This is a fairly
structured and controlled way to handle request scoped information. And
it keeps DI and testability. Would it be enough for your needs?
Hmm, not sure - I have not really looked into this stuff. But from my
understanding Spring is using ThreadLocals for this as well :)
It certainly does (not much choice I guess). But the point is that it
embeds it in such away that the components still can use pure IOC, no
need for the components to pull any info from static methods.
Sorry to be negative, but global variables is really an anti pattern. So
I'd like to discuss the specific problem and see if we can find a
cleaner solution first.
To be honest, I'm happy to discuss this stuff with someone. Ok,
rethinking a little bit, what about making the current request object
available? This contains the current container as an attribute and it's
possible to get everything else from the container.
I think that a sitemap scope could solve a large part of our needs.
WDYT?
/Daniel