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

Reply via email to