[EMAIL PROTECTED] wrote on 02/16/2007 04:13:35 PM:

> No problem. While we're mentioning document nits, several headings in
> Section 6, Framework API, mention interfaces that extend
> EventListener, but EventListener is never defined, and I don't see it
> as part of the OSGi-distributed class files.
> 

This is the standard java.util.EventListener. You can see this more 
clearly from the HTML javadoc 
[http://www2.osgi.org/javadoc/r4/org/osgi/framework/ServiceListener.html]

The custom doclet which we use to generate the javadoc for the PDF strips 
out the package names for brevity. 

> [...]
> 
> > A service listener can be called by multiple threads delivering
> > service events and can be reentered by the same thread if the
> > listener takes some action which fires a service event.
> >
> > Net: STC implementation must be thread safe.
> 
> I see. Thanks for the detailed explanation.
> 
> I have what seems to be a simple scenario, but I'm confused as to how
> to best use ServiceTracker. I'm watching for what I expect to be a
> singleton service coming and going; if there happens to be more than
> one instance registered, I'll still only pay attention to one at a
> time.
> 
> This service is of type A. In order to make use of A, I need to wrap
> it in several other decorating types B and C first:
> 
>   final C = new C( new B( getA() ) );
> 
> Think of an OutputStream, exposed as the service, being wrapped by a
> Writer being wrapped by a BufferedWriter, and so on. Constructing
> these layered wrappers might be expensive, so we'd only like to do it
> when the service is first registered, and repeat it only when we've
> lost one reference to the service and another one arrives.
> 
> To accommodate this scenario, my current implementation uses a
> ServiceTrackerCustomizer to create the C-wrapping-B-wrapping-A as
> above in the addingService() method. I'm also going the extra step of
> assigning this C instance to a member variable of the enclosing class,
> shown here with some names changed:
> 
>   public Object addingService(ServiceReference reference) {
>       synchronized( EnclosingClass.this ) {
>          // NB: c is a member variable of EnclosingClass.
>          if ( null == c ) {
>             c = new C( new B( (A) context.getService( reference ) ) );
>             return c;
>          } else
>             return null;
>       }
>    }

This is problematic since only the first A is wrapped and tracked. When 
that A in removed, you are out of luck! Since the tracker only knew about 
that A, there is no replacement for A available.

> 
> 
> Similarly:
> 
>   public void removedService(ServiceReference reference, Object service) 
{
>      synchronized( EnclosingClass.this ) {
>         if ( null != c ) {
>            c = null;
>            context.ungetService( reference );
>         }
>      }
>   }
> 
> Elsewhere in EnclosingClass, when I want to make use of my C instance,
> I do something like:
> 
>   private synchronized void useC() {
>     if ( null != c )
>       c.foo();
>   }
> 
> 
> Now, does this look like overkill? It's almost as much work as using a
> ServiceListener directly.
> 
> I now see that I could probably rewrite addingService() like this:
> 
>   public Object addingService(ServiceReference reference) {
>     return new C( new B( (A) context.getService( reference ) ) );
>   }
> 

This is fine if wrapping A is a lightweight since every tracked A will be 
wrapped. Assuming there will be only one A most of the time this is by far 
the simplest implementation!

> and not worry about whether I'm tracking any extra C instances beyond
> the one I care about.
> 
> Then, I could get rid of the "c" member variable and my useC() method
> could look more like:
> 
>   private void useC() {
>     final C c = (C) tracker.getService();
>     if ( null != c )
>       c.foo();
>   }
> 
> Is that more the intention of ServiceTracker?

Yes. It is better to never keep a copy of tracked service since it may 
change from time to time. Always call getService right before you want to 
use it.

> 
> Also, isn't it possible that in between the call to
> tracker.getService() and the call to C.foo() that the underlying A
> service being tracked could have gone away?

Yes, but that window is impossible to fully close without some global 
locks. You have to have some lock associated with the A wrapped by C such 
that in removedService when you see the ServiceReference for A arrive (A 
is being unregistered), you obtain that lock to block the unregistration 
of A. Since the thread using C which wraps A is holding the lock, the 
thread unregistering A and synchronously delivering the ServiceEvent will 
block attempting to get the lock. But this can be very dangerous. Proceed 
with extreme caution!!

> 
> One more question: Is it possible to configure a ServiceTracker to
> track at most one instance of a given service type?

Yes. You subclass ST to do that. The best solution would be to have 
addingService return the reference instead of 
context.getSerivce(reference). Then you can override the getService* 
methods to just-in-time convert the ref being tracked into the real 
service object. But your subclass will need to manage its own cache of 
service objects since the underlying ST only tracks the reference objects.

> 
> -- 
> Steven E. Harris
> _______________________________________________
> OSGi Developer Mail List
> [email protected]
> http://www2.osgi.org/mailman/listinfo/osgi-dev


BJ Hargrave
Senior Technical Staff Member, IBM
OSGi Fellow and CTO of the OSGi Alliance
[EMAIL PROTECTED]

office: +1 386 848 1781
mobile: +1 386 848 3788



_______________________________________________
OSGi Developer Mail List
[email protected]
http://www2.osgi.org/mailman/listinfo/osgi-dev

Reply via email to