You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Leo Sutic <le...@inspireinfrastructure.com> on 2004/03/31 13:08:21 UTC
[Kernel2.2] Comments
Nice work!
Some quick observations:
1. @author <a href="http://www.vnunet.com/">VNU Business
Publications</a>
Is this OK with Apache and VNU?
2. Wire.java
/**
* <p>Check wether the wire between this {@link Wirings} instance
and the
* original component is still active.</p>
*
* <p>When this method returns <b>true</b> all methods called on
this
* instance will be forwarded to the original component instance
associated
* with this wire.</p>
You cannot guarantee that. The instance may be redeployed between
the call
to wired() and the next call.
No point in having a method whose return value means nothing.
3. Component.java:
/**
* <p>Contextualize this {@link Component} component instance with
the
* {@link Wire} through which its caller is accessing it.</p>
*
* @param wire the {@link Wire} instance associated with this
instance.
*/
public void contextualize(Wire wire);
Does this mean that each component instance only has one wire? I.e.
only one client? You may end up with a lot of components if you have
component A depends on B, C, D, which depends on E, F, G, H...
Wouldn't it be better to keep this as a ThreadLocal variable that
can
be accessed by the component? Then you can have multiple clients,
but only one client per calling thread (which seems like a
reasonable
tradeoff).
4. Wirings.java
Talks about ((Wiring)myObject).release();
Should be ((Wire)myObject).release();
#include <my/usual/bitching/about/the/wired()/method>
5. Configuration.java
public class Configuration extends ArrayList
I'd use composition instead...
6. Parameters.java
Get rid of this one. Why can't components accept a hierarchy of
configuration nodes as configuration data?
7. Configurable.java
Should accept Configuration instead of Parameters. Being able to
send in a tree-structure of config info instead of a flat list is
useful.
8. Block.java
Love it.
9. Identifier.java
*
<p><code>protocol://location/path/major.minor(.revision)?</code></p>
Does this mean that all Blocks are automatically mapped into a URL
space?
Still trying to get my head around the rest.
/LS
Re: [Kernel2.2] Comments
Posted by Pier Fumagalli <pi...@betaversion.org>.
On 31 Mar 2004, at 13:42, Leo Sutic wrote:
>> From: Pier Fumagalli [mailto:pier@betaversion.org]
>>
>>> Some quick observations:
>>>
>>> 1. @author <a href="http://www.vnunet.com/">VNU Business
>>> Publications</a>
>>> Is this OK with Apache and VNU?
>>
>> Defintely OK with VNU (if someone visits our site because of a click
>> on
>> the JavaDOC, and then come back, we got one more customer... If you
>> guys don't want to see it in there, you can remove it no
>> problems... It is in my default Java class template.
>
> I have absolutely no problems with this. Just wondered if it had been
> left in accidentally.
Fixed, I moved it to the CREDITS.txt
>>> 2. Wire.java
>>> /**
>>> * <p>Check wether the wire between this {@link Wirings}
>>> instance and the
>>> * original component is still active.</p>
>>> *
>>> * <p>When this method returns <b>true</b> all methods called
>>> on this
>>> * instance will be forwarded to the original component instance
>>> associated
>>> * with this wire.</p>
>>>
>>> You cannot guarantee that. The instance may be redeployed
>>> between the call
>>> to wired() and the next call.
>>>
>>> No point in having a method whose return value means nothing.
>>
>> This method will return true until the block instance will not be
>> destroyed or replaced by the Deployer, and when this method returns
>> false, whoever got this wire should release it and acquire a new one
>> (which will be got from the new block instance).
>>
>> Rember? The idea is never to completely remove blocks until
>> forced to, so the Wire instance will still work even if wired()
>> returns
>> false. The wire will only be deactivated by either a call to
>> release() or
>> dispose() or by a forceful destruction by the deployer.
>
> I'd still like this to be transparent...
>
> Having a coding convention that requires you to do wired() checks
> before every call is bad in my opinion.
>
> What you can do is have an:
>
> Wire.ensureWired()
>
> which will do:
>
> if (!wired()) {
> // renew proxy target
> }
>
> Then the client can call the method before it starts processing. I.e.
> the client notifies the framework that "if you want to drop this
> instance, now is a good time".
AH! :-) Now I see what you ment in your previous emails! :-)
Yeah, I like it, non trivial to implement (as it might happen that in
"ensureWired" you won't be able to access a new component instance in
the original composer because of a some sort of exception), but what
the heck...
>>> 5. Configuration.java
>>>
>>> public class Configuration extends ArrayList
>>>
>>> I'd use composition instead...
>>
>> ??? extends AbstractList ???
>
> No, I meant:
>
> public class Configuration {
>
> private final List nodes = new ArrayList();
>
> ...
> }
Don't like it, you loose the whole "List" interface which is quite
useful when working with stuff... I so darn hate both SAX and DOM which
re-implement lists, sets and maps with their own interfaces. KISS (keep
it simple and STANDARD) :-P
>>> 9. Identifier.java
>>>
>>> *
>>> <p><code>protocol://location/path/major.minor(.revision)?</code></p>
>>>
>>> Does this mean that all Blocks are automatically mapped into a
>>> URL space?
>>
>> All blocks have a unique identifier. And this list agreed that each
>> block identifier will assume the requirements specified in the
>> Identifier interface.
>
> Yes, I'm with you so far. But what does the URL really signify? What if
> I put the URL into my web browser? Will I download the block? Or?
What do you get when you point your browser to the namespace of HTML?
<html xmlns="http://www.w3.org/1999/xhtml"/ >
Pier
Re: [Kernel2.2] Comments
Posted by Stefano Mazzocchi <st...@apache.org>.
Leo Sutic wrote:
>>> 9. Identifier.java
>>>
>>> *
>>><p><code>protocol://location/path/major.minor(.revision)?</code></p>
>>>
>>> Does this mean that all Blocks are automatically mapped into a
>
> URL
>
>>>space?
>>
>>All blocks have a unique identifier. And this list agreed that each
>>block identifier will assume the requirements specified in the
>>Identifier interface.
>
>
> Yes, I'm with you so far. But what does the URL really signify?
It's a URI, not necessarely a URL.
> What if I put the URL into my web browser? Will I download the block? Or?
eheh, just like everybody else, we don't know :-)
But the idea is to have an RDDL-like descriptor that the block deployer
can use as metadata and infer information from it (like external
dependencies and those type of things).
I'm typing this from the HP Labs in Bristol where the entire semantic
web activity is hosted, so I hear the walls say "use RDF, use RDF" like
mermaids to Ulisses, but that's a story for another day ;-)
--
Stefano.
Re: [Kernel2.2] Comments
Posted by Tim Larson <ti...@keow.org>.
On Wed, Mar 31, 2004 at 03:33:19PM +0200, Leo Sutic wrote:
> 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.
Keep this "Crash-Only Software" paper in mind:
http://www.stanford.edu/~candea/papers/crashonly/crashonly.html
Gracefull reloads would be very nice, but only if we can guarantee
that we can quarantine against the problems that Leo details.
What if we made crash-only (immediate drop and add) the default
for safety, and then make it possible via special documentation,
practices, and interfaces to support gracefull reloads of only
certain carefully constructed blocks where it is worth the effort.
--Tim Larson
Re: [Kernel2.2] Comments
Posted by Pier Fumagalli <pi...@betaversion.org>.
On 31 Mar 2004, at 18:35, Leo Sutic wrote:
>>> 2. Reloading
>>> 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.
>>
>> Not maybe, yes... The ClassLoading paradigm associates every single
>> class with its own classloader implementation. Old classes
>> will retain old classloaders and will work as if nothing has
>> happened...
>
> I don't understand what you base that "yes" on. Will the classloading
> work? Yes, it will. But will *the* *rest* of the system work? You have
> no guarantee at all.
I wrote 3 servlet containers in my life... :-) I can guarantee that
class loading _will_ work, and it will be entirely transparent by
component/composer classes.
>> It's how it works with servlet containers (for example).
>
> Yes, but the servlets are isolated from each other in the appserver.
> These blocks will be anything but.
What? Each block is a single isolate on a different classloading tree
structure, much like every single web application is to a servlet
container...
> So of course you can undeploy a webapp and deploy it again without
> issues - it isn't wired to any other webapp, and you can cleanly eject
> it from the container. Blocks are wired.
What is not "wired" to another app? Dude, the servlet API clearly
allows you to do intra-webapp request processing. Originally it was
done with the "ServletContext.getServlet()" call, now its done by
"ServletContext.getContext()" and issuing request dispatchers, but that
doesn't mean that from _ANY_ context, I can get WHATEVER instance of
ANY attribute associated with the context...
My take on the Cocoon Kernel simply shields ClassCastException(s)
becasuse it separates class loading (much like servlet do) but also
separates instances by using wires (which are requested basing on
commonly shared and UNRELOADABLE interfaces).
This kernel actually separates blocks in a much better way (IMVHO) that
any servlet container I've seen, coded, or used does...
>>> 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.
>>
>> ???????? I don't understand what you're talking about. Describe
>> exactly
>> the structure of the blocks, because I'm pretty much sure that if you
>> follow a correct blocks design, you'll be able to reload your SSL
>> engine and everything will be absolutely guaranteed to work no
>> problems.
>
> My point is this: Since you will run an old block side by side with
> the new one until all references to the old block are gone, you
> depend on correct block design and correct block implementation for
> those references to be released.
No, I rely on an interface which is published by an interface block and
cannot be reloaded. The interface published by the interface block is
what you use when you "lookup" for a new wiring, and the object you're
going to be given is a proxy instance of that interface dynamically
built using the proxy classes of JDK 1.3, which were designed EXACTLY
with this concept in mind...
> That is, unless the blocks are properly designed and properly
> implemented the old block will not be released, and will be used
> by clients that hold on to this old reference.
Nope, from the point of view of the caller block, you have an instance
of an object that implements that interface... You will NEVER EVER EVER
EVER have access to that component DIRECTLY. It is simply a wire, and
wires can be cut at any time, or can be maintained for as long as you
want even if new lookups will be bound to completely different proxy
instances.
> So, if you have a bad client that incorrectly holds on to an old
> copy of your SSL engine, then that client will pose a security risk.
Nope, the "client" as you define it, is simply another block, and that
"client" will not hold any reference to any object factored in the
"SSLEngine" block...
It will hold a reference to a proxy instance of the interface, and if I
(administrator) decide that that wire poses a security risk, I'll
forcedly cut it, making sure that all new lookups will return new proxy
instances on the newly (non-buggy) SSLEngine block.
> Of course, you say, bad clients are security risks! Which is true,
> but there are some aggravating circumstances here:
>
> The security risk only occurs when reloading.
>
> This means that the risk only manifests itself in a scenario that
> is unlikely to have been thoroughly tested by the developer. How much
> time do you think people will put into the "is my block reload-safe"
> testing?
>
> I think you proved my point with your reply. How complex/easy is
> this "correct blocks design"? Of course it will work if all code
> is perfect. But how easy is it to produce code that is correct?
Leo, I seriously think that you're missing the entire central point on
the core of my take on the Cocoon Kernel, which are PROXY component
instances...
>>> 2b. Multiple blocks stepping on each other's toes
>>>
>>> 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.
>>
>> I don't see how this can be different from having TWO instances of the
>
>> same Object... If you have to serialize access to a resource, simply
>> declare it static in your class (as you would in a normal java
>> application) and synchronize onto it...
>
> Please - no reliance on classloader setup. The classloader tree can
> be very complex in some cases, and having code that relies on just
> one setup is just plain bad.
>
>> When triggering blocks reload because of a change in the block classes
>
>> themselves (when you create a new classloader) yes, you will have the
>> same problem: two instances of the same object, but this doesn't
> differ
>> from when you reload a web-application in your servlet container.
>
> As I said above - webapps are isolated from each other much more than
> blocks. That means that the redeployment scenario is easier.
Again, having written few servlet containers, blocks are MUCH MORE
separated that web applications from a JVM perspective... From a
usability perspective (y'all block coders) they're far better
interoperable.
> [...]
> My whole argument is that your design will end up being very very
> complicated and very very hard to develop for, since it provides so few
> guarantees to block developers. Things like "what code is running", for
> example.
Leo, I seriously thinking you're really missing the point on how
component lookup is done, and how it is so completely different from
Avalon to require a whole interfaces-set changes...
I don't like to re-code the world myself, but my take on the kernel has
a completely different approach towards component lookups, so radically
different to what we envisioned 6 years ago (because the JVMs allow you
to do much more nowadays) that it requires an entire new mindset if you
want to code the framework itself (took me 6 years to understand it!
:-)
On the other hand, if you're a block developer (and here I want to
entirely reassure each one of you who is thinking about how to code his
block possibly using this kernel), all I ask you is to do the
following:
to acquire an instance:
object = (MyInterface)Wires.lookup(MyInterface.class, "wiringname")
before you use it
((Wire)object).ensureWired();
and when you want to release the object
((Wire)object).release() / dispose();
Which basically means ONE MORE line of your code, and guaranteed
availability of fresh components at all times.
Pier (back coding the "ensureWired()" thing)
RE: [Kernel2.2] Comments
Posted by Leo Sutic <le...@inspireinfrastructure.com>.
> From: Pier Fumagalli [mailto:pier@betaversion.org]
>
> On 31 Mar 2004, at 14:33, Leo Sutic wrote:
>
> > 1. Singletons
> The "Composer" is always singleton in each block instance. There are
> never two Composers in a single block instance.
OK.
> You might argue that you want a "framework" singleton (or a block
> that cannot be
> instantiated more than once)...
No, I don't.
> > 2. Reloading
> > 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.
>
> Not maybe, yes... The ClassLoading paradigm associates every single
> class with its own classloader implementation. Old classes
> will retain old classloaders and will work as if nothing has
happened...
I don't understand what you base that "yes" on. Will the classloading
work? Yes, it will. But will *the* *rest* of the system work? You have
no guarantee at all.
> It's how it works with servlet containers (for example).
Yes, but the servlets are isolated from each other in the appserver.
These blocks will be anything but.
So of course you can undeploy a webapp and deploy it again without
issues - it isn't wired to any other webapp, and you can cleanly eject
it from the container. Blocks are wired.
> > 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.
>
> ???????? I don't understand what you're talking about. Describe
exactly
> the structure of the blocks, because I'm pretty much sure that if you
> follow a correct blocks design, you'll be able to reload your SSL
> engine and everything will be absolutely guaranteed to work no
> problems.
My point is this: Since you will run an old block side by side with
the new one until all references to the old block are gone, you
depend on correct block design and correct block implementation for
those references to be released.
That is, unless the blocks are properly designed and properly
implemented the old block will not be released, and will be used
by clients that hold on to this old reference.
So, if you have a bad client that incorrectly holds on to an old
copy of your SSL engine, then that client will pose a security risk.
Of course, you say, bad clients are security risks! Which is true,
but there are some aggravating circumstances here:
The security risk only occurs when reloading.
This means that the risk only manifests itself in a scenario that
is unlikely to have been thoroughly tested by the developer. How much
time do you think people will put into the "is my block reload-safe"
testing?
I think you proved my point with your reply. How complex/easy is
this "correct blocks design"? Of course it will work if all code
is perfect. But how easy is it to produce code that is correct?
> > 2b. Multiple blocks stepping on each other's toes
> >
> > 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.
>
> I don't see how this can be different from having TWO instances of the
> same Object... If you have to serialize access to a resource, simply
> declare it static in your class (as you would in a normal java
> application) and synchronize onto it...
Please - no reliance on classloader setup. The classloader tree can
be very complex in some cases, and having code that relies on just
one setup is just plain bad.
> When triggering blocks reload because of a change in the block classes
> themselves (when you create a new classloader) yes, you will have the
> same problem: two instances of the same object, but this doesn't
differ
> from when you reload a web-application in your servlet container.
As I said above - webapps are isolated from each other much more than
blocks. That means that the redeployment scenario is easier.
> > 3. Over-reliance on Administrator Omniscience
>
> And administrator reloads a block when it wants to deploy a
> new version of it (HTMLGenerator version 1.0.1 is updated by
> HTMLGenerator version 1.0.2), and don't tell me that you want me
> to shut down the ENTIRE VM to perform that change...
If the other option is to not know what code I'm running on my
server, then yes.
So you've put the 1.0.2 version there. You've hit the "reload block"
button.
Does this mean that you're running version 1.0.2? No.
You are running 1.0.2 ***if*** all the blocks are correctly designed
and implemented, so that none is holding on to a reference to 1.0.1.
How can you find out? You can't.
Does it matter in this case? Probably not.
Can this be a risk? Yes.
> I'm confident that if designed correctly, blocks won't have a problem
> in rewiring themselves on newly deployed replacing instances,
My whole argument is that your design will end up being very very
complicated and very very hard to develop for, since it provides so few
guarantees to block developers. Things like "what code is running", for
example.
/LS
Re: [Kernel2.2] Comments
Posted by Pier Fumagalli <pi...@betaversion.org>.
On 31 Mar 2004, at 14:33, Leo Sutic wrote:
> 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.
The "Composer" is always singleton in each block instance. There are
never two Composers in a single block instance. You might argue that
you want a "framework" singleton (or a block that cannot be
instantiated more than once)... I would strongly oppose to put that in
the block descriptor, as (with any Java code) for a "VM-wide" (or
classloader-wide) singleton instance anyone can use the usual "static"
in the class. (note: Instances share the same classloaders as Objects
share the same Class)
For a singleton instance object (a singleton which gets re-created in
every new block Instance):
public SingletonComposer implements Composer {
private Object singleton = // the instance;
public void acquire() {
return(singleton);
}
public void release() {
}
public void dispose() {
}
}
For a framework singleton object (a singleton which is shared amongst
several Instances of the same block):
public SingletonComposer implements Composer {
private static Object singleton = // the instance;
public void acquire() {
return(SingletonComposer.singleton);
}
public void release() {
}
public void dispose() {
}
}
The JVM already provides those, let's not over-design.
> 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.
Can you give some examples of what could go wrong? I can't imagine
any...
> 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.
Not maybe, yes... The ClassLoading paradigm associates every single
class with its own classloader implementation. Old classes will retain
old classloaders and will work as if nothing has happened...
The JVM allows easily to create classes trees where the same class
exists in two different places at the same time, but is accessible by
all of them. This is why interfaces (public classes exposed by
interfaces blocks) CAN NOT be reloaded, because they are shared amongst
all class users.
It's how it works with servlet containers (for example).
> 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.
???????? I don't understand what you're talking about. Describe exactly
the structure of the blocks, because I'm pretty much sure that if you
follow a correct blocks design, you'll be able to reload your SSL
engine and everything will be absolutely guaranteed to work no
problems.
> 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.
I don't see how this can be different from having TWO instances of the
same Object... If you have to serialize access to a resource, simply
declare it static in your class (as you would in a normal java
application) and synchronize onto it...
When triggering blocks reload because of a change in the block classes
themselves (when you create a new classloader) yes, you will have the
same problem: two instances of the same object, but this doesn't differ
from when you reload a web-application in your servlet container.
> 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.
And administrator reloads a block when it wants to deploy a new version
of it (HTMLGenerator version 1.0.1 is updated by HTMLGenerator version
1.0.2), and don't tell me that you want me to shut down the ENTIRE VM
to perform that change...
I'm confident that if designed correctly, blocks won't have a problem
in rewiring themselves on newly deployed replacing instances, and I
(administrator) want control over it... Otherwise, what's the whole
point in having blocks in the first place? Just write a better
sourceresolver and load everything into your servlet container's
web-application classloader...
Pier
RE: [Kernel2.2] Comments
Posted by Leo Sutic <le...@inspireinfrastructure.com>.
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
RE: [Kernel2.2] Comments
Posted by Leo Sutic <le...@inspireinfrastructure.com>.
> From: Pier Fumagalli [mailto:pier@betaversion.org]
>
> > Some quick observations:
> >
> > 1. @author <a href="http://www.vnunet.com/">VNU Business
> > Publications</a>
> > Is this OK with Apache and VNU?
>
> Defintely OK with VNU (if someone visits our site because of a click
on
> the JavaDOC, and then come back, we got one more customer... If you
> guys don't want to see it in there, you can remove it no
> problems... It is in my default Java class template.
I have absolutely no problems with this. Just wondered if it had been
left in accidentally.
> > 2. Wire.java
> > /**
> > * <p>Check wether the wire between this {@link
> Wirings} instance
> > and the
> > * original component is still active.</p>
> > *
> > * <p>When this method returns <b>true</b> all methods
> called on
> > this
> > * instance will be forwarded to the original component
> instance
> > associated
> > * with this wire.</p>
> >
> > You cannot guarantee that. The instance may be
> redeployed between
> > the call
> > to wired() and the next call.
> >
> > No point in having a method whose return value means nothing.
>
> This method will return true until the block instance will not be
> destroyed or replaced by the Deployer, and when this method returns
> false, whoever got this wire should release it and acquire a new one
> (which will be got from the new block instance).
>
> Rember? The idea is never to completely remove blocks until
> forced to, so the Wire instance will still work even if wired()
returns
> false. The wire will only be deactivated by either a call to release()
or
> dispose() or by a forceful destruction by the deployer.
I'd still like this to be transparent...
Having a coding convention that requires you to do wired() checks
before every call is bad in my opinion.
What you can do is have an:
Wire.ensureWired()
which will do:
if (!wired()) {
// renew proxy target
}
Then the client can call the method before it starts processing. I.e.
the client notifies the framework that "if you want to drop this
instance,
now is a good time".
> Yes, each component instance has only one contextualized wire, because
> that instance is its own wire as it is returned to the caller. The
> JavaDOC goes in quite a lot of details on why this is done, and
provide
> some examples.
OK, will check.
> > 5. Configuration.java
> >
> > public class Configuration extends ArrayList
> >
> > I'd use composition instead...
>
> ??? extends AbstractList ???
No, I meant:
public class Configuration {
private final List nodes = new ArrayList();
...
}
> > 6. Parameters.java
> >
> > Get rid of this one. Why can't components accept a hierarchy of
> > configuration nodes as configuration data?
>
> No... Parameters are typed and the framework checks the type of each
> parameter. One of the parameters CAN be a configuration on the other
> hand if in its descriptor the block requires:
Missed that. Thanks!
> > 9. Identifier.java
> >
> > *
> > <p><code>protocol://location/path/major.minor(.revision)?</code></p>
> >
> > Does this mean that all Blocks are automatically mapped into a
URL
> > space?
>
> All blocks have a unique identifier. And this list agreed that each
> block identifier will assume the requirements specified in the
> Identifier interface.
Yes, I'm with you so far. But what does the URL really signify? What if
I put the URL into my web browser? Will I download the block? Or?
/LS
Re: [Kernel2.2] Comments
Posted by Pier Fumagalli <pi...@betaversion.org>.
On 31 Mar 2004, at 12:08, Leo Sutic wrote:
> Nice work!
Thanks
> Some quick observations:
>
> 1. @author <a href="http://www.vnunet.com/">VNU Business
> Publications</a>
> Is this OK with Apache and VNU?
Defintely OK with VNU (if someone visits our site because of a click on
the JavaDOC, and then come back, we got one more customer... If you
guys don't want to see it in there, you can remove it no problems... It
is in my default Java class template.
> 2. Wire.java
> /**
> * <p>Check wether the wire between this {@link Wirings} instance
> and the
> * original component is still active.</p>
> *
> * <p>When this method returns <b>true</b> all methods called on
> this
> * instance will be forwarded to the original component instance
> associated
> * with this wire.</p>
>
> You cannot guarantee that. The instance may be redeployed between
> the call
> to wired() and the next call.
>
> No point in having a method whose return value means nothing.
This method will return true until the block instance will not be
destroyed or replaced by the Deployer, and when this method returns
false, whoever got this wire should release it and acquire a new one
(which will be got from the new block instance).
Rember? The idea is never to completely remove blocks until forced to,
so the Wire instance will still work even if wired() returns false. The
wire will only be deactivated by either a call to release() or
dispose() or by a forceful destruction by the deployer.
> 3. Component.java:
> /**
> * <p>Contextualize this {@link Component} component instance with
> the
> * {@link Wire} through which its caller is accessing it.</p>
> *
> * @param wire the {@link Wire} instance associated with this
> instance.
> */
> public void contextualize(Wire wire);
>
> Does this mean that each component instance only has one wire? I.e.
> only one client? You may end up with a lot of components if you
> have
>
> component A depends on B, C, D, which depends on E, F, G, H...
>
> Wouldn't it be better to keep this as a ThreadLocal variable that
> can
> be accessed by the component? Then you can have multiple clients,
> but only one client per calling thread (which seems like a
> reasonable
> tradeoff).
Yes, each component instance has only one contextualized wire, because
that instance is its own wire as it is returned to the caller. The
JavaDOC goes in quite a lot of details on why this is done, and provide
some examples.
> 4. Wirings.java
>
> Talks about ((Wiring)myObject).release();
> Should be ((Wire)myObject).release();
>
> #include <my/usual/bitching/about/the/wired()/method>
Fixed.
> 5. Configuration.java
>
> public class Configuration extends ArrayList
>
> I'd use composition instead...
??? extends AbstractList ???
> 6. Parameters.java
>
> Get rid of this one. Why can't components accept a hierarchy of
> configuration nodes as configuration data?
No... Parameters are typed and the framework checks the type of each
parameter. One of the parameters CAN be a configuration on the other
hand if in its descriptor the block requires:
<param name="xyz" type="configuration"/>
Other typse might be:
<param name="abc" type="integer"/>
<param name="def" type="boolean"/>
<param name="ghi" type="string"/>
...
The framework will check that parameters required by the block are
available (specified before deployment) and of the correct type...
So Configuration is MUCH more restricted than Parameters.
> 7. Configurable.java
>
> Should accept Configuration instead of Parameters. Being able to
> send in a tree-structure of config info instead of a flat list is
> useful.
From the "Configurable" javadoc:
Note that a Parameters parameter can contain an entire Configuration
tree, nullifying the requirement of a configuration method using a
Configuration
> 8. Block.java
>
> Love it.
It's the core.
> 9. Identifier.java
>
> *
> <p><code>protocol://location/path/major.minor(.revision)?</code></p>
>
> Does this mean that all Blocks are automatically mapped into a URL
> space?
All blocks have a unique identifier. And this list agreed that each
block identifier will assume the requirements specified in the
Identifier interface.
Pier
Re: [Kernel2.2] Comments
Posted by Steven Noels <st...@outerthought.org>.
On 31 Mar 2004, at 13:08, Leo Sutic wrote:
> 1. @author <a href="http://www.vnunet.com/">VNU Business
> Publications</a>
> Is this OK with Apache and VNU?
There's a board advisory that @author tags shouldn't be used anymore,
but it's only an advisory, not a policy. The (c) *must* reside with
ASF, but if VNU wants, they can be properly credited in the CREDITS
file. IMHO, I wouldn't taint the entire donation-of-work-in-progress
with credit strings in every class - just put a single statement in the
CREDITS file.
</Steven>
--
Steven Noels http://outerthought.org/
Outerthought - Open Source Java & XML An Orixo Member
Read my weblog at http://blogs.cocoondev.org/stevenn/
stevenn at outerthought.org stevenn at apache.org