BJ Hargrave <[EMAIL PROTECTED]> writes:

> This would be best asked in the osgi-dev list since it is not a felix 
> specific issue.

Sorry, I had not yet subscribed to the osgi-dev list, so I just
did. I'll take the discussion over there.

> Wow. Change history for that file makes it my mistake... I have
> fixed it for 4.1. Thanks.

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.

[...]

> 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;
      }
   }


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 ) ) );
  }

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?

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?

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

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

Reply via email to