I just fixed the RMI-Test and spend about two hours debugging to find a very
subtle bug. (Or two).
1) One is serviceInstance creation on first methodInvocation: Thats fine unless
you are debugging and the first method
invocation on the service is the toString done by the Java Debugger API. This
doesn't show up anywhere in Breakpoints or
else. So after curiously wondering for some time, I introduced a empty
constructor with breakpoint which was never reached.
I then did two things: First added a new Throwable().printStackTrace() to the
constructor to see whats going on.
Secondly added a crude special handling for toString in
ServiceReferenceInstance.
2) So I noticed the real bug which was the duplicate instantiation of a
service, that ocurred during the passivation phase.
The current service (ServerRemoteEntityStoreMixin) unbinds in the passivate the
Registry which is the problematic
service under observation. The problem is the registry was already passivated
so the serviceInstance instance variable
inside ServiceReferenceInstance was already null. So on invocation of the
unbind() method a new registry was created on
which the unbind was called - which then failed because in a newly created
Registry there is nothing bound to be unbound.
Problems to be solved:
1) handle the object methods (equals, hashCode, wait, notify(All), toString)
not by directing them to the proxied
service (or in other cases entity) but rather have the CompositeInstance or
ServiceReferenceInstance handle them.
2) Have the passivation sorted out somehow. Either raise Exceptions on calls on
passivated composites. Or sort the
passivation that way that the higher level components can still access their
dependencies. Funny to get around with
cyclic dependencies. The problem is you never know which cleanup operations are
performed on services. Or have all
services be self-contained to that no external cleanup / resource release is
necessary.
For instance I changed the ServerRemoteEntityStoreMixin.passivate() to:
public void passivate() throws Exception
{
// registry.unbind( descriptor.identity() );
UnicastRemoteObject.unexportObject( remote, true );
}
and have the registry unbind all services on passivation
RegistryMixin.passivate():
public void passivate() throws Exception
{
for( String boundService : registry.list() )
{
registry.unbind( boundService );
}
UnicastRemoteObject.unexportObject( registry, true );
}
But thats only a local solution for this case.
Michael
_______________________________________________
qi4j-dev mailing list
[email protected]
http://lists.ops4j.org/mailman/listinfo/qi4j-dev