ares
ares

Reputation: 4413

In OSGi, what is the difference between type of service being tracked and type of the tracked object

In OSGi the class ServiceTracker defines two type parameters:

  1. S - The type of the service being tracked.
  2. T - The type of the tracked object.

What is the difference between the two of them?

Upvotes: 3

Views: 102

Answers (3)

BJ Hargrave
BJ Hargrave

Reputation: 9374

T allows you to track a different type than that service type S. For example, you can wrap the service S in an object of type T. For most use cases S and T are the same. But there are use cases where T != S.

Upvotes: 1

Peter Kriens
Peter Kriens

Reputation: 15372

In almost all cases I use the service tracker I need to do some housekeeping related to the tracked object. When the tracked object goes away, that housekeeping info should be garbage collected.

So for example, you track WhiteboardListeners. However, you want to keep track how long they use for their callback and deny them service if they use too much time. So we create a wrapper:

public class Example {

  interface Whiteboard {
    void visit();
  }

  static class Wrapper {
    Whiteboard  whiteboard;
    AtomicLong  averageTime = new AtomicLong();

    public Wrapper(Whiteboard whiteboard) {
        this.whiteboard = whiteboard;
    }

    void visit() {
        if (averageTime.get() < 100) {
            long start = System.currentTimeMillis();
            whiteboard.visit();
            long time = System.currentTimeMillis() - start;
            averageTime.getAndUpdate(v -> (99 * v + time) / 100);
        } else
            averageTime.getAndUpdate(v -> (99 * v) / 100);
    }
  }

  ServiceTracker<Whiteboard, Wrapper> tracker;

  @Activate
  void activate(BundleContext context) {
      tracker = new ServiceTracker<Whiteboard, Wrapper>(context,
            Whiteboard.class, null) {
        @Override
        public Wrapper addingService(
                ServiceReference<Whiteboard> reference) {
            return new Wrapper(context.getService(reference));
        }

        @Override
        public void removedService(ServiceReference<Whiteboard> reference,
                Wrapper service) {
            context.ungetService(reference);
        }
    };
    tracker.open();
  }

  void visit() {
    tracker.getTracked().values().forEach(wrapper -> wrapper.visit());
  }
}

I rarely use the Service Tracker nowadays because Declarative Services does the job in most cases a lot easier. However, when I use the Service Tracker, I rarely ever have S==T.

Upvotes: 3

Christian Schneider
Christian Schneider

Reputation: 19606

The tracked object allows you to do any necessary housekeeping when the service is removed again.

As an example see the trackers in pax-jdbc. In this case we need two services. The PooledDataSourceFactoryTracker will start another tracker for the DataSourceFactory. This second tracker is the tracked object of the first tracker. When the PooledDataSourceFactory is removed again then the other DataSourceFactory tracker is also closed.

This approach allows to track more than one service or do other houskeeping on service removal without having to deal with the threading.

Be aware though that even with this approach service trackers are very difficult to use correctly. In most cases it is better to use a frameworks like declarative services from the start.

Upvotes: 1

Related Questions