You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@river.apache.org by Mark Brouwer <ma...@cheiron.org> on 2007/06/14 14:55:14 UTC

Equality for service proxies, leases, server transactions, etc.

Already asked recently as part of a footnote, but there it got no
response, so I'll give it another try.

Equality for services, leases, event registrations, etc. is still a
painful exercise (especially in long running systems in which codebases
might change due to rolling fixes into services) and a case [1] for
which I must come to the conclusion I can't seem to create a proper work
around that makes a requirement work with a generic lookup service.

 From the Davis project I know that ReferentUuid
http://java.sun.com/products/jini/2.1/doc/api/net/jini/id/ReferentUuid.html
was designed to help in this area, given the fact since then none of the
classes that could take advantage of it have been made aware of it and
none of the Jini Specifications got any language that indicates
ReferentUuid plays a role here.

I'm curious to find out whether people think this is something that
should be tackled?


[1] probably my explanation is not detailed enough to follow all that is
going on, but the following is the case I try to solve and the problem
analysis why it doesn't work.

Assume a Jini service that is defined in class loader A creates a
child class loader B for deploying a algorithm plugin or a web application.

The Jini service is responsible for finding a lookup service on the
network. During the unmarshalling of the lookup service a new class
loader C is created that has as its parent class loader A.

Assume this class loader is passed on the plugin that is defined in
class loader B, all operations in the plugin take place with a context
class loader that equals B.

 From within the plugin it registers for receiving events through the
Jini Distributed Event Model for which it will get an EventRegistration
that contains a source field. The ServiceTemplate contains types that
are only available in class loader B. The registration is done
indirectly through a SDM.

The lookup service finds a match and notifies the exported remote event
listener. The event is unmarshalled with a context class loader of B and
a default class loader of B, this will result in the creation of a class
loader D that has B as its parent. The service item part of the event is
usable in the context of the plugin but in this case the SDM rejects the
event because it turns out the source of the registration and the field
doesn't match. Analysis learns that the source of the registration is
defined in class loader C and the source as part of the event in class
loader D. The cause of this is the default class loader used during
unmarshalling which is different from the perspective of the
BasicInvocationDispatcher (receiving events) and the
BasicInvocationHandler (event registration) as the basic invocation
handler uses the class loader of the proxy (C) as the default loader.

      Class loader hierarchy

      A-------
      |      |
      |      |
      |      C  (proxy lookup service, event registration, source)
      |
      |
      B-------
             |
             |
             |
             D  (service events, source)


I have 2 workarounds to my avail that I have working:

1) the first one is to utilize the inverted event model on
ServiceRegistrarX which results in the unmarshalling of events that
carry a source field that is defined in the same class loader as the
source field of the event registration, i.e. the source field will be
defined in class loader C as that is the default loader during
unmarshalling.

2) use the Jini Distributed Event Model and have as the source an object
that is part of the Platform (class visible from both class loaders)
such as a Uuid. Well that is my preferred choice anyway
(http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6316548) but due to
compatibility concerns it ain't the default for the lookup service I
provide.

The problem with the above is that both are not supported by the
majority of lookup services in the field deployed and as such is a lame
solution. In case the source object would have implemented ReferentUuid
the various utility classes could have utilized that and it would have
worked, the same problem I foresee with ServerTransaction, etc.

To be really honest it is kind of problematic if it turns out all Jini
related operations should originate from one big happy class loader as
that rules out a lot of possibilities in the design of Jini services.
-- 
Mark







Re: Equality for service proxies, leases, server transactions, etc.

Posted by Bob Scheifler <Bo...@Sun.COM>.
Mark Brouwer wrote:
> If person A designs a service based on a platform assumption I think
> person B shouldn't use it with a platform definition that breaks any
> assumptions otherwise he/she is asking for troubles anyway.

I believe the original thinking was that person A should design the
service to be platform-independent as much as possible, so that person B
is able to choose their own platform.

- Bob

Re: Equality for service proxies, leases, server transactions, etc.

Posted by Mark Brouwer <ma...@cheiron.org>.
Bob Scheifler wrote:

>> Maybe I didn't make that clear but I was referring to those objects for
>> which it is assumed the primary interface is part of the platform, such
>> as can be assumed for Lease and TransactionParticipant, etc. similar as
>> that ReferentUuid must be in a Platform to make it work too.
> 
> I think that presents a problem when person A designs the service
> and person B independently decides what is in his/her platform.

