OK, I've gotten my head round the kernel in a sort-of kind-of
way.
My basic problem with it is the management of block instances.
(I absolutely love it in every other respect.)
1. Singletons
I have repeatedly (both in my own development and based on
questions from users) seen the need for a singleton design
pattern. I.e. when a block instance corresponds to some
physical resource that can't be virtualized. For example,
a database connection (if you're only allowed one), can
be shared among several clients, but you must still have
a singleton that manages that single connection.
For Cocoon, one could argue that such blocks should be
outside of Cocoon, but this is not always possible.
2. Reloading
When I first read about this framework the plan was to
simply drop the block when it was being reloaded, no matter
if it was currently executing a method call, or whatever.
Then after some discussion the idea was to keep the new block
and the old block side by side and gradually phase out the
old block as it was released by clients.
However, I think this will lead to unpredictable behavior.
This type of lazy reloading will cause problems, even more
problems than the usual ones you get when reloading classes.
2a. Stale classes
One problem is when you retain a reference to a class that
is about to become reloaded. For example:
interface Templates {
public TransformerHandler getTransformerHandler ();
}
interface MyBlock {
public Templates getTemplates ();
}
and the impls: TemplatesImpl, MyBlockImpl.
Suppose you get a handle to MyBlock. Then you get the Templates
from it. Then the MyBlockImpl block is reloaded. When you call
getTransformerHandler on the Templates you just retrieved, will
you execute the old code or the new code? Obviously, the old
code.
Will this old code work with the new classes that has been reloaded
in the rest of the system?
Maybe.
Suppose a you have a SSL block. Further suppose that a bug has
been discovered in it and you have to get it patched.
With the side-by-side running, I have *no guarantee* that the new
block is active.
2b. Multiple blocks stepping on each other's toes
Suppose a block accesses some kind of resource that only accepts
one client, meaning that the block must serialize access to
that resource. This can be done via synchronized wrapper
methods, mutexes or whatever.
But if you suddenly have two instances of the block... Well, you've
pretty much had it then.
You risk not only a crash, but that ***wrong stuff*** is being done
***without a crash***. The resource may be stateful:
interface AccountCursor {
public void moveToAccount (String account);
public void withdraw (int amountOfEuro);
public void put (int amountOfEuro);
}
What would happen if two block instances accessed this resource
in parallell? No errors, but a messed up account DB.
3. Over-reliance on Administrator Omniscience
Linked to the "maybe" in 2a.
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=108032323410266&w=2
Thing, that (by the way) will _NEVER_ happen automagically, but only
when the administrator decides that it's time to reload a block
instance?
So, why should we bother with these problems? The administrator
knows when a block can be reloaded, right?
Wrong.
What sane admin will hit the reload button, unless he knows
with some certainty what will happen, or that the system will
crash instead of trashing important databases if something goes
wrong?
Frankly, I'll be too scared to use this reloading functionality.
And then what's the point?
I can also answer the question immediately before the quote above:
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=108032323410266&w=2
What's the difference between that, and loosing the connection
for a second with a component?
When a connection is lost it is *lost*. It has well defined behavior. It
has easily understood effects on the code. It has *visible* effects on
the code (Exceptions being thrown everywhere).
With this lazy reloading scheme, or any reloading scheme that doesn't
involve locking, you won't get any exceptions, but you'll get a whole
lot of nasty errors that will not leave any other trace except a trashed
server after a few hours of running bad code.
/LS