Mark Brouwer wrote:
Already a long time on my list of things to tackle is customization of
the object identification layer.

While sitting in the bath tub I had a Eureka moment as I also believe
customization of the object identification layer brings me something
else that I'm fighting with for a few years.

First the problem, although the use case refers to Seven the problem
itself is not specific to Seven, it is just to provide some context for
the problem I'm trying to solve.

Assume you develop a service for which the downloadable code evolves
over time. The hosting environment (in this case Seven) evolves as well.
The service is deployed as a persistent service, that is it will
maintain the same ServiceID and object identifier for the endpoint even
while sometimes it crashes (unplanned downtime) or is upgraded, either
due to fixes new features in the service or due to upgrading of the
hosting platform (planned downtime).

Assume that as part of the planned maintenance downloadable code has
changed and as a result the codebase annotation changes in time as well
(Seven makes with each upgrade a full analysis of download JAR files to
see whether the codebase needs a change). In case evolution is displayed
as t0-3 and the codebase annotation changes as A-D. It is good to
understand that the codebase served for a service will be available to
clients.

  annotation:  A       B       C       D
               |-------|-------|-------|
  time:        t0      t1      t2      t3

So the first time at t0 we deploy our persistent service and the
codebase annotation is A. Meaning that when the client receives the
smart proxy to its service it will create a class loader for which the
implementation classes are obtained from A.

Then we find out that we want to enhance or bug-fix our service and
bring it down for planned maintenance (this also relates to my previous
posting). After the upgrade Seven finds out a new codebase annotation is
needed, so clients that find the service after t1 will see a codebase
annotation B and they create a class loader for the proxy implementation
classes from B. No problem here this client is happy.

The problem occur with the clients that saw codebase A, because even
when they can communicate with the upgraded server, the marshalled
stream will contain codebase annotations B. The net effect is that these
classes will be created in a new class loader and are type incompatible
with the classes the client already has defined in the class loader
related to A.

Assume that the server could in the above case make sure that the
annotations used for classes defined in the service class loader ar enot
annotated with B but with A. The client could (likely) to continue
working with the service, with the 'disadvantage' that it won't see any
changes in the newer classes (B).

So what is required from the perspective of the framework is a way to
find out where on the evolution time scale a smart proxy was handed to a
client. That identifier could be used by the class annotation mechanism
to provide the right codebase annotation.

In the past I've been thinking of a new version of the protocol that
describes how marshalling and unmarshalling of all the request/response
data takes place, to allow for adding an additional identifier over
which you can have control over and that is persisted as part of the
BasicInvocationHandler.

But this is where the bath tub came into play. I realized that I can
achive the same thing through the object identification layer. Assume
that with the time evolution of the service I use a different Uuid for
each time the service exports (t0-t3) and that I also keep track of all
the Uuids used for exporting the service it would mean that depending on
when on the time scale obtained the smart proxies have different object
identifiers, you end up with these relations:

  annotation:  A       B       C       D
               |       |       |       |
  object id:   ef...   3c...   1a...   ba...
               |       |       |       |
               |-------|-------|-------|
  time:        t0      t1      t2      t3


In case at the object identification layer a request comes for a Uuid I
can check whether it is in the export table, if not whether it
represents history of the exported service. If the latter is the case it
should redirect to the current Uuid under which it is exported and it
can populate the Collection object representing the context as passed in
to InvocationDispatcher.dispatch(Remote, InboundRequest, Collection).
The invocation dispatcher can then use the context information (if any)
to set some thread local variable that can be utilized by the (in my
case) context aware class annotator and arrange for providing the
correct codebase annotation.

I realize this doesn't solve all problems related to codebase versioning
(e.g. not the cases where intermediate services pass around objects),
but it does solve the most common case for which I ran into troubles
with upgrading of services.

In case there are really incompatible upgrades and these are defined for
the service as such, this mechanism will also allow throwing an
exception that indicates the client should give up talking to the server
(throwing NoSuchObjectException?, or maybe one that indicates it is
unusable due to an incompatible evolution).
--
Mark

Reply via email to