On 5 Mar 2004, at 21:10, Stefano Mazzocchi wrote:

Tim Larson wrote:

On Fri, Mar 05, 2004 at 01:24:57PM -0500, Stefano Mazzocchi wrote:

Package: org.apache.cocoon.cforms

here I would go "forms" instead. package naming is where the estate really is, where class collissions might happen.
I understand how this seems like a good place for the battleground,
but to introduce a new winner it looks like this would force us to
break code compiled against the previous major version because we
would be stealing the class and interface names for the new version.
Does the new block system somehow solve this problem like via
classloaders or something else?

eh, very good question, actually. I spent a few hours discussing with Pier about this yesterday over IM. Pier, as usual, sees the very core problem and I always miss ;-)

Heh! :-) No, Ste, it's that I only have to shovel more crap than you have to on production environments...


What it means is that I'd rather have a simpler (and more understandable) environment to code against, rather than a complete but complex one, because when shit happens, I'm going to be the one who has to bring our LIVE server up-and-running QUICK! :-P

The way the JVM classloading mechanism is designed (well, the code verifier actually) is that you cannot have two classes with the same name and package in the same classloading hierarchy.

So, for example, suppose you have the following hierarchy:

    B
   /
  A
   \
    C

where block A depends on block B and C. Now, if B and C expose the same class, there is no problem if that is accessed from B or from C internally, but as soon as A starts to access it, which one does it get?

Perfectly correct... More in details, A will have an instance of the Class object from either B or C linked to the class name. For example if both B and C expose the class "org.betaversion.MyClass", the C and B classloader will both contain an instance of that class associated with that name.


When A receives an instance of "org.betaversion.MyClass" the ByteCode Verifier will check it against A's classloader instance of the "org.betaversion.MyClass" class object, which he got from either B or C.

If the instance of the class object A has is different from the one that instantiated the object, well, the BCV will throw a ClassCastException

(It might be tricky to understand what's an instance of a Class and what's an instance of an Object, if someone has some doubts, ask me, please... I had to read the JVM specification 3 or 4 times before grasping it)

So, in short, it is feasible (IMHO, even if I haven't tried yet) to come up with a classloading hierarchy that allows isolation, but only when the semantics associated to the class usage are *really* isolated.

It is absolutely possible, yes... IN THEORY! :-D


It means that if (in the above example), we could analyze all classes accessible by A supplied by B and C (which means all public classes), analyze their signatures, come up with a list of all the class instances which are "visible" from outside, we can safely see whether we can (or not) satisfy our versions tree.

In practice (though) this is quite impossible as 99.9% of the classes created are always "public" and therefore accessible from the children class loaders...

Note that this seems easy to enforce, but it's really not, especially if you get into block versioning!!!

      X.1
     /
    B
   /
  A   D
   \ / \
    C   E
     \   \
      F   X.2

Now, if A asks for a particular task that B executes, requiring version 1 of block X, then asks for another task, executed by C, left to D, which handles to E which requires version 2 of X, then you get a ClassCastException. No way out!

And debugging this is going to be the biggest pain in the universe!!

Not even debugging... Analyzing the dependancies (although possible) will be a nightmare...


So, my suggestion is to create a dependency checker which will tell all the potential class collision conflicts, at deploy time (by crawling the class space, perform MD5 hashing of classes and identify collisions)

You don't even have to have an MD5 :-) Because even if you have the SAME EXACT file, if that file is loaded by two different classloaders, you won't be able to do a cast operation...


It's a matter of instances of class objects... The instance of the class is different, no way you can cast...

So, in short: having to different versions of the same interface in memory is possible only if there is always a way for the system to differentiate between them. that is: no way to use them both.

Trivial for a few blocks, but very tricky when the number of blocks dependencies explodes.

Ok, I see that it MIGHT be a problem... But it will also be an incentive. If I (Pier) write a block, and that relies on a set of other blocks, and I CANNOT avoid the problem of "old versions", I will be forced to "maintain" my block if I want to use new features...


It basically turns a technical disadvantage into a social advantage. We cannot guarantee cross-version compatibility for a particular set of block, the community, if the block is "worthy" will make sure that it's always up-to-date to the latest standards :-)

If you don't maintain your block, you're out :-) If you're not involved with the community, your code will fade away :-) I wouldn't see this as a problem! :-)

This is the best answer I can give at the moment.

Pier, anything to add here?

Yep... That I don't see versioning problems as a problem at all... If we don't solve the versioning problem, we'll never have the other problem of "uh, I don't know how that block works so I won't fix it or update it" :-)


Pier



Reply via email to