cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Pier Fumagalli <p...@betaversion.org>
Subject Re: [Kernel2.2] Comments
Date Wed, 31 Mar 2004 18:42:21 GMT
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)


Mime
View raw message