If person A designs a service based on a platform assumption I think
person B shouldn't use it with a platform definition that breaks any
assumptions otherwise he/she is asking for troubles anyway.

There is a solution to this ... start defining a base Jini Platform, but
unfortunately after shouting for that for a long time my sound waves
never seem to reflect. Sometimes I even think it entered a larger void
than Voyager 1 which in itself is quite an achievement I guess.
-- 
Mark


Re: Equality for service proxies, leases, server transactions, etc.

Posted by Bob Scheifler <Bo...@Sun.COM>.
Mark Brouwer wrote:
> One could say that for both EventRegistration and ServiceRegistration
> (implemented by com.sun.jini.reggie.Registration) the resource it
> represents is covered by the associated Lease and as such there is no
> need for ReferentUuid to be implemented by Registration at all, but
> nevertheless it has been decided so. It is even so that when looking
> at the code I see that equals of Registration delegates to the lease
> which seems to confirm what I believe is the case.
> 
> As such I would have expected EventRegistration to have an
> equals/hashCode as well and to find it normal to have it (a subclass of
> course) to implement ReferentUuid.

The difference is simply that EventRegistration was designed to just
be a simple local struct, not a proxy; perhaps the best indicator is that
it's a class, not an interface.  Whereas ServiceRegistration is an
interface, with remote methods.

> Currently in Seven I have a subclass of EventRegistration that has an
> additional reregister method (performs a remote method call) and it
> implements RemoteMethodControl.

OK, there was no expectation of that being done.

> Maybe I didn't make that clear but I was referring to those objects for
> which it is assumed the primary interface is part of the platform, such
> as can be assumed for Lease and TransactionParticipant, etc. similar as
> that ReferentUuid must be in a Platform to make it work too.

I think that presents a problem when person A designs the service
and person B independently decides what is in his/her platform.
Having a semantic asymmetry between platform and non-platform
services also seems a bit odd?  But probably more to the point:

> This will at least return false in case you compare the main proxy and
> administration proxy (assuming it doesn't implement Administrable) even
> while their Uuid as returned by getReferentUuid() are equal.

I believe it was intentional when using ReferentUuid for equals that
it's only testing for "same remote resource", not "functionally equivalent
proxy" or "role equivalent proxy".  Main proxy and admin proxy are
both proxies for the same top-level service, so they have the same
ReferentUuid; ServiceRegistration and Lease are both proxies for the
same service registration, so they have the same ReferentUuid.

- Bob


Re: Equality for service proxies, leases, server transactions, etc.

Posted by Mark Brouwer <ma...@cheiron.org>.
Hi Bob,

I think I preferred my previous teacher as he at least doesn't give you
the feeling you ask stupid questions all the time :-P

Bob Scheifler wrote:
> Mark Brouwer wrote:
>> 1) Going through the source of the contributed services to see which
>> other proxies provided by Seven should take advantage of ReferentUuid I
>> noticed that for Reggie the decision was made to have
>> com.sun.jini.reggie.Registration implement ReferentUuid, while for the
>> other type of registrations (events) it was decided that they don't
>> implement ReferentUuid, what is the rationale behind that decision?
> 
> Not sure what you have in mind, EventRegistration isn't a proxy interface.

I have nothing particular in mind, I try to understand when and why
to implement ReferentUuid and I have no neural network in place yet that
when that question goes in, the answer flows out automatically with full
confidence. So far I get the impression it is important because some
specs require reference equality that is currently
specified to be answered through equals of an object/proxy/source and
ReferentUuid is a robust tool for that. Maybe when ReferentUuid was
invented in 1999 those specs would have been different and clients would
have drawn reference equality conclusions instead of letting an equals
decide, but I believe that is the answer of which I can have an opinion
but is really for you and others to say ;-)

One could say that for both EventRegistration and ServiceRegistration
(implemented by com.sun.jini.reggie.Registration) the resource it
represents is covered by the associated Lease and as such there is no
need for ReferentUuid to be implemented by Registration at all, but
nevertheless it has been decided so. It is even so that when looking
at the code I see that equals of Registration delegates to the lease
which seems to confirm what I believe is the case.

As such I would have expected EventRegistration to have an
equals/hashCode as well and to find it normal to have it (a subclass of
course) to implement ReferentUuid.

