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