On Sun, 2002-11-24 at 21:53, Nicola Ken Barozzi wrote:
> Stephen McConnell wrote:
> > Leo Sutic wrote:
> >> Fourth, you do not provide any reason at all for a context. Reading your
> >> mail, my conclusion would be to dump the Context completely. I think it
> >> has been shown that everything can be realized as a service, and then
> >> we would not be limited to constant-value lookup (which is more suitable
> >> for a Configuration anyway).
> >
> > Your making the assumption that a container can only provide canstant
> > -values in context. I don't agree with assumption. Take for example a
> > container that is providing an activation timestamp, the key-chain of
> > the invoking user, and a classloader. These values will typically be
> > different in every application of contexualize. These values canot be
> > expressed in a configuration, or parameters, or under the Serviceable or
> > Composable interfaces.
(aside: just about any context material can be put in a service instead
with enough effort:
blah = context.get("blah");
VS
blahservice = service.get("blahservice");
context = blahservice.getContext();
blah = context.get("blah");
so that last sentence is not true. It is also not the issue ;)
Abstract
--------
> Then please comment on the below code.
> What's the real difference?
separation of concerns. The rest of this rather lengthy e-mail tries to
explain by example. The point I make at the end of the e-mail is that
regardless of the real differences, it is best if only one of the
patterns is followed.
The easy answer
---------------
> How can a coder easily decide what to use?
He looks at what the container(s) he wants to use provide him with. If
the container doesn't provide him with the information he needs, he has
to add it himself in some form. The easiest way to add this
functionality is to get a TimestampService from a central repository.
A container developer has to choose between providing "very clean and
lean" and providing "the kitchen sink".
Avalon has to concern itself with trying to make the job easy for the
component developer, and to lesser extend the container developer.
Extended example
----------------
Let's abuse that timestamp example:
Timestamp appStarted = (Timestamp) context.get(
CommonContextKeys.STARTUP_TIMESTAMP );
Timestamp appRestarted = (Timestamp) context.get(
CommonContextKeys.RESTART_TIMESTAMP );
Timestamp componentStarted = (Timestamp) context.get(
CommonContextKeys.COMPONENT_RESTART_TIMESTAMP );
Timestamp componentRestarted = (Timestamp) context.get(
CommonContextKeys.COMPONENT_RESTART_TIMESTAMP );
this is all information that could be argued should come from the
container (if it is to be provided, that is, which is a different topic
altogether ;). The difference with
TimedContext context = (TimedContext)c;
Timestamp appStarted = context.getStartupTimestamp();
Timestamp appRestarted = (Timestamp) context.getRestartTimestamp();
Timestamp componentStarted = (Timestamp)
context.getComponentStartTimestamp();
Timestamp componentRestarted = (Timestamp)
context.getComponentRestartTimestamp();
is mostly syntax sugar. Now consider:
Timestamp currentTimeInBrazil = (Timestamp) context.get(
CommonContextKeys.CURRENT_TIME_IN_BRAZIL_IF_WE'RE_TRAVELING_AT_HALF_THE_SPEED_OF_LIGHT
);
or even:
Timestamp currentTimeInBrazil = (Timestamp)
context.getCurrentTimeInBrazilIfWereTravelingAtHalfTheSpeedOfLight();
which is clearly not good because one can certainly not expect a
container (let alone all containers) to keep track of the current time
in Brazil, let alone know about quamtum mechanics. _If_ there is a
container which supports this kind of stuff, you can be rather sure it's
the only one!
Now the grey area:
Timestamp currentTime = (Timestamp) context.get(
CommonContextKeys.CURRENT_TIME );
which is where things get hairy. This is of course mapped to
System.getCurrentTime() (or whatever that is called), but to make the
example valid assume that such a method does not exist and the container
talks to the OS (or some time server) to figure this out.
Would it be possible to extract out the code from the container that
talks to the OS and make it into a service? Probably. You get:
Timestamp appStarted = context.getStartupTimestamp();
Timestamp appRestarted = (Timestamp) context.getRestartTimestamp();
Timestamp componentStarted = (Timestamp)
context.getComponentStartTimestamp();
Timestamp componentRestarted = (Timestamp)
context.getComponentRestartTimestamp();
Would that be smart? That depends. Perhaps talking to the OS is
something you want to enable the container to do but not hosted
components (ie security).
Should you then use some kind of security management kernel plug-in for
this? Depends. Perhaps you know for certain that this is the only case
where a component needs to talk to the underlying OS directly and you
don't want all the security complexity and overhead.
The long answer
---------------
If your problems are simple enough it seems rather silly to bother with
a framework at all (example: using phoenix to run a component that
prints 'hello world' to the console); debating which approach is the
best becomes real difficult.
Separation of concerns is the hardest thing to do in software
architecture. There's not always a definite answer.
Thing is (important point!), from the "One Framework" point of view, the
use of services vs the use of context means the common ground shared
between containers can be smaller while having components that are still
portable across containers.
If you depend on a getBlahStuff() in a SpecificContainerContext, you
cannot move your component into a container that doesn't provide you
with getBlah() (usually you won't be able to move your component into a
container that doesn't provide you with a SpecificContainerContext).
If your component depends on a BlahStuff being available as a service
(where BlahStuff is provided by the SpecificContainer), you can use
BlahStuff inside AnotherContainer as long as it is possible to create a
BlahStuff service yourself that can run in AnotherContainer.
Real-life example
-----------------
As a concrete example, from the current BlockContext (inside phoenix
CVS):
/**
* Retrieve the MBeanServer for this application.
*
* NOTE: Unsure if this will ever be implemented
* may be retrievable via CM instead, or perhaps in
* a directory or whatever.
*/
//MBeanServer getMBeanServer();
Now, if phoenix where to indeed provide access to the MBeanServer (which
is at the core of the JMX management extensions) this way, and you have
a component that depends on that, a requirement for moving that
component to Merlin (or EOB, plexus, or "Avalon Container for J2ME"....)
is that Merlin also exposes an MBeanServer in this way (atm, Merlin has
no clue about what an MBeanServer is).
OTOH, if a component gets at that MBeanServer through a ServiceManager,
you can move that component to Merlin without problems, as long as you
are able to find or write an MBeanServer that can also run in Merlin.
Even when component portability is not a problem (there's only "The
Official Avalon Container" and no-one is allowed to make another one or
they'll be visited by the feds), there's a compatibility problem when
"The Official Avalon Container" wants to switch from providing an
MBeanServer to providing a SoapServer, or wants to switch to a new
version of the JMX spec.
Of course, if you make things dynamic enough all these problems go away.
Doing lots of dynamic proxying would certainly get us somewhere (cost:
the container code becomes more and more complex); using a weakly typed
language might solve this as well.
Wrapping up
-----------
Anyway, see the differences now?
Regardless of what we figure is the best way to all this in the end, it
is beneficial to both component developers and container developers if
the way to handle this stuff becomes a widely applied pattern if
possible. If both phoenix, merlin, EOB and James provide a
CURRENT_TIME_IN_BRAZIL_IF_WE'RE_TRAVELING_AT_HALF_THE_SPEED_OF_LIGHT,
but the code you need to get at it is different in every one of them,
that's no good. That is why it is worth spending countless hours
discussing all this :D
long live the lengthy e-mail, g'night,
- Leo
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>