Currently in Seven I have a subclass of EventRegistration that has an
additional reregister method (performs a remote method call) and it
implements RemoteMethodControl. So maybe now it could be seen as acting
as what you would call a proxy and should I suddenly start using
ReferentUuid here, but if EventRegistration doesn't need it, why should
the subclass suddenly need it? I find this hard to reason about given
the absence of a spec that requires reference equality for these event
registrations.

>> 2) Why don't the equals implementation at least check whether the object
>> passed in for the test of equality implements the same interface.
> 
> Because that would introduce the defined-in-different-class-loaders
> problem that you're trying to avoid.

Maybe I didn't make that clear but I was referring to those objects for
which it is assumed the primary interface is part of the platform, such
as can be assumed for Lease and TransactionParticipant, etc. similar as
that ReferentUuid must be in a Platform to make it work too. So I
decided to implement the equals for a LeaseProxy as below:

public boolean equals(Object obj) {

     if (obj == this) {
         return true;
     }
     else if ((obj instanceof Lease) && (obj instanceof ReferentUuid)) {
         return uuid.equals(((ReferentUuid) obj).getReferentUuid());
     }

     return false;
}

Assume you have a main proxy and its associated administration proxy
both implementing ReferentUuid, in that case the equals of the main
proxy will be along the lines of:

public boolean equals(Object obj) {

     if (obj == this) {
         return true;
     }
     else if ((obj instanceof Administrable)
              && (obj instanceof ReferentUuid)) {
         return uuid.equals(((ReferentUuid) obj).getReferentUuid());
     }

     return false;
}

This will at least return false in case you compare the main proxy and
administration proxy (assuming it doesn't implement Administrable) even
while their Uuid as returned by getReferentUuid() are equal.

Maybe it is completely logical that the answer should be true here, but
somehow I can't get a grip on why it should.
-- 
Mark

Re: Equality for service proxies, leases, server transactions, etc.

Posted by Bob Scheifler <Bo...@Sun.COM>.
Mark Brouwer wrote:
> 1) Going through the source of the contributed services to see which
> other proxies provided by Seven should take advantage of ReferentUuid I
> noticed that for Reggie the decision was made to have
> com.sun.jini.reggie.Registration implement ReferentUuid, while for the
> other type of registrations (events) it was decided that they don't
> implement ReferentUuid, what is the rationale behind that decision?

Not sure what you have in mind, EventRegistration isn't a proxy interface.

> 2) Why don't the equals implementation at least check whether the object
> passed in for the test of equality implements the same interface.

Because that would introduce the defined-in-different-class-loaders
problem that you're trying to avoid.

- Bob

Re: Equality for service proxies, leases, server transactions, etc.

Posted by Mark Brouwer <ma...@cheiron.org>.
Hi Vinod,

Took me some to respond because I had to do some homework ... and some
experiments.

There are 2 questions at the bottom for those who want to skip a lot of
explanation and history.

Vinod Johnson - Sun Microsystems wrote:

> I must be missing something here, but do you see any exception from the 
> SDM, or is the event silently dropped? In the case of reggie, its proxy 

It is silently dropped when the source in the registration doesn't
match the source in the event. Based on the inline comments I believe
the author considered it a case where the event arrived before the
eventReg is in the map.

> implements equals (which the SDM uses to check for equality) to do a 
> comparison on the net.jini.id.Uuid value returned from getReferentUuid. 
> Is it that your registrar proxy does not do the same? Given the 

As if you kissed me awake :-) The very short answer to this is that I
removed ReferentUuid from the specialized proxy as ReferentUuid in
Reggie was IIRC only used by its own equals and then (4 years ago) I
didn't understood the implications of its usage to the extend I
apparently should have and there were some questions whether in my case
it was the right thing to do (i.e. utilizing ReferentUuid).

The equals for my ServiceRegistrar is specified by the JSC Specification
which states it implements reference equality by default but doesn't
make usage of ReferentUuid, it is implemented as an implementation
detail as part of the invocation handler of the dynamic proxy that is
placed for the specialized proxy and that means for being equal the
other proxy should be defined in the same class loader, which becomes
painfully clear is brittle in some occasions.

In 2003 John McClain gave me a course "proxy equals" for which he should
have flunked me then ;-), see
http://archives.java.sun.com/cgi-bin/wa?A2=ind0307&L=jini-users&F=&S=&P=14022
. The thread ended with me saying "Whether the container generated
dynamic proxy implements ReferentUuid depends on whether the JSC service
proxy implements ReferentUuid. I thought of having the container
generated proxy always implementing ReferentUuid during the conversion
of some of the contributed services, but I leave that for when I have
time to think over the consequences."

