blob: f5cd086c5531ad72b08c1ca8e564ef4547bc7ad3 [file] [log] [blame]
Richard S. Hall2532cf82010-03-24 09:51:11 +00001/*
Richard S. Halld0dca9b2011-05-18 14:52:16 +00002 * Copyright (c) OSGi Alliance (2000, 2010). All Rights Reserved.
Richard S. Hall2532cf82010-03-24 09:51:11 +00003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.osgi.util.tracker;
18
Richard S. Halld0dca9b2011-05-18 14:52:16 +000019import java.lang.reflect.Array;
20import java.util.Collections;
21import java.util.SortedMap;
22import java.util.TreeMap;
Richard S. Hall2532cf82010-03-24 09:51:11 +000023
24import org.osgi.framework.AllServiceListener;
25import org.osgi.framework.BundleContext;
26import org.osgi.framework.Constants;
27import org.osgi.framework.Filter;
28import org.osgi.framework.InvalidSyntaxException;
29import org.osgi.framework.ServiceEvent;
30import org.osgi.framework.ServiceListener;
31import org.osgi.framework.ServiceReference;
Richard S. Hall2532cf82010-03-24 09:51:11 +000032
33/**
Richard S. Halld0dca9b2011-05-18 14:52:16 +000034 * The {@code ServiceTracker} class simplifies using services from the
Richard S. Hall2532cf82010-03-24 09:51:11 +000035 * Framework's service registry.
36 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +000037 * A {@code ServiceTracker} object is constructed with search criteria and
38 * a {@code ServiceTrackerCustomizer} object. A {@code ServiceTracker}
39 * can use a {@code ServiceTrackerCustomizer} to customize the service
40 * objects to be tracked. The {@code ServiceTracker} can then be opened to
Richard S. Hall2532cf82010-03-24 09:51:11 +000041 * begin tracking all services in the Framework's service registry that match
Richard S. Halld0dca9b2011-05-18 14:52:16 +000042 * the specified search criteria. The {@code ServiceTracker} correctly
43 * handles all of the details of listening to {@code ServiceEvent}s and
Richard S. Hall2532cf82010-03-24 09:51:11 +000044 * getting and ungetting services.
45 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +000046 * The {@code getServiceReferences} method can be called to get references
47 * to the services being tracked. The {@code getService} and
48 * {@code getServices} methods can be called to get the service objects for
Richard S. Hall2532cf82010-03-24 09:51:11 +000049 * the tracked service.
50 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +000051 * The {@code ServiceTracker} class is thread-safe. It does not call a
52 * {@code ServiceTrackerCustomizer} while holding any locks.
53 * {@code ServiceTrackerCustomizer} implementations must also be
Richard S. Hall2532cf82010-03-24 09:51:11 +000054 * thread-safe.
55 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +000056 * @param <S> The type of the service being tracked.
57 * @param <T> The type of the tracked object.
Richard S. Hall2532cf82010-03-24 09:51:11 +000058 * @ThreadSafe
Richard S. Halld0dca9b2011-05-18 14:52:16 +000059 * @version $Id: df62459c90f49d06e89ff8f20915a9eec401217e $
Richard S. Hall2532cf82010-03-24 09:51:11 +000060 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000061public class ServiceTracker<S, T> implements ServiceTrackerCustomizer<S, T> {
Richard S. Hall2532cf82010-03-24 09:51:11 +000062 /* set this to true to compile in debug messages */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000063 static final boolean DEBUG = false;
Richard S. Hall2532cf82010-03-24 09:51:11 +000064 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +000065 * The Bundle Context used by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +000066 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000067 protected final BundleContext context;
Richard S. Hall2532cf82010-03-24 09:51:11 +000068 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +000069 * The Filter used by this {@code ServiceTracker} which specifies the
Richard S. Hall2532cf82010-03-24 09:51:11 +000070 * search criteria for the services to track.
71 *
72 * @since 1.1
73 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000074 protected final Filter filter;
Richard S. Hall2532cf82010-03-24 09:51:11 +000075 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +000076 * The {@code ServiceTrackerCustomizer} for this tracker.
Richard S. Hall2532cf82010-03-24 09:51:11 +000077 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000078 final ServiceTrackerCustomizer<S, T> customizer;
Richard S. Hall2532cf82010-03-24 09:51:11 +000079 /**
80 * Filter string for use when adding the ServiceListener. If this field is
81 * set, then certain optimizations can be taken since we don't have a user
82 * supplied filter.
83 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000084 final String listenerFilter;
Richard S. Hall2532cf82010-03-24 09:51:11 +000085 /**
86 * Class name to be tracked. If this field is set, then we are tracking by
87 * class name.
88 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000089 private final String trackClass;
Richard S. Hall2532cf82010-03-24 09:51:11 +000090 /**
91 * Reference to be tracked. If this field is set, then we are tracking a
92 * single ServiceReference.
93 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000094 private final ServiceReference<S> trackReference;
Richard S. Hall2532cf82010-03-24 09:51:11 +000095 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +000096 * Tracked services: {@code ServiceReference} -> customized Object and
97 * {@code ServiceListener} object
Richard S. Hall2532cf82010-03-24 09:51:11 +000098 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000099 private volatile Tracked tracked;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000100
101 /**
102 * Accessor method for the current Tracked object. This method is only
103 * intended to be used by the unsynchronized methods which do not modify the
104 * tracked field.
105 *
106 * @return The current Tracked object.
107 */
108 private Tracked tracked() {
109 return tracked;
110 }
111
112 /**
113 * Cached ServiceReference for getServiceReference.
114 *
115 * This field is volatile since it is accessed by multiple threads.
116 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000117 private volatile ServiceReference<S> cachedReference;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000118 /**
119 * Cached service object for getService.
120 *
121 * This field is volatile since it is accessed by multiple threads.
122 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000123 private volatile T cachedService;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000124
125 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000126 * Create a {@code ServiceTracker} on the specified
127 * {@code ServiceReference}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000128 *
129 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000130 * The service referenced by the specified {@code ServiceReference}
131 * will be tracked by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000132 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000133 * @param context The {@code BundleContext} against which the tracking
Richard S. Hall2532cf82010-03-24 09:51:11 +0000134 * is done.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000135 * @param reference The {@code ServiceReference} for the service to be
Richard S. Hall2532cf82010-03-24 09:51:11 +0000136 * tracked.
137 * @param customizer The customizer object to call when services are added,
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000138 * modified, or removed in this {@code ServiceTracker}. If
139 * customizer is {@code null}, then this
140 * {@code ServiceTracker} will be used as the
141 * {@code ServiceTrackerCustomizer} and this
142 * {@code ServiceTracker} will call the
143 * {@code ServiceTrackerCustomizer} methods on itself.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000144 */
145 public ServiceTracker(final BundleContext context,
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000146 final ServiceReference<S> reference,
147 final ServiceTrackerCustomizer<S, T> customizer) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000148 this.context = context;
149 this.trackReference = reference;
150 this.trackClass = null;
151 this.customizer = (customizer == null) ? this : customizer;
152 this.listenerFilter = "(" + Constants.SERVICE_ID + "="
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000153 + reference.getProperty(Constants.SERVICE_ID).toString() + ")";
Richard S. Hall2532cf82010-03-24 09:51:11 +0000154 try {
155 this.filter = context.createFilter(listenerFilter);
156 }
157 catch (InvalidSyntaxException e) {
158 /*
159 * we could only get this exception if the ServiceReference was
160 * invalid
161 */
162 IllegalArgumentException iae = new IllegalArgumentException(
163 "unexpected InvalidSyntaxException: " + e.getMessage());
164 iae.initCause(e);
165 throw iae;
166 }
167 }
168
169 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000170 * Create a {@code ServiceTracker} on the specified class name.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000171 *
172 * <p>
173 * Services registered under the specified class name will be tracked by
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000174 * this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000175 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000176 * @param context The {@code BundleContext} against which the tracking
Richard S. Hall2532cf82010-03-24 09:51:11 +0000177 * is done.
178 * @param clazz The class name of the services to be tracked.
179 * @param customizer The customizer object to call when services are added,
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000180 * modified, or removed in this {@code ServiceTracker}. If
181 * customizer is {@code null}, then this
182 * {@code ServiceTracker} will be used as the
183 * {@code ServiceTrackerCustomizer} and this
184 * {@code ServiceTracker} will call the
185 * {@code ServiceTrackerCustomizer} methods on itself.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000186 */
187 public ServiceTracker(final BundleContext context, final String clazz,
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000188 final ServiceTrackerCustomizer<S, T> customizer) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000189 this.context = context;
190 this.trackReference = null;
191 this.trackClass = clazz;
192 this.customizer = (customizer == null) ? this : customizer;
193 // we call clazz.toString to verify clazz is non-null!
194 this.listenerFilter = "(" + Constants.OBJECTCLASS + "="
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000195 + clazz.toString() + ")";
Richard S. Hall2532cf82010-03-24 09:51:11 +0000196 try {
197 this.filter = context.createFilter(listenerFilter);
198 }
199 catch (InvalidSyntaxException e) {
200 /*
201 * we could only get this exception if the clazz argument was
202 * malformed
203 */
204 IllegalArgumentException iae = new IllegalArgumentException(
205 "unexpected InvalidSyntaxException: " + e.getMessage());
206 iae.initCause(e);
207 throw iae;
208 }
209 }
210
211 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000212 * Create a {@code ServiceTracker} on the specified {@code Filter}
Richard S. Hall2532cf82010-03-24 09:51:11 +0000213 * object.
214 *
215 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000216 * Services which match the specified {@code Filter} object will be
217 * tracked by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000218 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000219 * @param context The {@code BundleContext} against which the tracking
Richard S. Hall2532cf82010-03-24 09:51:11 +0000220 * is done.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000221 * @param filter The {@code Filter} to select the services to be
Richard S. Hall2532cf82010-03-24 09:51:11 +0000222 * tracked.
223 * @param customizer The customizer object to call when services are added,
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000224 * modified, or removed in this {@code ServiceTracker}. If
225 * customizer is null, then this {@code ServiceTracker} will be
226 * used as the {@code ServiceTrackerCustomizer} and this
227 * {@code ServiceTracker} will call the
228 * {@code ServiceTrackerCustomizer} methods on itself.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000229 * @since 1.1
230 */
231 public ServiceTracker(final BundleContext context, final Filter filter,
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000232 final ServiceTrackerCustomizer<S, T> customizer) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000233 this.context = context;
234 this.trackReference = null;
235 this.trackClass = null;
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000236 this.listenerFilter = filter.toString();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000237 this.filter = filter;
238 this.customizer = (customizer == null) ? this : customizer;
239 if ((context == null) || (filter == null)) {
240 /*
241 * we throw a NPE here to be consistent with the other constructors
242 */
243 throw new NullPointerException();
244 }
245 }
246
247 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000248 * Create a {@code ServiceTracker} on the specified class.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000249 *
250 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000251 * Services registered under the name of the specified class will be tracked
252 * by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000253 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000254 * @param context The {@code BundleContext} against which the tracking
255 * is done.
256 * @param clazz The class of the services to be tracked.
257 * @param customizer The customizer object to call when services are added,
258 * modified, or removed in this {@code ServiceTracker}. If
259 * customizer is {@code null}, then this
260 * {@code ServiceTracker} will be used as the
261 * {@code ServiceTrackerCustomizer} and this
262 * {@code ServiceTracker} will call the
263 * {@code ServiceTrackerCustomizer} methods on itself.
264 * @since 1.5
265 */
266 public ServiceTracker(final BundleContext context, final Class<S> clazz,
267 final ServiceTrackerCustomizer<S, T> customizer) {
268 this(context, clazz.getName(), customizer);
269 }
270
271 /**
272 * Open this {@code ServiceTracker} and begin tracking services.
273 *
274 * <p>
275 * This implementation calls {@code open(false)}.
276 *
277 * @throws java.lang.IllegalStateException If the {@code BundleContext}
278 * with which this {@code ServiceTracker} was created is no
Richard S. Hall2532cf82010-03-24 09:51:11 +0000279 * longer valid.
280 * @see #open(boolean)
281 */
282 public void open() {
283 open(false);
284 }
285
286 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000287 * Open this {@code ServiceTracker} and begin tracking services.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000288 *
289 * <p>
290 * Services which match the search criteria specified when this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000291 * {@code ServiceTracker} was created are now tracked by this
292 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000293 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000294 * @param trackAllServices If {@code true}, then this
295 * {@code ServiceTracker} will track all matching services
296 * regardless of class loader accessibility. If {@code false},
297 * then this {@code ServiceTracker} will only track matching
Richard S. Hall2532cf82010-03-24 09:51:11 +0000298 * services which are class loader accessible to the bundle whose
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000299 * {@code BundleContext} is used by this
300 * {@code ServiceTracker}.
301 * @throws java.lang.IllegalStateException If the {@code BundleContext}
302 * with which this {@code ServiceTracker} was created is no
Richard S. Hall2532cf82010-03-24 09:51:11 +0000303 * longer valid.
304 * @since 1.3
305 */
306 public void open(boolean trackAllServices) {
307 final Tracked t;
308 synchronized (this) {
309 if (tracked != null) {
310 return;
311 }
312 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000313 System.out.println("ServiceTracker.open: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000314 }
315 t = trackAllServices ? new AllTracked() : new Tracked();
316 synchronized (t) {
317 try {
318 context.addServiceListener(t, listenerFilter);
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000319 ServiceReference<S>[] references = null;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000320 if (trackClass != null) {
321 references = getInitialReferences(trackAllServices,
322 trackClass, null);
323 }
324 else {
325 if (trackReference != null) {
326 if (trackReference.getBundle() != null) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000327 ServiceReference<S>[] single = new ServiceReference[] {trackReference};
328 references = single;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000329 }
330 }
331 else { /* user supplied filter */
332 references = getInitialReferences(trackAllServices,
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000333 null, listenerFilter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000334 }
335 }
336 /* set tracked with the initial references */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000337 t.setInitial(references);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000338 }
339 catch (InvalidSyntaxException e) {
340 throw new RuntimeException(
341 "unexpected InvalidSyntaxException: "
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000342 + e.getMessage(), e);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000343 }
344 }
345 tracked = t;
346 }
347 /* Call tracked outside of synchronized region */
348 t.trackInitial(); /* process the initial references */
349 }
350
351 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000352 * Returns the list of initial {@code ServiceReference}s that will be
353 * tracked by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000354 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000355 * @param trackAllServices If {@code true}, use
356 * {@code getAllServiceReferences}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000357 * @param className The class name with which the service was registered, or
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000358 * {@code null} for all services.
359 * @param filterString The filter criteria or {@code null} for all
Richard S. Hall2532cf82010-03-24 09:51:11 +0000360 * services.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000361 * @return The list of initial {@code ServiceReference}s.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000362 * @throws InvalidSyntaxException If the specified filterString has an
363 * invalid syntax.
364 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000365 private ServiceReference<S>[] getInitialReferences(
366 boolean trackAllServices, String className, String filterString)
Richard S. Hall2532cf82010-03-24 09:51:11 +0000367 throws InvalidSyntaxException {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000368 ServiceReference<S>[] result = (ServiceReference<S>[]) ((trackAllServices) ? context
369 .getAllServiceReferences(className, filterString)
370 : context.getServiceReferences(className, filterString));
371 return result;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000372 }
373
374 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000375 * Close this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000376 *
377 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000378 * This method should be called when this {@code ServiceTracker} should
Richard S. Hall2532cf82010-03-24 09:51:11 +0000379 * end the tracking of services.
380 *
381 * <p>
382 * This implementation calls {@link #getServiceReferences()} to get the list
383 * of tracked services to remove.
384 */
385 public void close() {
386 final Tracked outgoing;
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000387 final ServiceReference<S>[] references;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000388 synchronized (this) {
389 outgoing = tracked;
390 if (outgoing == null) {
391 return;
392 }
393 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000394 System.out.println("ServiceTracker.close: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000395 }
396 outgoing.close();
397 references = getServiceReferences();
398 tracked = null;
399 try {
400 context.removeServiceListener(outgoing);
401 }
402 catch (IllegalStateException e) {
403 /* In case the context was stopped. */
404 }
405 }
406 modified(); /* clear the cache */
407 synchronized (outgoing) {
408 outgoing.notifyAll(); /* wake up any waiters */
409 }
410 if (references != null) {
411 for (int i = 0; i < references.length; i++) {
412 outgoing.untrack(references[i], null);
413 }
414 }
415 if (DEBUG) {
416 if ((cachedReference == null) && (cachedService == null)) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000417 System.out.println("ServiceTracker.close[cached cleared]: "
418 + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000419 }
420 }
421 }
422
423 /**
424 * Default implementation of the
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000425 * {@code ServiceTrackerCustomizer.addingService} method.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000426 *
427 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000428 * This method is only called when this {@code ServiceTracker} has been
429 * constructed with a {@code null ServiceTrackerCustomizer} argument.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000430 *
431 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000432 * This implementation returns the result of calling {@code getService}
433 * on the {@code BundleContext} with which this
434 * {@code ServiceTracker} was created passing the specified
435 * {@code ServiceReference}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000436 * <p>
437 * This method can be overridden in a subclass to customize the service
438 * object to be tracked for the service being added. In that case, take care
439 * not to rely on the default implementation of
440 * {@link #removedService(ServiceReference, Object) removedService} to unget
441 * the service.
442 *
443 * @param reference The reference to the service being added to this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000444 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000445 * @return The service object to be tracked for the service added to this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000446 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000447 * @see ServiceTrackerCustomizer#addingService(ServiceReference)
448 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000449 public T addingService(ServiceReference<S> reference) {
450 T result = (T) context.getService(reference);
451 return result;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000452 }
453
454 /**
455 * Default implementation of the
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000456 * {@code ServiceTrackerCustomizer.modifiedService} method.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000457 *
458 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000459 * This method is only called when this {@code ServiceTracker} has been
460 * constructed with a {@code null ServiceTrackerCustomizer} argument.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000461 *
462 * <p>
463 * This implementation does nothing.
464 *
465 * @param reference The reference to modified service.
466 * @param service The service object for the modified service.
467 * @see ServiceTrackerCustomizer#modifiedService(ServiceReference, Object)
468 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000469 public void modifiedService(ServiceReference<S> reference, T service) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000470 /* do nothing */
471 }
472
473 /**
474 * Default implementation of the
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000475 * {@code ServiceTrackerCustomizer.removedService} method.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000476 *
477 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000478 * This method is only called when this {@code ServiceTracker} has been
479 * constructed with a {@code null ServiceTrackerCustomizer} argument.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000480 *
481 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000482 * This implementation calls {@code ungetService}, on the
483 * {@code BundleContext} with which this {@code ServiceTracker}
484 * was created, passing the specified {@code ServiceReference}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000485 * <p>
486 * This method can be overridden in a subclass. If the default
487 * implementation of {@link #addingService(ServiceReference) addingService}
488 * method was used, this method must unget the service.
489 *
490 * @param reference The reference to removed service.
491 * @param service The service object for the removed service.
492 * @see ServiceTrackerCustomizer#removedService(ServiceReference, Object)
493 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000494 public void removedService(ServiceReference<S> reference, T service) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000495 context.ungetService(reference);
496 }
497
498 /**
499 * Wait for at least one service to be tracked by this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000500 * {@code ServiceTracker}. This method will also return when this
501 * {@code ServiceTracker} is closed.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000502 *
503 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000504 * It is strongly recommended that {@code waitForService} is not used
505 * during the calling of the {@code BundleActivator} methods.
506 * {@code BundleActivator} methods are expected to complete in a short
Richard S. Hall2532cf82010-03-24 09:51:11 +0000507 * period of time.
508 *
509 * <p>
510 * This implementation calls {@link #getService()} to determine if a service
511 * is being tracked.
512 *
513 * @param timeout The time interval in milliseconds to wait. If zero, the
514 * method will wait indefinitely.
515 * @return Returns the result of {@link #getService()}.
516 * @throws InterruptedException If another thread has interrupted the
517 * current thread.
518 * @throws IllegalArgumentException If the value of timeout is negative.
519 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000520 public T waitForService(long timeout) throws InterruptedException {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000521 if (timeout < 0) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000522 throw new IllegalArgumentException("timeout value is negative");
Richard S. Hall2532cf82010-03-24 09:51:11 +0000523 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000524 T object = getService();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000525 while (object == null) {
526 final Tracked t = tracked();
527 if (t == null) { /* if ServiceTracker is not open */
528 return null;
529 }
530 synchronized (t) {
531 if (t.size() == 0) {
532 t.wait(timeout);
533 }
534 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000535 object = getService();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000536 if (timeout > 0) {
537 return object;
538 }
539 }
540 return object;
541 }
542
543 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000544 * Return an array of {@code ServiceReference}s for all services being
545 * tracked by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000546 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000547 * @return Array of {@code ServiceReference}s or {@code null} if
Richard S. Hall2532cf82010-03-24 09:51:11 +0000548 * no services are being tracked.
549 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000550 public ServiceReference<S>[] getServiceReferences() {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000551 final Tracked t = tracked();
552 if (t == null) { /* if ServiceTracker is not open */
553 return null;
554 }
555 synchronized (t) {
556 int length = t.size();
557 if (length == 0) {
558 return null;
559 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000560 ServiceReference<S>[] result = new ServiceReference[length];
561 return t.copyKeys(result);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000562 }
563 }
564
565 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000566 * Returns a {@code ServiceReference} for one of the services being
567 * tracked by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000568 *
569 * <p>
570 * If multiple services are being tracked, the service with the highest
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000571 * ranking (as specified in its {@code service.ranking} property) is
Richard S. Hall2532cf82010-03-24 09:51:11 +0000572 * returned. If there is a tie in ranking, the service with the lowest
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000573 * service ID (as specified in its {@code service.id} property); that
Richard S. Hall2532cf82010-03-24 09:51:11 +0000574 * is, the service that was registered first is returned. This is the same
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000575 * algorithm used by {@code BundleContext.getServiceReference}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000576 *
577 * <p>
578 * This implementation calls {@link #getServiceReferences()} to get the list
579 * of references for the tracked services.
580 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000581 * @return A {@code ServiceReference} or {@code null} if no
Richard S. Hall2532cf82010-03-24 09:51:11 +0000582 * services are being tracked.
583 * @since 1.1
584 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000585 public ServiceReference<S> getServiceReference() {
586 ServiceReference<S> reference = cachedReference;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000587 if (reference != null) {
588 if (DEBUG) {
589 System.out
590 .println("ServiceTracker.getServiceReference[cached]: "
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000591 + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000592 }
593 return reference;
594 }
595 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000596 System.out.println("ServiceTracker.getServiceReference: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000597 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000598 ServiceReference<S>[] references = getServiceReferences();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000599 int length = (references == null) ? 0 : references.length;
600 if (length == 0) { /* if no service is being tracked */
601 return null;
602 }
603 int index = 0;
604 if (length > 1) { /* if more than one service, select highest ranking */
605 int rankings[] = new int[length];
606 int count = 0;
607 int maxRanking = Integer.MIN_VALUE;
608 for (int i = 0; i < length; i++) {
609 Object property = references[i]
610 .getProperty(Constants.SERVICE_RANKING);
611 int ranking = (property instanceof Integer) ? ((Integer) property)
612 .intValue()
613 : 0;
614 rankings[i] = ranking;
615 if (ranking > maxRanking) {
616 index = i;
617 maxRanking = ranking;
618 count = 1;
619 }
620 else {
621 if (ranking == maxRanking) {
622 count++;
623 }
624 }
625 }
626 if (count > 1) { /* if still more than one service, select lowest id */
627 long minId = Long.MAX_VALUE;
628 for (int i = 0; i < length; i++) {
629 if (rankings[i] == maxRanking) {
630 long id = ((Long) (references[i]
631 .getProperty(Constants.SERVICE_ID)))
632 .longValue();
633 if (id < minId) {
634 index = i;
635 minId = id;
636 }
637 }
638 }
639 }
640 }
641 return cachedReference = references[index];
642 }
643
644 /**
645 * Returns the service object for the specified
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000646 * {@code ServiceReference} if the specified referenced service is
647 * being tracked by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000648 *
649 * @param reference The reference to the desired service.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000650 * @return A service object or {@code null} if the service referenced
651 * by the specified {@code ServiceReference} is not being
Richard S. Hall2532cf82010-03-24 09:51:11 +0000652 * tracked.
653 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000654 public T getService(ServiceReference<S> reference) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000655 final Tracked t = tracked();
656 if (t == null) { /* if ServiceTracker is not open */
657 return null;
658 }
659 synchronized (t) {
660 return t.getCustomizedObject(reference);
661 }
662 }
663
664 /**
665 * Return an array of service objects for all services being tracked by this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000666 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000667 *
668 * <p>
669 * This implementation calls {@link #getServiceReferences()} to get the list
670 * of references for the tracked services and then calls
671 * {@link #getService(ServiceReference)} for each reference to get the
672 * tracked service object.
673 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000674 * @return An array of service objects or {@code null} if no services
Richard S. Hall2532cf82010-03-24 09:51:11 +0000675 * are being tracked.
676 */
677 public Object[] getServices() {
678 final Tracked t = tracked();
679 if (t == null) { /* if ServiceTracker is not open */
680 return null;
681 }
682 synchronized (t) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000683 ServiceReference<S>[] references = getServiceReferences();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000684 int length = (references == null) ? 0 : references.length;
685 if (length == 0) {
686 return null;
687 }
688 Object[] objects = new Object[length];
689 for (int i = 0; i < length; i++) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000690 objects[i] = getService(references[i]);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000691 }
692 return objects;
693 }
694 }
695
696 /**
697 * Returns a service object for one of the services being tracked by this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000698 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000699 *
700 * <p>
701 * If any services are being tracked, this implementation returns the result
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000702 * of calling {@code getService(getServiceReference())}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000703 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000704 * @return A service object or {@code null} if no services are being
Richard S. Hall2532cf82010-03-24 09:51:11 +0000705 * tracked.
706 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000707 public T getService() {
708 T service = cachedService;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000709 if (service != null) {
710 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000711 System.out.println("ServiceTracker.getService[cached]: "
712 + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000713 }
714 return service;
715 }
716 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000717 System.out.println("ServiceTracker.getService: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000718 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000719 ServiceReference<S> reference = getServiceReference();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000720 if (reference == null) {
721 return null;
722 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000723 return cachedService = getService(reference);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000724 }
725
726 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000727 * Remove a service from this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000728 *
729 * The specified service will be removed from this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000730 * {@code ServiceTracker}. If the specified service was being tracked
731 * then the {@code ServiceTrackerCustomizer.removedService} method will
Richard S. Hall2532cf82010-03-24 09:51:11 +0000732 * be called for that service.
733 *
734 * @param reference The reference to the service to be removed.
735 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000736 public void remove(ServiceReference<S> reference) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000737 final Tracked t = tracked();
738 if (t == null) { /* if ServiceTracker is not open */
739 return;
740 }
741 t.untrack(reference, null);
742 }
743
744 /**
745 * Return the number of services being tracked by this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000746 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000747 *
748 * @return The number of services being tracked.
749 */
750 public int size() {
751 final Tracked t = tracked();
752 if (t == null) { /* if ServiceTracker is not open */
753 return 0;
754 }
755 synchronized (t) {
756 return t.size();
757 }
758 }
759
760 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000761 * Returns the tracking count for this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000762 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000763 * The tracking count is initialized to 0 when this {@code ServiceTracker}
764 * is opened. Every time a service is added, modified or removed from this
765 * {@code ServiceTracker}, the tracking count is incremented.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000766 *
767 * <p>
768 * The tracking count can be used to determine if this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000769 * {@code ServiceTracker} has added, modified or removed a service by
Richard S. Hall2532cf82010-03-24 09:51:11 +0000770 * comparing a tracking count value previously collected with the current
771 * tracking count value. If the value has not changed, then no service has
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000772 * been added, modified or removed from this {@code ServiceTracker} since
773 * the previous tracking count was collected.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000774 *
775 * @since 1.2
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000776 * @return The tracking count for this {@code ServiceTracker} or -1 if this
777 * {@code ServiceTracker} is not open.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000778 */
779 public int getTrackingCount() {
780 final Tracked t = tracked();
781 if (t == null) { /* if ServiceTracker is not open */
782 return -1;
783 }
784 synchronized (t) {
785 return t.getTrackingCount();
786 }
787 }
788
789 /**
790 * Called by the Tracked object whenever the set of tracked services is
791 * modified. Clears the cache.
792 */
793 /*
794 * This method must not be synchronized since it is called by Tracked while
795 * Tracked is synchronized. We don't want synchronization interactions
796 * between the listener thread and the user thread.
797 */
798 void modified() {
799 cachedReference = null; /* clear cached value */
800 cachedService = null; /* clear cached value */
801 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000802 System.out.println("ServiceTracker.modified: " + filter);
803 }
804 }
805
806 /**
807 * Return a {@code SortedMap} of the {@code ServiceReference}s and
808 * service objects for all services being tracked by this
809 * {@code ServiceTracker}. The map is sorted in reverse natural order
810 * of {@code ServiceReference}. That is, the first entry is the service
811 * with the highest ranking and the lowest service id.
812 *
813 * @return A {@code SortedMap} with the {@code ServiceReference}s
814 * and service objects for all services being tracked by this
815 * {@code ServiceTracker}. If no services are being tracked,
816 * then the returned map is empty.
817 * @since 1.5
818 */
819 public SortedMap<ServiceReference<S>, T> getTracked() {
820 SortedMap<ServiceReference<S>, T> map = new TreeMap<ServiceReference<S>, T>(
821 Collections.reverseOrder());
822 final Tracked t = tracked();
823 if (t == null) { /* if ServiceTracker is not open */
824 return map;
825 }
826 synchronized (t) {
827 return t.copyEntries(map);
828 }
829 }
830
831 /**
832 * Return if this {@code ServiceTracker} is empty.
833 *
834 * @return {@code true} if this {@code ServiceTracker} is not tracking any
835 * services.
836 * @since 1.5
837 */
838 public boolean isEmpty() {
839 final Tracked t = tracked();
840 if (t == null) { /* if ServiceTracker is not open */
841 return true;
842 }
843 synchronized (t) {
844 return t.isEmpty();
845 }
846 }
847
848 /**
849 * Return an array of service objects for all services being tracked by this
850 * {@code ServiceTracker}. The runtime type of the returned array is that of
851 * the specified array.
852 *
853 * <p>
854 * This implementation calls {@link #getServiceReferences()} to get the list
855 * of references for the tracked services and then calls
856 * {@link #getService(ServiceReference)} for each reference to get the
857 * tracked service object.
858 *
859 * @param array An array into which the tracked service objects will be
860 * stored, if the array is large enough.
861 * @return An array of service objects being tracked. If the specified array
862 * is large enough to hold the result, then the specified array is
863 * returned. If the specified array is longer then necessary to hold
864 * the result, the array element after the last service object is
865 * set to {@code null}. If the specified array is not large enough
866 * to hold the result, a new array is created and returned.
867 * @since 1.5
868 */
869 public T[] getServices(T[] array) {
870 final Tracked t = tracked();
871 if (t == null) { /* if ServiceTracker is not open */
872 if (array.length > 0) {
873 array[0] = null;
874 }
875 return array;
876 }
877 synchronized (t) {
878 ServiceReference<S>[] references = getServiceReferences();
879 int length = (references == null) ? 0 : references.length;
880 if (length == 0) {
881 if (array.length > 0) {
882 array[0] = null;
883 }
884 return array;
885 }
886 if (length > array.length) {
887 array = (T[]) Array.newInstance(array.getClass()
888 .getComponentType(), length);
889 }
890 for (int i = 0; i < length; i++) {
891 array[i] = getService(references[i]);
892 }
893 if (array.length > length) {
894 array[length] = null;
895 }
896 return array;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000897 }
898 }
899
900 /**
901 * Inner class which subclasses AbstractTracked. This class is the
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000902 * {@code ServiceListener} object for the tracker.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000903 *
904 * @ThreadSafe
905 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000906 private class Tracked extends
907 AbstractTracked<ServiceReference<S>, T, ServiceEvent>
908 implements ServiceListener {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000909 /**
910 * Tracked constructor.
911 */
912 Tracked() {
913 super();
914 }
915
916 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000917 * {@code ServiceListener} method for the
918 * {@code ServiceTracker} class. This method must NOT be
Richard S. Hall2532cf82010-03-24 09:51:11 +0000919 * synchronized to avoid deadlock potential.
920 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000921 * @param event {@code ServiceEvent} object from the framework.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000922 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000923 final public void serviceChanged(final ServiceEvent event) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000924 /*
925 * Check if we had a delayed call (which could happen when we
926 * close).
927 */
928 if (closed) {
929 return;
930 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000931 final ServiceReference<S> reference = (ServiceReference<S>) event
932 .getServiceReference();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000933 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000934 System.out.println("ServiceTracker.Tracked.serviceChanged["
935 + event.getType() + "]: " + reference);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000936 }
937
938 switch (event.getType()) {
939 case ServiceEvent.REGISTERED :
940 case ServiceEvent.MODIFIED :
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000941 track(reference, event);
942 /*
943 * If the customizer throws an unchecked exception, it is
944 * safe to let it propagate
945 */
Richard S. Hall2532cf82010-03-24 09:51:11 +0000946 break;
947 case ServiceEvent.MODIFIED_ENDMATCH :
948 case ServiceEvent.UNREGISTERING :
949 untrack(reference, event);
950 /*
951 * If the customizer throws an unchecked exception, it is
952 * safe to let it propagate
953 */
954 break;
955 }
956 }
957
958 /**
959 * Increment the tracking count and tell the tracker there was a
960 * modification.
961 *
962 * @GuardedBy this
963 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000964 final void modified() {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000965 super.modified(); /* increment the modification count */
966 ServiceTracker.this.modified();
967 }
968
969 /**
970 * Call the specific customizer adding method. This method must not be
971 * called while synchronized on this object.
972 *
973 * @param item Item to be tracked.
974 * @param related Action related object.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000975 * @return Customized object for the tracked item or {@code null}
Richard S. Hall2532cf82010-03-24 09:51:11 +0000976 * if the item is not to be tracked.
977 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000978 final T customizerAdding(final ServiceReference<S> item,
979 final ServiceEvent related) {
980 return customizer.addingService(item);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000981 }
982
983 /**
984 * Call the specific customizer modified method. This method must not be
985 * called while synchronized on this object.
986 *
987 * @param item Tracked item.
988 * @param related Action related object.
989 * @param object Customized object for the tracked item.
990 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000991 final void customizerModified(final ServiceReference<S> item,
992 final ServiceEvent related, final T object) {
993 customizer.modifiedService(item, object);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000994 }
995
996 /**
997 * Call the specific customizer removed method. This method must not be
998 * called while synchronized on this object.
999 *
1000 * @param item Tracked item.
1001 * @param related Action related object.
1002 * @param object Customized object for the tracked item.
1003 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +00001004 final void customizerRemoved(final ServiceReference<S> item,
1005 final ServiceEvent related, final T object) {
1006 customizer.removedService(item, object);
Richard S. Hall2532cf82010-03-24 09:51:11 +00001007 }
1008 }
1009
1010 /**
1011 * Subclass of Tracked which implements the AllServiceListener interface.
1012 * This class is used by the ServiceTracker if open is called with true.
1013 *
1014 * @since 1.3
1015 * @ThreadSafe
1016 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +00001017 private class AllTracked extends Tracked implements AllServiceListener {
Richard S. Hall2532cf82010-03-24 09:51:11 +00001018 /**
1019 * AllTracked constructor.
1020 */
1021 AllTracked() {
1022 super();
1023 }
1024 }
1025}