Leo,
I'm mostly comfortable with the definition you've given. I commend you for attempting a non-partisan solution to this issue. I'd like to propose that for this effort *you* are seen to lead the dialogue and dissentors to definitions suggest patches to you, rather that write some 10 page redifinition. Fingers crossed we all use <snip/> etc as appropriate.
the Context interface and its associated stage - Contextualizable - has been the subject of much controversy. As a matter of fact, I'd say that it is the single most controversial subject we have in Framework, and I'd like to propose a way where I think the conflicting viewpoints can be accomodated, although this will require some compromise.
-oOo-
[...]
[...]Note, Phoenix's 'things' delivered by BlockContext are not only entries in maps. requestShutdown (for example) is an action rather than a lookupable thing. Usage :
As for the actual type of the context instance being given to the component:
Merlin:
The component specifies a context class C. That class is instantiated with the constructor taking one Context parameter. This instance is then given to the component. (This was as I understood it from Stephen's emails, I haven't found any code doing this in the assembly or meta packages, so I might be way off here.)
Phoenix:
A BlockContext implementation is given directly to the component. No way for the component to specify any other class.
Note that both containers completely solve the problem so far as to having a way to specify the expected key-value mappings accessible in the Context.
blockContext.requestShutdown();
It could not be used like so ..
((ShutdownHandler) context.get("shutdownhandler")).requestShutdown();
What is needed is a way to specify what methods should be avilable in addition to a way to specify key-value mappings accessible via the Context.get method. This is needed in order to be able to capture the Phoenix BlockContext interface. With both meta-models, you can specify a requirement for any key K to map to an object of any type V, and using the standardized context keys, you can specify the meaning of the value V. However, neither allows you to require a method called requestShutdown() that requests a shutdown. While Merlin allows you to specify an implementation class, that method can not be used to provide a BlockContext.
I guess, you've just defined what I said above.
What I intend to add is the following:
+ A way to specify what mehods are required in the context.
+ A restriction on what methods may be required while still remaining 100% Avalon compatible.
How to Specify Methods:
The component will declare one class name designating an interface. This can be done like this:
<context>
<require-interface name="org.apache.avalon.phoenix.BlockContext"/>
</context>
This indicates that the context object being passed to contextualize() must be cast-able to a BlockContext. This is read as: "The component requires that all methods in the BlockContext interface is present in the context, and that the context object given can be casted to a BlockContext."
Sounds plausible.
A Restriction on Methods:I like the sound of that. It is similar to something I wafted out some weeks ago.
There will be a set of standard interfaces in Framework. Any component may request any union of those interfaces. For example, if we have in framework:
interface WorkDirectoryContext {
public File getWorkDirectory ();
}
interface ContextDirectoryContext {
public File getContextDirectory ();
}
A component may have an interface: interface MyContextInterface extends ContextDirectoryContext, WorkDirectoryContext {};
:-)
And may specify that interface:
<context>
<require-interface name="org.example.MyContextInterface"/>
</context>
And can expect to have the request fulfilled in any 100% Avalon container. (Alternatively we can limit interfaces to Avalon Micro Edition, SE, or EE, depending on the profiles we come up with for the übercontainer.) Note that this does in no way exclude specifying key-value pair requirements. A component can specify key-value pairs, an interface, both or neither.
A final restriction on the methods are that the method signatures must be unique. That is, if we in framework have two interfaces:
interface WorkDirectoryContext {
public File getDirectory ();
}
interface ContextDirectoryContext {
public File getDirectory ();
}
With identical signatures, a union of those interfaces
interface MyContextInterface
extends ContextDirectoryContext,
WorkDirectoryContext
{};
will only have one method, and furthermore it is *impossible* to determine through which interface a call was made. That is:
MyContextInterface mci = ...;
// These two method calls are indistinguishale.
// There is no way, even with dynamic proxies,
// for the mci object to know whether the context
// directory or the work directory should be returned.
((WorkDirectoryContext) mci).getDirectory ();
((ContextDirectoryContext) mci).getDirectory ();
Agree.
We can ease that restriction by only requiring method signatures in the interfaces in Framework to be unique, but this would make it harder to promote a method into Framework. Obvious conclusion: these context interfaces should be kept to a minimum.That is not true. Real world companies who's codebases you have no visibilit of use that feature.
What we allow in Framework:
It is my view that the methods in Framework should be limited to simple data-access methods, such as getWorkDirectory and getContextDirectory, and that methods such as requestShutdown should be left out. The reasoning behind this is as follows:
+ There is major controversy regarding the exposure of services, such as requestShutdown (in particular that one).
+ Few components in Phoenix uses that method.
+ In fact, I think most Phoenix blocks only use the getContextDirectory method.
Your visibility again.
+ Therefore, we can lower the requirements on those blocks, thus making them portable.If is is to be the case that some interfaces ( a core set) are inside A-F, then fine, it already liked that adea. If we understand that people will make specialised containers that build on A-F concepts and they can have their own Context derivatives, then that is fine too.
+ For the few blocks that *do* require a requestShutdown or similar, they can declare a requirement of BlockContext.
+ Those few blocks will remain non-portable, but I guess they are so few that it doesn't matter.
Also, it is my opinion that:
+ Addition of a context interface to Framework should be via consensus vote.
+ Domain-specific contexts, such as EJB contexts and servlet contexts, should not be allowed into Framework, as neither EJBs nor Servlets are Avalon components.
Agree.
-oOo-... in what ever way the container sees fit. Non need to use A-F default impls as long as the interfaces are honored.
PROVIDING A CONTEXT
-------------------
In the previos section I established that a component may place two types of requirements on a context:
1) Key-value mappings.
2) Methods in the context interface.
How to provide (1) is a solved problem and there is concensus on it.
As for (2), I expect the container to have some class that implements Context:
class ContextImpl implements Context { ... }
That class should implement *all* Framework-level interfaces:
class ContextImpl implements Context,
WorkDirectoryContext, ContextDirectoryContext { ... }
[..]
-oOo-Sounds good. We must not forget that the MailetContext is ficticious though (respect for the JAMES team).
Summary:
I have shown a way to declare a context requirement for components that captures all current usage patterns, and shown how the requirement can be satisfied by a container. The methods shown here can be used to define ServletContexts, EJB contexts, etc. as well. In particular, they can be used to define the Phoenix BlockContext and the JAMES MailContext. Portability suffers a little, but not enough to make it an issue.
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>