4 years passed by and I didn't gave it any thoughts because I forgot
about it and never ran into any problems, well I'll had to do that
thinking now.

> specification of ReferentUuid, it's probably better to actually compare 
> the Uuids rather than test for equals - I can't answer the 
> history/rationale behind the current state of the implementation.

John McClain once said:

"ReferentUuid is currently intend more as a tool that people can use to
implement robust and stable notions of reference equality, than as an
interface that clients will use directly. I agree it can do more, and
the spec has been written so it can (and some day may), in particular
clients can infer reference equality if two proxies that implement
ReferentUuid have the same Uuid - but for Davis we were not comfortable
with forcing all proxies to implement ReferentUuid".

I think I've read that as that there is still a grand master plan for
ReferentUuid and to make it more explicit as part of certain specs. For
example requiring a Lease to implement ReferentUuid would appeal to me
more than relying on its equals.

Also I think I feel very uncomfortable with e.g. an ServiceRegistrar and
its administration proxy being equal because they rely on ReferentUuid
for that purpose. Both are fundamentally different although their equals
imply they are the same. I believe defining reference equality through
equals is just not the best way, but it is a fact for some of the
specifications.

If for a proxy it boils down to implementing ReferentUuid and the only
usage is for its equals implementation to utilize it I wonder why we
don't make clients aware of it and have them perform the reference
equality check. Modify the future specs to demand Jini service proxies
to implement ReferentUuid, if not overridden by another spec.

But for now I just modified the container generated dynamic proxy code
to make usage of ReferentUuid and see what the implications would be for
the container implementation and for the JSC Specification:

1) if a specialized proxy handed to the container doesn't implement
ReferentUuid the container will add ReferentUuid to the dynamic proxy
and provide its own reference equality when invoked;

2) if the specialized proxy implements ReferentUuid the invocation
handler of the dynamic proxy will delegate to the specialized proxy to
provide the answer for getReferentUuid()

3) if the specialized proxy doesn't override Object.equals ReferentUuid
will be utilized for equals, otherwise the equals on the specialized
proxy will be utilized

4) a similar mechanism for the administration proxy returned by a
specialized proxy that is also enhanced by the container to get all
kinds of free administration functionality. The current equals
implementation will verify by a way that is not subject to class loader
skew whether one is main proxy and the other the administration proxy as
I don't think these should be considered true (Reggie e.g. considers
them equal).

Rerunning the tests without modification of any of the services seems to
indicate everything works just fine and the source for the event
registration and events itself are considered equal.

I like to takes John McClain graduate course now, so some more questions:

1) Going through the source of the contributed services to see which
other proxies provided by Seven should take advantage of ReferentUuid I
noticed that for Reggie the decision was made to have
com.sun.jini.reggie.Registration implement ReferentUuid, while for the
other type of registrations (events) it was decided that they don't
implement ReferentUuid, what is the rationale behind that decision?

2) Why don't the equals implementation at least check whether the object
passed in for the test of equality implements the same interface. So a
Lease.equals(Object) should test whether object is of type Lease, etc,
same for transaction participant, etc. I'm aware the chance of 2 Uuids
clashing is rather small (of not done on purpose), though it seems 'more
correct' to test for having 2 object that implement also the primary
interface?
-- 
Mark



















Re: Equality for service proxies, leases, server transactions, etc.

Posted by Vinod Johnson - Sun Microsystems <Th...@Sun.COM>.
>
> The lookup service finds a match and notifies the exported remote event
> listener. The event is unmarshalled with a context class loader of B and
> a default class loader of B, this will result in the creation of a class
> loader D that has B as its parent. The service item part of the event is
> usable in the context of the plugin but in this case the SDM rejects the
> event because it turns out the source of the registration and the field
> doesn't match. Analysis learns that the source of the registration is
I must be missing something here, but do you see any exception from the 
SDM, or is the event silently dropped? In the case of reggie, its proxy 
implements equals (which the SDM uses to check for equality) to do a 
comparison on the net.jini.id.Uuid value returned from getReferentUuid. 
Is it that your registrar proxy does not do the same? Given the 
specification of ReferentUuid, it's probably better to actually compare 
the Uuids rather than test for equals - I can't answer the 
history/rationale behind the current state of the implementation.

-- 
- vinod