1 /*
2  * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved.
3  *
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 
17 package org.osgi.util.tracker;
18 
19 import java.lang.reflect.Array;
20 import java.util.Collections;
21 import java.util.SortedMap;
22 import java.util.TreeMap;
23 
24 import org.osgi.annotation.versioning.ConsumerType;
25 import org.osgi.framework.AllServiceListener;
26 import org.osgi.framework.BundleContext;
27 import org.osgi.framework.Constants;
28 import org.osgi.framework.Filter;
29 import org.osgi.framework.InvalidSyntaxException;
30 import org.osgi.framework.ServiceEvent;
31 import org.osgi.framework.ServiceListener;
32 import org.osgi.framework.ServiceReference;
33 
34 /**
35  * The {@code ServiceTracker} class simplifies using services from the
36  * Framework's service registry.
37  * <p>
38  * A {@code ServiceTracker} object is constructed with search criteria and a
39  * {@code ServiceTrackerCustomizer} object. A {@code ServiceTracker} can use a
40  * {@code ServiceTrackerCustomizer} to customize the service objects to be
41  * tracked. The {@code ServiceTracker} can then be opened to begin tracking all
42  * services in the Framework's service registry that match the specified search
43  * criteria. The {@code ServiceTracker} correctly handles all of the details of
44  * listening to {@code ServiceEvent}s and getting and ungetting services.
45  * <p>
46  * The {@code getServiceReferences} method can be called to get references to
47  * the services being tracked. The {@code getService} and {@code getServices}
48  * methods can be called to get the service objects for the tracked service.
49  * <p>
50  * The {@code ServiceTracker} class is thread-safe. It does not call a
51  * {@code ServiceTrackerCustomizer} while holding any locks.
52  * {@code ServiceTrackerCustomizer} implementations must also be thread-safe.
53  *
54  * @param <S> The type of the service being tracked.
55  * @param <T> The type of the tracked object.
56  * @ThreadSafe
57  * @author $Id: 3c9016c43c6289259f97470eff4c9986b6fb887a $
58  */
59 @ConsumerType
60 public class ServiceTracker<S, T> implements ServiceTrackerCustomizer<S, T> {
61 	/* set this to true to compile in debug messages */
62 	static final boolean					DEBUG	= false;
63 	/**
64 	 * The Bundle Context used by this {@code ServiceTracker}.
65 	 */
66 	protected final BundleContext			context;
67 	/**
68 	 * The Filter used by this {@code ServiceTracker} which specifies the search
69 	 * criteria for the services to track.
70 	 *
71 	 * @since 1.1
72 	 */
73 	protected final Filter					filter;
74 	/**
75 	 * The {@code ServiceTrackerCustomizer} for this tracker.
76 	 */
77 	final ServiceTrackerCustomizer<S, T>	customizer;
78 	/**
79 	 * Filter string for use when adding the ServiceListener. If this field is
80 	 * set, then certain optimizations can be taken since we don't have a user
81 	 * supplied filter.
82 	 */
83 	final String							listenerFilter;
84 	/**
85 	 * Class name to be tracked. If this field is set, then we are tracking by
86 	 * class name.
87 	 */
88 	private final String					trackClass;
89 	/**
90 	 * Reference to be tracked. If this field is set, then we are tracking a
91 	 * single ServiceReference.
92 	 */
93 	private final ServiceReference<S>		trackReference;
94 	/**
95 	 * Tracked services: {@code ServiceReference} -> customized Object and
96 	 * {@code ServiceListener} object
97 	 */
98 	private volatile Tracked				tracked;
99 
100 	/**
101 	 * Accessor method for the current Tracked object. This method is only
102 	 * intended to be used by the unsynchronized methods which do not modify the
103 	 * tracked field.
104 	 *
105 	 * @return The current Tracked object.
106 	 */
tracked()107 	private Tracked tracked() {
108 		return tracked;
109 	}
110 
111 	/**
112 	 * Cached ServiceReference for getServiceReference.
113 	 *
114 	 * This field is volatile since it is accessed by multiple threads.
115 	 */
116 	private volatile ServiceReference<S>	cachedReference;
117 	/**
118 	 * Cached service object for getService.
119 	 *
120 	 * This field is volatile since it is accessed by multiple threads.
121 	 */
122 	private volatile T						cachedService;
123 
124 	/**
125 	 * Create a {@code ServiceTracker} on the specified {@code ServiceReference}
126 	 * .
127 	 *
128 	 * <p>
129 	 * The service referenced by the specified {@code ServiceReference} will be
130 	 * tracked by this {@code ServiceTracker}.
131 	 *
132 	 * @param context The {@code BundleContext} against which the tracking is
133 	 *        done.
134 	 * @param reference The {@code ServiceReference} for the service to be
135 	 *        tracked.
136 	 * @param customizer The customizer object to call when services are added,
137 	 *        modified, or removed in this {@code ServiceTracker}. If customizer
138 	 *        is {@code null}, then this {@code ServiceTracker} will be used as
139 	 *        the {@code ServiceTrackerCustomizer} and this
140 	 *        {@code ServiceTracker} will call the
141 	 *        {@code ServiceTrackerCustomizer} methods on itself.
142 	 */
ServiceTracker(final BundleContext context, final ServiceReference<S> reference, final ServiceTrackerCustomizer<S, T> customizer)143 	public ServiceTracker(final BundleContext context, final ServiceReference<S> reference, final ServiceTrackerCustomizer<S, T> customizer) {
144 		this.context = context;
145 		this.trackReference = reference;
146 		this.trackClass = null;
147 		this.customizer = (customizer == null) ? this : customizer;
148 		this.listenerFilter = "(" + Constants.SERVICE_ID + "=" + reference.getProperty(Constants.SERVICE_ID).toString() + ")";
149 		try {
150 			this.filter = context.createFilter(listenerFilter);
151 		} catch (InvalidSyntaxException e) {
152 			/*
153 			 * we could only get this exception if the ServiceReference was
154 			 * invalid
155 			 */
156 			IllegalArgumentException iae = new IllegalArgumentException("unexpected InvalidSyntaxException: " + e.getMessage());
157 			iae.initCause(e);
158 			throw iae;
159 		}
160 	}
161 
162 	/**
163 	 * Create a {@code ServiceTracker} on the specified class name.
164 	 *
165 	 * <p>
166 	 * Services registered under the specified class name will be tracked by
167 	 * this {@code ServiceTracker}.
168 	 *
169 	 * @param context The {@code BundleContext} against which the tracking is
170 	 *        done.
171 	 * @param clazz The class name of the services to be tracked.
172 	 * @param customizer The customizer object to call when services are added,
173 	 *        modified, or removed in this {@code ServiceTracker}. If customizer
174 	 *        is {@code null}, then this {@code ServiceTracker} will be used as
175 	 *        the {@code ServiceTrackerCustomizer} and this
176 	 *        {@code ServiceTracker} will call the
177 	 *        {@code ServiceTrackerCustomizer} methods on itself.
178 	 */
ServiceTracker(final BundleContext context, final String clazz, final ServiceTrackerCustomizer<S, T> customizer)179 	public ServiceTracker(final BundleContext context, final String clazz, final ServiceTrackerCustomizer<S, T> customizer) {
180 		this.context = context;
181 		this.trackReference = null;
182 		this.trackClass = clazz;
183 		this.customizer = (customizer == null) ? this : customizer;
184 		// we call clazz.toString to verify clazz is non-null!
185 		this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz.toString() + ")";
186 		try {
187 			this.filter = context.createFilter(listenerFilter);
188 		} catch (InvalidSyntaxException e) {
189 			/*
190 			 * we could only get this exception if the clazz argument was
191 			 * malformed
192 			 */
193 			IllegalArgumentException iae = new IllegalArgumentException("unexpected InvalidSyntaxException: " + e.getMessage());
194 			iae.initCause(e);
195 			throw iae;
196 		}
197 	}
198 
199 	/**
200 	 * Create a {@code ServiceTracker} on the specified {@code Filter} object.
201 	 *
202 	 * <p>
203 	 * Services which match the specified {@code Filter} object will be tracked
204 	 * by this {@code ServiceTracker}.
205 	 *
206 	 * @param context The {@code BundleContext} against which the tracking is
207 	 *        done.
208 	 * @param filter The {@code Filter} to select the services to be tracked.
209 	 * @param customizer The customizer object to call when services are added,
210 	 *        modified, or removed in this {@code ServiceTracker}. If customizer
211 	 *        is null, then this {@code ServiceTracker} will be used as the
212 	 *        {@code ServiceTrackerCustomizer} and this {@code ServiceTracker}
213 	 *        will call the {@code ServiceTrackerCustomizer} methods on itself.
214 	 * @since 1.1
215 	 */
ServiceTracker(final BundleContext context, final Filter filter, final ServiceTrackerCustomizer<S, T> customizer)216 	public ServiceTracker(final BundleContext context, final Filter filter, final ServiceTrackerCustomizer<S, T> customizer) {
217 		this.context = context;
218 		this.trackReference = null;
219 		this.trackClass = null;
220 		this.listenerFilter = filter.toString();
221 		this.filter = filter;
222 		this.customizer = (customizer == null) ? this : customizer;
223 		if ((context == null) || (filter == null)) {
224 			/*
225 			 * we throw a NPE here to be consistent with the other constructors
226 			 */
227 			throw new NullPointerException();
228 		}
229 	}
230 
231 	/**
232 	 * Create a {@code ServiceTracker} on the specified class.
233 	 *
234 	 * <p>
235 	 * Services registered under the name of the specified class will be tracked
236 	 * by this {@code ServiceTracker}.
237 	 *
238 	 * @param context The {@code BundleContext} against which the tracking is
239 	 *        done.
240 	 * @param clazz The class of the services to be tracked.
241 	 * @param customizer The customizer object to call when services are added,
242 	 *        modified, or removed in this {@code ServiceTracker}. If customizer
243 	 *        is {@code null}, then this {@code ServiceTracker} will be used as
244 	 *        the {@code ServiceTrackerCustomizer} and this
245 	 *        {@code ServiceTracker} will call the
246 	 *        {@code ServiceTrackerCustomizer} methods on itself.
247 	 * @since 1.5
248 	 */
ServiceTracker(final BundleContext context, final Class<S> clazz, final ServiceTrackerCustomizer<S, T> customizer)249 	public ServiceTracker(final BundleContext context, final Class<S> clazz, final ServiceTrackerCustomizer<S, T> customizer) {
250 		this(context, clazz.getName(), customizer);
251 	}
252 
253 	/**
254 	 * Open this {@code ServiceTracker} and begin tracking services.
255 	 *
256 	 * <p>
257 	 * This implementation calls {@code open(false)}.
258 	 *
259 	 * @throws java.lang.IllegalStateException If the {@code BundleContext} with
260 	 *         which this {@code ServiceTracker} was created is no longer valid.
261 	 * @see #open(boolean)
262 	 */
open()263 	public void open() {
264 		open(false);
265 	}
266 
267 	/**
268 	 * Open this {@code ServiceTracker} and begin tracking services.
269 	 *
270 	 * <p>
271 	 * Services which match the search criteria specified when this
272 	 * {@code ServiceTracker} was created are now tracked by this
273 	 * {@code ServiceTracker}.
274 	 *
275 	 * @param trackAllServices If {@code true}, then this {@code ServiceTracker}
276 	 *        will track all matching services regardless of class loader
277 	 *        accessibility. If {@code false}, then this {@code ServiceTracker}
278 	 *        will only track matching services which are class loader
279 	 *        accessible to the bundle whose {@code BundleContext} is used by
280 	 *        this {@code ServiceTracker}.
281 	 * @throws java.lang.IllegalStateException If the {@code BundleContext} with
282 	 *         which this {@code ServiceTracker} was created is no longer valid.
283 	 * @since 1.3
284 	 */
open(boolean trackAllServices)285 	public void open(boolean trackAllServices) {
286 		final Tracked t;
287 		synchronized (this) {
288 			if (tracked != null) {
289 				return;
290 			}
291 			if (DEBUG) {
292 				System.out.println("ServiceTracker.open: " + filter);
293 			}
294 			t = trackAllServices ? new AllTracked() : new Tracked();
295 			synchronized (t) {
296 				try {
297 					context.addServiceListener(t, listenerFilter);
298 					ServiceReference<S>[] references = null;
299 					if (trackClass != null) {
300 						references = getInitialReferences(trackAllServices, trackClass, null);
301 					} else {
302 						if (trackReference != null) {
303 							if (trackReference.getBundle() != null) {
304 								@SuppressWarnings("unchecked")
305 								ServiceReference<S>[] single = new ServiceReference[] {trackReference};
306 								references = single;
307 							}
308 						} else { /* user supplied filter */
309 							references = getInitialReferences(trackAllServices, null, listenerFilter);
310 						}
311 					}
312 					/* set tracked with the initial references */
313 					t.setInitial(references);
314 				} catch (InvalidSyntaxException e) {
315 					throw new RuntimeException("unexpected InvalidSyntaxException: " + e.getMessage(), e);
316 				}
317 			}
318 			tracked = t;
319 		}
320 		/* Call tracked outside of synchronized region */
321 		t.trackInitial(); /* process the initial references */
322 	}
323 
324 	/**
325 	 * Returns the list of initial {@code ServiceReference}s that will be
326 	 * tracked by this {@code ServiceTracker}.
327 	 *
328 	 * @param trackAllServices If {@code true}, use
329 	 *        {@code getAllServiceReferences}.
330 	 * @param className The class name with which the service was registered, or
331 	 *        {@code null} for all services.
332 	 * @param filterString The filter criteria or {@code null} for all services.
333 	 * @return The list of initial {@code ServiceReference}s.
334 	 * @throws InvalidSyntaxException If the specified filterString has an
335 	 *         invalid syntax.
336 	 */
getInitialReferences(boolean trackAllServices, String className, String filterString)337 	private ServiceReference<S>[] getInitialReferences(boolean trackAllServices, String className, String filterString) throws InvalidSyntaxException {
338 		@SuppressWarnings("unchecked")
339 		ServiceReference<S>[] result = (ServiceReference<S>[]) ((trackAllServices) ? context.getAllServiceReferences(className, filterString) : context.getServiceReferences(className, filterString));
340 		return result;
341 	}
342 
343 	/**
344 	 * Close this {@code ServiceTracker}.
345 	 *
346 	 * <p>
347 	 * This method should be called when this {@code ServiceTracker} should end
348 	 * the tracking of services.
349 	 *
350 	 * <p>
351 	 * This implementation calls {@link #getServiceReferences()} to get the list
352 	 * of tracked services to remove.
353 	 */
close()354 	public void close() {
355 		final Tracked outgoing;
356 		final ServiceReference<S>[] references;
357 		synchronized (this) {
358 			outgoing = tracked;
359 			if (outgoing == null) {
360 				return;
361 			}
362 			if (DEBUG) {
363 				System.out.println("ServiceTracker.close: " + filter);
364 			}
365 			outgoing.close();
366 			references = getServiceReferences();
367 			tracked = null;
368 			try {
369 				context.removeServiceListener(outgoing);
370 			} catch (IllegalStateException e) {
371 				/* In case the context was stopped. */
372 			}
373 		}
374 		modified(); /* clear the cache */
375 		synchronized (outgoing) {
376 			outgoing.notifyAll(); /* wake up any waiters */
377 		}
378 		if (references != null) {
379 			for (int i = 0; i < references.length; i++) {
380 				outgoing.untrack(references[i], null);
381 			}
382 		}
383 		if (DEBUG) {
384 			if ((cachedReference == null) && (cachedService == null)) {
385 				System.out.println("ServiceTracker.close[cached cleared]: " + filter);
386 			}
387 		}
388 	}
389 
390 	/**
391 	 * Default implementation of the
392 	 * {@code ServiceTrackerCustomizer.addingService} method.
393 	 * <p>
394 	 * This method is only called when this {@code ServiceTracker} has been
395 	 * constructed with a {@code null ServiceTrackerCustomizer} argument.
396 	 * <p>
397 	 * This implementation returns the result of calling {@code getService}, on
398 	 * the {@code BundleContext} with which this {@code ServiceTracker} was
399 	 * created, passing the specified {@code ServiceReference}.
400 	 * <p>
401 	 * This method can be overridden in a subclass to customize the service
402 	 * object to be tracked for the service being added. In that case, take care
403 	 * not to rely on the default implementation of
404 	 * {@link #removedService(ServiceReference, Object) removedService} to unget
405 	 * the service.
406 	 *
407 	 * @param reference The reference to the service being added to this
408 	 *            {@code ServiceTracker}.
409 	 * @return The service object to be tracked for the service added to this
410 	 *         {@code ServiceTracker}.
411 	 * @see ServiceTrackerCustomizer#addingService(ServiceReference)
412 	 */
413 	@Override
addingService(ServiceReference<S> reference)414 	public T addingService(ServiceReference<S> reference) {
415 		@SuppressWarnings("unchecked")
416 		T result = (T) context.getService(reference);
417 		return result;
418 	}
419 
420 	/**
421 	 * Default implementation of the
422 	 * {@code ServiceTrackerCustomizer.modifiedService} method.
423 	 *
424 	 * <p>
425 	 * This method is only called when this {@code ServiceTracker} has been
426 	 * constructed with a {@code null ServiceTrackerCustomizer} argument.
427 	 *
428 	 * <p>
429 	 * This implementation does nothing.
430 	 *
431 	 * @param reference The reference to modified service.
432 	 * @param service The service object for the modified service.
433 	 * @see ServiceTrackerCustomizer#modifiedService(ServiceReference, Object)
434 	 */
435 	@Override
modifiedService(ServiceReference<S> reference, T service)436 	public void modifiedService(ServiceReference<S> reference, T service) {
437 		/* do nothing */
438 	}
439 
440 	/**
441 	 * Default implementation of the
442 	 * {@code ServiceTrackerCustomizer.removedService} method.
443 	 * <p>
444 	 * This method is only called when this {@code ServiceTracker} has been
445 	 * constructed with a {@code null ServiceTrackerCustomizer} argument.
446 	 * <p>
447 	 * This implementation calls {@code ungetService}, on the
448 	 * {@code BundleContext} with which this {@code ServiceTracker} was created,
449 	 * passing the specified {@code ServiceReference}.
450 	 * <p>
451 	 * This method can be overridden in a subclass. If the default
452 	 * implementation of {@link #addingService(ServiceReference) addingService}
453 	 * method was used, this method must unget the service.
454 	 *
455 	 * @param reference The reference to removed service.
456 	 * @param service The service object for the removed service.
457 	 * @see ServiceTrackerCustomizer#removedService(ServiceReference, Object)
458 	 */
459 	@Override
removedService(ServiceReference<S> reference, T service)460 	public void removedService(ServiceReference<S> reference, T service) {
461 		context.ungetService(reference);
462 	}
463 
464 	/**
465 	 * Wait for at least one service to be tracked by this
466 	 * {@code ServiceTracker}. This method will also return when this
467 	 * {@code ServiceTracker} is closed.
468 	 *
469 	 * <p>
470 	 * It is strongly recommended that {@code waitForService} is not used during
471 	 * the calling of the {@code BundleActivator} methods.
472 	 * {@code BundleActivator} methods are expected to complete in a short
473 	 * period of time.
474 	 *
475 	 * <p>
476 	 * This implementation calls {@link #getService()} to determine if a service
477 	 * is being tracked.
478 	 *
479 	 * @param timeout The time interval in milliseconds to wait. If zero, the
480 	 *        method will wait indefinitely.
481 	 * @return Returns the result of {@link #getService()}.
482 	 * @throws InterruptedException If another thread has interrupted the
483 	 *         current thread.
484 	 * @throws IllegalArgumentException If the value of timeout is negative.
485 	 */
waitForService(long timeout)486 	public T waitForService(long timeout) throws InterruptedException {
487 		if (timeout < 0) {
488 			throw new IllegalArgumentException("timeout value is negative");
489 		}
490 
491 		T object = getService();
492 		if (object != null) {
493 			return object;
494 		}
495 
496 		final long endTime = (timeout == 0) ? 0 : (System.currentTimeMillis() + timeout);
497 		do {
498 			final Tracked t = tracked();
499 			if (t == null) { /* if ServiceTracker is not open */
500 				return null;
501 			}
502 			synchronized (t) {
503 				if (t.size() == 0) {
504 					t.wait(timeout);
505 				}
506 			}
507 			object = getService();
508 			if (endTime > 0) { // if we have a timeout
509 				timeout = endTime - System.currentTimeMillis();
510 				if (timeout <= 0) { // that has expired
511 					break;
512 				}
513 			}
514 		} while (object == null);
515 		return object;
516 	}
517 
518 	/**
519 	 * Return an array of {@code ServiceReference}s for all services being
520 	 * tracked by this {@code ServiceTracker}.
521 	 *
522 	 * @return Array of {@code ServiceReference}s or {@code null} if no services
523 	 *         are being tracked.
524 	 */
getServiceReferences()525 	public ServiceReference<S>[] getServiceReferences() {
526 		final Tracked t = tracked();
527 		if (t == null) { /* if ServiceTracker is not open */
528 			return null;
529 		}
530 		synchronized (t) {
531 			if (t.isEmpty()) {
532 				return null;
533 			}
534 			@SuppressWarnings("unchecked")
535 			ServiceReference<S>[] result = new ServiceReference[0];
536 			return t.copyKeys(result);
537 		}
538 	}
539 
540 	/**
541 	 * Returns a {@code ServiceReference} for one of the services being tracked
542 	 * by this {@code ServiceTracker}.
543 	 *
544 	 * <p>
545 	 * If multiple services are being tracked, the service with the highest
546 	 * ranking (as specified in its {@code service.ranking} property) is
547 	 * returned. If there is a tie in ranking, the service with the lowest
548 	 * service id (as specified in its {@code service.id} property); that is,
549 	 * the service that was registered first is returned. This is the same
550 	 * algorithm used by {@code BundleContext.getServiceReference}.
551 	 *
552 	 * <p>
553 	 * This implementation calls {@link #getServiceReferences()} to get the list
554 	 * of references for the tracked services.
555 	 *
556 	 * @return A {@code ServiceReference} or {@code null} if no services are
557 	 *         being tracked.
558 	 * @since 1.1
559 	 */
getServiceReference()560 	public ServiceReference<S> getServiceReference() {
561 		ServiceReference<S> reference = cachedReference;
562 		if (reference != null) {
563 			if (DEBUG) {
564 				System.out.println("ServiceTracker.getServiceReference[cached]: " + filter);
565 			}
566 			return reference;
567 		}
568 		if (DEBUG) {
569 			System.out.println("ServiceTracker.getServiceReference: " + filter);
570 		}
571 		ServiceReference<S>[] references = getServiceReferences();
572 		int length = (references == null) ? 0 : references.length;
573 		if (length == 0) { /* if no service is being tracked */
574 			return null;
575 		}
576 		int index = 0;
577 		if (length > 1) { /* if more than one service, select highest ranking */
578 			int rankings[] = new int[length];
579 			int count = 0;
580 			int maxRanking = Integer.MIN_VALUE;
581 			for (int i = 0; i < length; i++) {
582 				Object property = references[i].getProperty(Constants.SERVICE_RANKING);
583 				int ranking = (property instanceof Integer) ? ((Integer) property).intValue() : 0;
584 				rankings[i] = ranking;
585 				if (ranking > maxRanking) {
586 					index = i;
587 					maxRanking = ranking;
588 					count = 1;
589 				} else {
590 					if (ranking == maxRanking) {
591 						count++;
592 					}
593 				}
594 			}
595 			if (count > 1) { /* if still more than one service, select lowest id */
596 				long minId = Long.MAX_VALUE;
597 				for (int i = 0; i < length; i++) {
598 					if (rankings[i] == maxRanking) {
599 						long id = ((Long) (references[i].getProperty(Constants.SERVICE_ID))).longValue();
600 						if (id < minId) {
601 							index = i;
602 							minId = id;
603 						}
604 					}
605 				}
606 			}
607 		}
608 		return cachedReference = references[index];
609 	}
610 
611 	/**
612 	 * Returns the service object for the specified {@code ServiceReference} if
613 	 * the specified referenced service is being tracked by this
614 	 * {@code ServiceTracker}.
615 	 *
616 	 * @param reference The reference to the desired service.
617 	 * @return A service object or {@code null} if the service referenced by the
618 	 *         specified {@code ServiceReference} is not being tracked.
619 	 */
getService(ServiceReference<S> reference)620 	public T getService(ServiceReference<S> reference) {
621 		final Tracked t = tracked();
622 		if (t == null) { /* if ServiceTracker is not open */
623 			return null;
624 		}
625 		synchronized (t) {
626 			return t.getCustomizedObject(reference);
627 		}
628 	}
629 
630 	/**
631 	 * Return an array of service objects for all services being tracked by this
632 	 * {@code ServiceTracker}.
633 	 *
634 	 * <p>
635 	 * This implementation calls {@link #getServiceReferences()} to get the list
636 	 * of references for the tracked services and then calls
637 	 * {@link #getService(ServiceReference)} for each reference to get the
638 	 * tracked service object.
639 	 *
640 	 * @return An array of service objects or {@code null} if no services are
641 	 *         being tracked.
642 	 */
getServices()643 	public Object[] getServices() {
644 		final Tracked t = tracked();
645 		if (t == null) { /* if ServiceTracker is not open */
646 			return null;
647 		}
648 		synchronized (t) {
649 			ServiceReference<S>[] references = getServiceReferences();
650 			int length = (references == null) ? 0 : references.length;
651 			if (length == 0) {
652 				return null;
653 			}
654 			Object[] objects = new Object[length];
655 			for (int i = 0; i < length; i++) {
656 				objects[i] = getService(references[i]);
657 			}
658 			return objects;
659 		}
660 	}
661 
662 	/**
663 	 * Returns a service object for one of the services being tracked by this
664 	 * {@code ServiceTracker}.
665 	 *
666 	 * <p>
667 	 * If any services are being tracked, this implementation returns the result
668 	 * of calling {@code getService(getServiceReference())}.
669 	 *
670 	 * @return A service object or {@code null} if no services are being
671 	 *         tracked.
672 	 */
getService()673 	public T getService() {
674 		T service = cachedService;
675 		if (service != null) {
676 			if (DEBUG) {
677 				System.out.println("ServiceTracker.getService[cached]: " + filter);
678 			}
679 			return service;
680 		}
681 		if (DEBUG) {
682 			System.out.println("ServiceTracker.getService: " + filter);
683 		}
684 		ServiceReference<S> reference = getServiceReference();
685 		if (reference == null) {
686 			return null;
687 		}
688 		return cachedService = getService(reference);
689 	}
690 
691 	/**
692 	 * Remove a service from this {@code ServiceTracker}.
693 	 *
694 	 * The specified service will be removed from this {@code ServiceTracker}.
695 	 * If the specified service was being tracked then the
696 	 * {@code ServiceTrackerCustomizer.removedService} method will be called for
697 	 * that service.
698 	 *
699 	 * @param reference The reference to the service to be removed.
700 	 */
remove(ServiceReference<S> reference)701 	public void remove(ServiceReference<S> reference) {
702 		final Tracked t = tracked();
703 		if (t == null) { /* if ServiceTracker is not open */
704 			return;
705 		}
706 		t.untrack(reference, null);
707 	}
708 
709 	/**
710 	 * Return the number of services being tracked by this
711 	 * {@code ServiceTracker}.
712 	 *
713 	 * @return The number of services being tracked.
714 	 */
size()715 	public int size() {
716 		final Tracked t = tracked();
717 		if (t == null) { /* if ServiceTracker is not open */
718 			return 0;
719 		}
720 		synchronized (t) {
721 			return t.size();
722 		}
723 	}
724 
725 	/**
726 	 * Returns the tracking count for this {@code ServiceTracker}.
727 	 *
728 	 * The tracking count is initialized to 0 when this {@code ServiceTracker}
729 	 * is opened. Every time a service is added, modified or removed from this
730 	 * {@code ServiceTracker}, the tracking count is incremented.
731 	 *
732 	 * <p>
733 	 * The tracking count can be used to determine if this
734 	 * {@code ServiceTracker} has added, modified or removed a service by
735 	 * comparing a tracking count value previously collected with the current
736 	 * tracking count value. If the value has not changed, then no service has
737 	 * been added, modified or removed from this {@code ServiceTracker} since
738 	 * the previous tracking count was collected.
739 	 *
740 	 * @since 1.2
741 	 * @return The tracking count for this {@code ServiceTracker} or -1 if this
742 	 *         {@code ServiceTracker} is not open.
743 	 */
getTrackingCount()744 	public int getTrackingCount() {
745 		final Tracked t = tracked();
746 		if (t == null) { /* if ServiceTracker is not open */
747 			return -1;
748 		}
749 		synchronized (t) {
750 			return t.getTrackingCount();
751 		}
752 	}
753 
754 	/**
755 	 * Called by the Tracked object whenever the set of tracked services is
756 	 * modified. Clears the cache.
757 	 */
758 	/*
759 	 * This method must not be synchronized since it is called by Tracked while
760 	 * Tracked is synchronized. We don't want synchronization interactions
761 	 * between the listener thread and the user thread.
762 	 */
modified()763 	void modified() {
764 		cachedReference = null; /* clear cached value */
765 		cachedService = null; /* clear cached value */
766 		if (DEBUG) {
767 			System.out.println("ServiceTracker.modified: " + filter);
768 		}
769 	}
770 
771 	/**
772 	 * Return a {@code SortedMap} of the {@code ServiceReference}s and service
773 	 * objects for all services being tracked by this {@code ServiceTracker}.
774 	 * The map is sorted in reverse natural order of {@code ServiceReference}.
775 	 * That is, the first entry is the service with the highest ranking and the
776 	 * lowest service id.
777 	 *
778 	 * @return A {@code SortedMap} with the {@code ServiceReference}s and
779 	 *         service objects for all services being tracked by this
780 	 *         {@code ServiceTracker}. If no services are being tracked, then
781 	 *         the returned map is empty.
782 	 * @since 1.5
783 	 */
getTracked()784 	public SortedMap<ServiceReference<S>, T> getTracked() {
785 		SortedMap<ServiceReference<S>, T> map = new TreeMap<ServiceReference<S>, T>(Collections.reverseOrder());
786 		final Tracked t = tracked();
787 		if (t == null) { /* if ServiceTracker is not open */
788 			return map;
789 		}
790 		synchronized (t) {
791 			return t.copyEntries(map);
792 		}
793 	}
794 
795 	/**
796 	 * Return if this {@code ServiceTracker} is empty.
797 	 *
798 	 * @return {@code true} if this {@code ServiceTracker} is not tracking any
799 	 *         services.
800 	 * @since 1.5
801 	 */
isEmpty()802 	public boolean isEmpty() {
803 		final Tracked t = tracked();
804 		if (t == null) { /* if ServiceTracker is not open */
805 			return true;
806 		}
807 		synchronized (t) {
808 			return t.isEmpty();
809 		}
810 	}
811 
812 	/**
813 	 * Return an array of service objects for all services being tracked by this
814 	 * {@code ServiceTracker}. The runtime type of the returned array is that of
815 	 * the specified array.
816 	 *
817 	 * <p>
818 	 * This implementation calls {@link #getServiceReferences()} to get the list
819 	 * of references for the tracked services and then calls
820 	 * {@link #getService(ServiceReference)} for each reference to get the
821 	 * tracked service object.
822 	 *
823 	 * @param array An array into which the tracked service objects will be
824 	 *        stored, if the array is large enough.
825 	 * @return An array of service objects being tracked. If the specified array
826 	 *         is large enough to hold the result, then the specified array is
827 	 *         returned. If the specified array is longer then necessary to hold
828 	 *         the result, the array element after the last service object is
829 	 *         set to {@code null}. If the specified array is not large enough
830 	 *         to hold the result, a new array is created and returned.
831 	 * @since 1.5
832 	 */
getServices(T[] array)833 	public T[] getServices(T[] array) {
834 		final Tracked t = tracked();
835 		if (t == null) { /* if ServiceTracker is not open */
836 			if (array.length > 0) {
837 				array[0] = null;
838 			}
839 			return array;
840 		}
841 		synchronized (t) {
842 			ServiceReference<S>[] references = getServiceReferences();
843 			int length = (references == null) ? 0 : references.length;
844 			if (length == 0) {
845 				if (array.length > 0) {
846 					array[0] = null;
847 				}
848 				return array;
849 			}
850 			if (length > array.length) {
851 				@SuppressWarnings("unchecked")
852 				T[] newInstance = (T[]) Array.newInstance(array.getClass().getComponentType(), length);
853 				array = newInstance;
854 			}
855 			for (int i = 0; i < length; i++) {
856 				array[i] = getService(references[i]);
857 			}
858 			if (array.length > length) {
859 				array[length] = null;
860 			}
861 			return array;
862 		}
863 	}
864 
865 	/**
866 	 * Inner class which subclasses AbstractTracked. This class is the
867 	 * {@code ServiceListener} object for the tracker.
868 	 *
869 	 * @ThreadSafe
870 	 */
871 	private class Tracked extends AbstractTracked<ServiceReference<S>, T, ServiceEvent> implements ServiceListener {
872 		/**
873 		 * Tracked constructor.
874 		 */
Tracked()875 		Tracked() {
876 			super();
877 		}
878 
879 		/**
880 		 * {@code ServiceListener} method for the {@code ServiceTracker} class.
881 		 * This method must NOT be synchronized to avoid deadlock potential.
882 		 *
883 		 * @param event {@code ServiceEvent} object from the framework.
884 		 */
885 		@Override
serviceChanged(final ServiceEvent event)886 		final public void serviceChanged(final ServiceEvent event) {
887 			/*
888 			 * Check if we had a delayed call (which could happen when we
889 			 * close).
890 			 */
891 			if (closed) {
892 				return;
893 			}
894 			@SuppressWarnings("unchecked")
895 			final ServiceReference<S> reference = (ServiceReference<S>) event.getServiceReference();
896 			if (DEBUG) {
897 				System.out.println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: " + reference);
898 			}
899 
900 			switch (event.getType()) {
901 				case ServiceEvent.REGISTERED :
902 				case ServiceEvent.MODIFIED :
903 					track(reference, event);
904 					/*
905 					 * If the customizer throws an unchecked exception, it is
906 					 * safe to let it propagate
907 					 */
908 					break;
909 				case ServiceEvent.MODIFIED_ENDMATCH :
910 				case ServiceEvent.UNREGISTERING :
911 					untrack(reference, event);
912 					/*
913 					 * If the customizer throws an unchecked exception, it is
914 					 * safe to let it propagate
915 					 */
916 					break;
917 			}
918 		}
919 
920 		/**
921 		 * Increment the tracking count and tell the tracker there was a
922 		 * modification.
923 		 *
924 		 * @GuardedBy this
925 		 */
926 		@Override
modified()927 		final void modified() {
928 			super.modified(); /* increment the modification count */
929 			ServiceTracker.this.modified();
930 		}
931 
932 		/**
933 		 * Call the specific customizer adding method. This method must not be
934 		 * called while synchronized on this object.
935 		 *
936 		 * @param item Item to be tracked.
937 		 * @param related Action related object.
938 		 * @return Customized object for the tracked item or {@code null} if the
939 		 *         item is not to be tracked.
940 		 */
941 		@Override
customizerAdding(final ServiceReference<S> item, final ServiceEvent related)942 		final T customizerAdding(final ServiceReference<S> item, final ServiceEvent related) {
943 			return customizer.addingService(item);
944 		}
945 
946 		/**
947 		 * Call the specific customizer modified method. This method must not be
948 		 * called while synchronized on this object.
949 		 *
950 		 * @param item Tracked item.
951 		 * @param related Action related object.
952 		 * @param object Customized object for the tracked item.
953 		 */
954 		@Override
customizerModified(final ServiceReference<S> item, final ServiceEvent related, final T object)955 		final void customizerModified(final ServiceReference<S> item, final ServiceEvent related, final T object) {
956 			customizer.modifiedService(item, object);
957 		}
958 
959 		/**
960 		 * Call the specific customizer removed method. This method must not be
961 		 * called while synchronized on this object.
962 		 *
963 		 * @param item Tracked item.
964 		 * @param related Action related object.
965 		 * @param object Customized object for the tracked item.
966 		 */
967 		@Override
customizerRemoved(final ServiceReference<S> item, final ServiceEvent related, final T object)968 		final void customizerRemoved(final ServiceReference<S> item, final ServiceEvent related, final T object) {
969 			customizer.removedService(item, object);
970 		}
971 	}
972 
973 	/**
974 	 * Subclass of Tracked which implements the AllServiceListener interface.
975 	 * This class is used by the ServiceTracker if open is called with true.
976 	 *
977 	 * @since 1.3
978 	 * @ThreadSafe
979 	 */
980 	private class AllTracked extends Tracked implements AllServiceListener {
981 		/**
982 		 * AllTracked constructor.
983 		 */
AllTracked()984 		AllTracked() {
985 			super();
986 		}
987 	}
988 }
989