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)



Reply via email to