[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
