blob: 3ba97ab0e450b06923092daa0972051d5cf988e0 [file] [log] [blame]
Richard S. Hall2532cf82010-03-24 09:51:11 +00001/*
Carsten Ziegeler3314f912014-07-30 07:22:32 +00002 * Copyright (c) OSGi Alliance (2000, 2014). All Rights Reserved.
Richard S. Halldfd78a42012-05-11 20:19:02 +00003 *
Richard S. Hall2532cf82010-03-24 09:51:11 +00004 * 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 +000023import org.osgi.framework.AllServiceListener;
24import org.osgi.framework.BundleContext;
25import org.osgi.framework.Constants;
26import org.osgi.framework.Filter;
27import org.osgi.framework.InvalidSyntaxException;
28import org.osgi.framework.ServiceEvent;
29import org.osgi.framework.ServiceListener;
30import org.osgi.framework.ServiceReference;
Richard S. Hall2532cf82010-03-24 09:51:11 +000031
32/**
Richard S. Halld0dca9b2011-05-18 14:52:16 +000033 * The {@code ServiceTracker} class simplifies using services from the
Richard S. Hall2532cf82010-03-24 09:51:11 +000034 * Framework's service registry.
35 * <p>
Richard S. Halldfd78a42012-05-11 20:19:02 +000036 * A {@code ServiceTracker} object is constructed with search criteria and a
37 * {@code ServiceTrackerCustomizer} object. A {@code ServiceTracker} can use a
38 * {@code ServiceTrackerCustomizer} to customize the service objects to be
39 * tracked. The {@code ServiceTracker} can then be opened to begin tracking all
40 * services in the Framework's service registry that match the specified search
41 * criteria. The {@code ServiceTracker} correctly handles all of the details of
42 * listening to {@code ServiceEvent}s and getting and ungetting services.
Richard S. Hall2532cf82010-03-24 09:51:11 +000043 * <p>
Richard S. Halldfd78a42012-05-11 20:19:02 +000044 * The {@code getServiceReferences} method can be called to get references to
45 * the services being tracked. The {@code getService} and {@code getServices}
46 * methods can be called to get the service objects for the tracked service.
Richard S. Hall2532cf82010-03-24 09:51:11 +000047 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +000048 * The {@code ServiceTracker} class is thread-safe. It does not call a
49 * {@code ServiceTrackerCustomizer} while holding any locks.
Richard S. Halldfd78a42012-05-11 20:19:02 +000050 * {@code ServiceTrackerCustomizer} implementations must also be thread-safe.
Richard S. Hall2532cf82010-03-24 09:51:11 +000051 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +000052 * @param <S> The type of the service being tracked.
53 * @param <T> The type of the tracked object.
Richard S. Hall2532cf82010-03-24 09:51:11 +000054 * @ThreadSafe
Carsten Ziegeler3314f912014-07-30 07:22:32 +000055 * @author $Id: a0af979aa9c88a89f220c1b2d8d7c060ced41006 $
Richard S. Hall2532cf82010-03-24 09:51:11 +000056 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000057public class ServiceTracker<S, T> implements ServiceTrackerCustomizer<S, T> {
Richard S. Hall2532cf82010-03-24 09:51:11 +000058 /* set this to true to compile in debug messages */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000059 static final boolean DEBUG = false;
Richard S. Hall2532cf82010-03-24 09:51:11 +000060 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +000061 * The Bundle Context used by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +000062 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000063 protected final BundleContext context;
Richard S. Hall2532cf82010-03-24 09:51:11 +000064 /**
Richard S. Halldfd78a42012-05-11 20:19:02 +000065 * The Filter used by this {@code ServiceTracker} which specifies the search
66 * criteria for the services to track.
Richard S. Hall2532cf82010-03-24 09:51:11 +000067 *
68 * @since 1.1
69 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000070 protected final Filter filter;
Richard S. Hall2532cf82010-03-24 09:51:11 +000071 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +000072 * The {@code ServiceTrackerCustomizer} for this tracker.
Richard S. Hall2532cf82010-03-24 09:51:11 +000073 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000074 final ServiceTrackerCustomizer<S, T> customizer;
Richard S. Hall2532cf82010-03-24 09:51:11 +000075 /**
76 * Filter string for use when adding the ServiceListener. If this field is
77 * set, then certain optimizations can be taken since we don't have a user
78 * supplied filter.
79 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000080 final String listenerFilter;
Richard S. Hall2532cf82010-03-24 09:51:11 +000081 /**
82 * Class name to be tracked. If this field is set, then we are tracking by
83 * class name.
84 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000085 private final String trackClass;
Richard S. Hall2532cf82010-03-24 09:51:11 +000086 /**
87 * Reference to be tracked. If this field is set, then we are tracking a
88 * single ServiceReference.
89 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000090 private final ServiceReference<S> trackReference;
Richard S. Hall2532cf82010-03-24 09:51:11 +000091 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +000092 * Tracked services: {@code ServiceReference} -> customized Object and
93 * {@code ServiceListener} object
Richard S. Hall2532cf82010-03-24 09:51:11 +000094 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +000095 private volatile Tracked tracked;
Richard S. Hall2532cf82010-03-24 09:51:11 +000096
97 /**
98 * Accessor method for the current Tracked object. This method is only
99 * intended to be used by the unsynchronized methods which do not modify the
100 * tracked field.
101 *
102 * @return The current Tracked object.
103 */
104 private Tracked tracked() {
105 return tracked;
106 }
107
108 /**
109 * Cached ServiceReference for getServiceReference.
110 *
111 * This field is volatile since it is accessed by multiple threads.
112 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000113 private volatile ServiceReference<S> cachedReference;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000114 /**
115 * Cached service object for getService.
116 *
117 * This field is volatile since it is accessed by multiple threads.
118 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000119 private volatile T cachedService;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000120
121 /**
Richard S. Halldfd78a42012-05-11 20:19:02 +0000122 * Create a {@code ServiceTracker} on the specified {@code ServiceReference}
123 * .
Richard S. Hall2532cf82010-03-24 09:51:11 +0000124 *
125 * <p>
Richard S. Halldfd78a42012-05-11 20:19:02 +0000126 * The service referenced by the specified {@code ServiceReference} will be
127 * tracked by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000128 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000129 * @param context The {@code BundleContext} against which the tracking is
130 * done.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000131 * @param reference The {@code ServiceReference} for the service to be
Richard S. Hall2532cf82010-03-24 09:51:11 +0000132 * tracked.
133 * @param customizer The customizer object to call when services are added,
Richard S. Halldfd78a42012-05-11 20:19:02 +0000134 * modified, or removed in this {@code ServiceTracker}. If customizer
135 * is {@code null}, then this {@code ServiceTracker} will be used as
136 * the {@code ServiceTrackerCustomizer} and this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000137 * {@code ServiceTracker} will call the
138 * {@code ServiceTrackerCustomizer} methods on itself.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000139 */
Richard S. Halldfd78a42012-05-11 20:19:02 +0000140 public ServiceTracker(final BundleContext context, final ServiceReference<S> reference, final ServiceTrackerCustomizer<S, T> customizer) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000141 this.context = context;
142 this.trackReference = reference;
143 this.trackClass = null;
144 this.customizer = (customizer == null) ? this : customizer;
Richard S. Halldfd78a42012-05-11 20:19:02 +0000145 this.listenerFilter = "(" + Constants.SERVICE_ID + "=" + reference.getProperty(Constants.SERVICE_ID).toString() + ")";
Richard S. Hall2532cf82010-03-24 09:51:11 +0000146 try {
147 this.filter = context.createFilter(listenerFilter);
Richard S. Halldfd78a42012-05-11 20:19:02 +0000148 } catch (InvalidSyntaxException e) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000149 /*
150 * we could only get this exception if the ServiceReference was
151 * invalid
152 */
Richard S. Halldfd78a42012-05-11 20:19:02 +0000153 IllegalArgumentException iae = new IllegalArgumentException("unexpected InvalidSyntaxException: " + e.getMessage());
Richard S. Hall2532cf82010-03-24 09:51:11 +0000154 iae.initCause(e);
155 throw iae;
156 }
157 }
158
159 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000160 * Create a {@code ServiceTracker} on the specified class name.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000161 *
162 * <p>
163 * Services registered under the specified class name will be tracked by
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000164 * this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000165 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000166 * @param context The {@code BundleContext} against which the tracking is
167 * done.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000168 * @param clazz The class name of the services to be tracked.
169 * @param customizer The customizer object to call when services are added,
Richard S. Halldfd78a42012-05-11 20:19:02 +0000170 * modified, or removed in this {@code ServiceTracker}. If customizer
171 * is {@code null}, then this {@code ServiceTracker} will be used as
172 * the {@code ServiceTrackerCustomizer} and this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000173 * {@code ServiceTracker} will call the
174 * {@code ServiceTrackerCustomizer} methods on itself.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000175 */
Richard S. Halldfd78a42012-05-11 20:19:02 +0000176 public ServiceTracker(final BundleContext context, final String clazz, final ServiceTrackerCustomizer<S, T> customizer) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000177 this.context = context;
178 this.trackReference = null;
179 this.trackClass = clazz;
180 this.customizer = (customizer == null) ? this : customizer;
181 // we call clazz.toString to verify clazz is non-null!
Richard S. Halldfd78a42012-05-11 20:19:02 +0000182 this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz.toString() + ")";
Richard S. Hall2532cf82010-03-24 09:51:11 +0000183 try {
184 this.filter = context.createFilter(listenerFilter);
Richard S. Halldfd78a42012-05-11 20:19:02 +0000185 } catch (InvalidSyntaxException e) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000186 /*
187 * we could only get this exception if the clazz argument was
188 * malformed
189 */
Richard S. Halldfd78a42012-05-11 20:19:02 +0000190 IllegalArgumentException iae = new IllegalArgumentException("unexpected InvalidSyntaxException: " + e.getMessage());
Richard S. Hall2532cf82010-03-24 09:51:11 +0000191 iae.initCause(e);
192 throw iae;
193 }
194 }
195
196 /**
Richard S. Halldfd78a42012-05-11 20:19:02 +0000197 * Create a {@code ServiceTracker} on the specified {@code Filter} object.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000198 *
199 * <p>
Richard S. Halldfd78a42012-05-11 20:19:02 +0000200 * Services which match the specified {@code Filter} object will be tracked
201 * by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000202 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000203 * @param context The {@code BundleContext} against which the tracking is
204 * done.
205 * @param filter The {@code Filter} to select the services to be tracked.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000206 * @param customizer The customizer object to call when services are added,
Richard S. Halldfd78a42012-05-11 20:19:02 +0000207 * modified, or removed in this {@code ServiceTracker}. If customizer
208 * is null, then this {@code ServiceTracker} will be used as the
209 * {@code ServiceTrackerCustomizer} and this {@code ServiceTracker}
210 * will call the {@code ServiceTrackerCustomizer} methods on itself.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000211 * @since 1.1
212 */
Richard S. Halldfd78a42012-05-11 20:19:02 +0000213 public ServiceTracker(final BundleContext context, final Filter filter, final ServiceTrackerCustomizer<S, T> customizer) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000214 this.context = context;
215 this.trackReference = null;
216 this.trackClass = null;
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000217 this.listenerFilter = filter.toString();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000218 this.filter = filter;
219 this.customizer = (customizer == null) ? this : customizer;
220 if ((context == null) || (filter == null)) {
221 /*
222 * we throw a NPE here to be consistent with the other constructors
223 */
224 throw new NullPointerException();
225 }
226 }
227
228 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000229 * Create a {@code ServiceTracker} on the specified class.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000230 *
231 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000232 * Services registered under the name of the specified class will be tracked
233 * by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000234 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000235 * @param context The {@code BundleContext} against which the tracking is
236 * done.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000237 * @param clazz The class of the services to be tracked.
238 * @param customizer The customizer object to call when services are added,
Richard S. Halldfd78a42012-05-11 20:19:02 +0000239 * modified, or removed in this {@code ServiceTracker}. If customizer
240 * is {@code null}, then this {@code ServiceTracker} will be used as
241 * the {@code ServiceTrackerCustomizer} and this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000242 * {@code ServiceTracker} will call the
243 * {@code ServiceTrackerCustomizer} methods on itself.
244 * @since 1.5
245 */
Richard S. Halldfd78a42012-05-11 20:19:02 +0000246 public ServiceTracker(final BundleContext context, final Class<S> clazz, final ServiceTrackerCustomizer<S, T> customizer) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000247 this(context, clazz.getName(), customizer);
248 }
249
250 /**
251 * Open this {@code ServiceTracker} and begin tracking services.
252 *
253 * <p>
254 * This implementation calls {@code open(false)}.
255 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000256 * @throws java.lang.IllegalStateException If the {@code BundleContext} with
257 * which this {@code ServiceTracker} was created is no longer valid.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000258 * @see #open(boolean)
259 */
260 public void open() {
261 open(false);
262 }
263
264 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000265 * Open this {@code ServiceTracker} and begin tracking services.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000266 *
267 * <p>
268 * Services which match the search criteria specified when this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000269 * {@code ServiceTracker} was created are now tracked by this
270 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000271 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000272 * @param trackAllServices If {@code true}, then this {@code ServiceTracker}
273 * will track all matching services regardless of class loader
274 * accessibility. If {@code false}, then this {@code ServiceTracker}
275 * will only track matching services which are class loader
276 * accessible to the bundle whose {@code BundleContext} is used by
277 * this {@code ServiceTracker}.
278 * @throws java.lang.IllegalStateException If the {@code BundleContext} with
279 * which this {@code ServiceTracker} was created is no longer valid.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000280 * @since 1.3
281 */
282 public void open(boolean trackAllServices) {
283 final Tracked t;
284 synchronized (this) {
285 if (tracked != null) {
286 return;
287 }
288 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000289 System.out.println("ServiceTracker.open: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000290 }
291 t = trackAllServices ? new AllTracked() : new Tracked();
292 synchronized (t) {
293 try {
294 context.addServiceListener(t, listenerFilter);
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000295 ServiceReference<S>[] references = null;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000296 if (trackClass != null) {
Richard S. Halldfd78a42012-05-11 20:19:02 +0000297 references = getInitialReferences(trackAllServices, trackClass, null);
298 } else {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000299 if (trackReference != null) {
300 if (trackReference.getBundle() != null) {
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000301 @SuppressWarnings("unchecked")
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000302 ServiceReference<S>[] single = new ServiceReference[] {trackReference};
303 references = single;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000304 }
Richard S. Halldfd78a42012-05-11 20:19:02 +0000305 } else { /* user supplied filter */
306 references = getInitialReferences(trackAllServices, null, listenerFilter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000307 }
308 }
309 /* set tracked with the initial references */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000310 t.setInitial(references);
Richard S. Halldfd78a42012-05-11 20:19:02 +0000311 } catch (InvalidSyntaxException e) {
312 throw new RuntimeException("unexpected InvalidSyntaxException: " + e.getMessage(), e);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000313 }
314 }
315 tracked = t;
316 }
317 /* Call tracked outside of synchronized region */
318 t.trackInitial(); /* process the initial references */
319 }
320
321 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000322 * Returns the list of initial {@code ServiceReference}s that will be
323 * tracked by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000324 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000325 * @param trackAllServices If {@code true}, use
326 * {@code getAllServiceReferences}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000327 * @param className The class name with which the service was registered, or
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000328 * {@code null} for all services.
Richard S. Halldfd78a42012-05-11 20:19:02 +0000329 * @param filterString The filter criteria or {@code null} for all services.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000330 * @return The list of initial {@code ServiceReference}s.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000331 * @throws InvalidSyntaxException If the specified filterString has an
332 * invalid syntax.
333 */
Richard S. Halldfd78a42012-05-11 20:19:02 +0000334 private ServiceReference<S>[] getInitialReferences(boolean trackAllServices, String className, String filterString) throws InvalidSyntaxException {
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000335 @SuppressWarnings("unchecked")
Richard S. Halldfd78a42012-05-11 20:19:02 +0000336 ServiceReference<S>[] result = (ServiceReference<S>[]) ((trackAllServices) ? context.getAllServiceReferences(className, filterString) : context.getServiceReferences(className, filterString));
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000337 return result;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000338 }
339
340 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000341 * Close this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000342 *
343 * <p>
Richard S. Halldfd78a42012-05-11 20:19:02 +0000344 * This method should be called when this {@code ServiceTracker} should end
345 * the tracking of services.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000346 *
347 * <p>
348 * This implementation calls {@link #getServiceReferences()} to get the list
349 * of tracked services to remove.
350 */
351 public void close() {
352 final Tracked outgoing;
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000353 final ServiceReference<S>[] references;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000354 synchronized (this) {
355 outgoing = tracked;
356 if (outgoing == null) {
357 return;
358 }
359 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000360 System.out.println("ServiceTracker.close: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000361 }
362 outgoing.close();
363 references = getServiceReferences();
364 tracked = null;
365 try {
366 context.removeServiceListener(outgoing);
Richard S. Halldfd78a42012-05-11 20:19:02 +0000367 } catch (IllegalStateException e) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000368 /* In case the context was stopped. */
369 }
370 }
371 modified(); /* clear the cache */
372 synchronized (outgoing) {
373 outgoing.notifyAll(); /* wake up any waiters */
374 }
375 if (references != null) {
376 for (int i = 0; i < references.length; i++) {
377 outgoing.untrack(references[i], null);
378 }
379 }
380 if (DEBUG) {
381 if ((cachedReference == null) && (cachedService == null)) {
Richard S. Halldfd78a42012-05-11 20:19:02 +0000382 System.out.println("ServiceTracker.close[cached cleared]: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000383 }
384 }
385 }
386
387 /**
388 * Default implementation of the
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000389 * {@code ServiceTrackerCustomizer.addingService} method.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000390 *
391 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000392 * This method is only called when this {@code ServiceTracker} has been
393 * constructed with a {@code null ServiceTrackerCustomizer} argument.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000394 *
395 * <p>
Richard S. Halldfd78a42012-05-11 20:19:02 +0000396 * This implementation returns the result of calling {@code getService} on
397 * the {@code BundleContext} with which this {@code ServiceTracker} was
398 * created passing the specified {@code ServiceReference}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000399 * <p>
400 * This method can be overridden in a subclass to customize the service
401 * object to be tracked for the service being added. In that case, take care
402 * not to rely on the default implementation of
403 * {@link #removedService(ServiceReference, Object) removedService} to unget
404 * the service.
405 *
406 * @param reference The reference to the service being added to this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000407 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000408 * @return The service object to be tracked for the service added to this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000409 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000410 * @see ServiceTrackerCustomizer#addingService(ServiceReference)
411 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000412 public T addingService(ServiceReference<S> reference) {
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000413 @SuppressWarnings("unchecked")
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000414 T result = (T) context.getService(reference);
415 return result;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000416 }
417
418 /**
419 * Default implementation of the
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000420 * {@code ServiceTrackerCustomizer.modifiedService} method.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000421 *
422 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000423 * This method is only called when this {@code ServiceTracker} has been
424 * constructed with a {@code null ServiceTrackerCustomizer} argument.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000425 *
426 * <p>
427 * This implementation does nothing.
428 *
429 * @param reference The reference to modified service.
430 * @param service The service object for the modified service.
431 * @see ServiceTrackerCustomizer#modifiedService(ServiceReference, Object)
432 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000433 public void modifiedService(ServiceReference<S> reference, T service) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000434 /* do nothing */
435 }
436
437 /**
438 * Default implementation of the
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000439 * {@code ServiceTrackerCustomizer.removedService} method.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000440 *
441 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000442 * This method is only called when this {@code ServiceTracker} has been
443 * constructed with a {@code null ServiceTrackerCustomizer} argument.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000444 *
445 * <p>
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000446 * This implementation calls {@code ungetService}, on the
Richard S. Halldfd78a42012-05-11 20:19:02 +0000447 * {@code BundleContext} with which this {@code ServiceTracker} was created,
448 * passing the specified {@code ServiceReference}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000449 * <p>
450 * This method can be overridden in a subclass. If the default
451 * implementation of {@link #addingService(ServiceReference) addingService}
452 * method was used, this method must unget the service.
453 *
454 * @param reference The reference to removed service.
455 * @param service The service object for the removed service.
456 * @see ServiceTrackerCustomizer#removedService(ServiceReference, Object)
457 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000458 public void removedService(ServiceReference<S> reference, T service) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000459 context.ungetService(reference);
460 }
461
462 /**
463 * Wait for at least one service to be tracked by this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000464 * {@code ServiceTracker}. This method will also return when this
465 * {@code ServiceTracker} is closed.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000466 *
467 * <p>
Richard S. Halldfd78a42012-05-11 20:19:02 +0000468 * It is strongly recommended that {@code waitForService} is not used during
469 * the calling of the {@code BundleActivator} methods.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000470 * {@code BundleActivator} methods are expected to complete in a short
Richard S. Hall2532cf82010-03-24 09:51:11 +0000471 * period of time.
472 *
473 * <p>
474 * This implementation calls {@link #getService()} to determine if a service
475 * is being tracked.
476 *
477 * @param timeout The time interval in milliseconds to wait. If zero, the
478 * method will wait indefinitely.
479 * @return Returns the result of {@link #getService()}.
480 * @throws InterruptedException If another thread has interrupted the
481 * current thread.
482 * @throws IllegalArgumentException If the value of timeout is negative.
483 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000484 public T waitForService(long timeout) throws InterruptedException {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000485 if (timeout < 0) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000486 throw new IllegalArgumentException("timeout value is negative");
Richard S. Hall2532cf82010-03-24 09:51:11 +0000487 }
Richard S. Halldfd78a42012-05-11 20:19:02 +0000488
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000489 T object = getService();
Richard S. Halldfd78a42012-05-11 20:19:02 +0000490 if (object != null) {
491 return object;
492 }
493
494 final long endTime = (timeout == 0) ? 0 : (System.currentTimeMillis() + timeout);
495 do {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000496 final Tracked t = tracked();
497 if (t == null) { /* if ServiceTracker is not open */
498 return null;
499 }
500 synchronized (t) {
501 if (t.size() == 0) {
502 t.wait(timeout);
503 }
504 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000505 object = getService();
Richard S. Halldfd78a42012-05-11 20:19:02 +0000506 if (endTime > 0) { // if we have a timeout
507 timeout = endTime - System.currentTimeMillis();
508 if (timeout <= 0) { // that has expired
509 break;
510 }
Richard S. Hall2532cf82010-03-24 09:51:11 +0000511 }
Richard S. Halldfd78a42012-05-11 20:19:02 +0000512 } while (object == null);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000513 return object;
514 }
515
516 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000517 * Return an array of {@code ServiceReference}s for all services being
518 * tracked by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000519 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000520 * @return Array of {@code ServiceReference}s or {@code null} if no services
521 * are being tracked.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000522 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000523 public ServiceReference<S>[] getServiceReferences() {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000524 final Tracked t = tracked();
525 if (t == null) { /* if ServiceTracker is not open */
526 return null;
527 }
528 synchronized (t) {
529 int length = t.size();
530 if (length == 0) {
531 return null;
532 }
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000533 @SuppressWarnings("unchecked")
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000534 ServiceReference<S>[] result = new ServiceReference[length];
535 return t.copyKeys(result);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000536 }
537 }
538
539 /**
Richard S. Halldfd78a42012-05-11 20:19:02 +0000540 * Returns a {@code ServiceReference} for one of the services being tracked
541 * by this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000542 *
543 * <p>
544 * If multiple services are being tracked, the service with the highest
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000545 * ranking (as specified in its {@code service.ranking} property) is
Richard S. Hall2532cf82010-03-24 09:51:11 +0000546 * returned. If there is a tie in ranking, the service with the lowest
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000547 * service id (as specified in its {@code service.id} property); that is,
Richard S. Halldfd78a42012-05-11 20:19:02 +0000548 * the service that was registered first is returned. This is the same
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000549 * algorithm used by {@code BundleContext.getServiceReference}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000550 *
551 * <p>
552 * This implementation calls {@link #getServiceReferences()} to get the list
553 * of references for the tracked services.
554 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000555 * @return A {@code ServiceReference} or {@code null} if no services are
556 * being tracked.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000557 * @since 1.1
558 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000559 public ServiceReference<S> getServiceReference() {
560 ServiceReference<S> reference = cachedReference;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000561 if (reference != null) {
562 if (DEBUG) {
Richard S. Halldfd78a42012-05-11 20:19:02 +0000563 System.out.println("ServiceTracker.getServiceReference[cached]: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000564 }
565 return reference;
566 }
567 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000568 System.out.println("ServiceTracker.getServiceReference: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000569 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000570 ServiceReference<S>[] references = getServiceReferences();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000571 int length = (references == null) ? 0 : references.length;
572 if (length == 0) { /* if no service is being tracked */
573 return null;
574 }
575 int index = 0;
576 if (length > 1) { /* if more than one service, select highest ranking */
577 int rankings[] = new int[length];
578 int count = 0;
579 int maxRanking = Integer.MIN_VALUE;
580 for (int i = 0; i < length; i++) {
Richard S. Halldfd78a42012-05-11 20:19:02 +0000581 Object property = references[i].getProperty(Constants.SERVICE_RANKING);
582 int ranking = (property instanceof Integer) ? ((Integer) property).intValue() : 0;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000583 rankings[i] = ranking;
584 if (ranking > maxRanking) {
585 index = i;
586 maxRanking = ranking;
587 count = 1;
Richard S. Halldfd78a42012-05-11 20:19:02 +0000588 } else {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000589 if (ranking == maxRanking) {
590 count++;
591 }
592 }
593 }
594 if (count > 1) { /* if still more than one service, select lowest id */
595 long minId = Long.MAX_VALUE;
596 for (int i = 0; i < length; i++) {
597 if (rankings[i] == maxRanking) {
Richard S. Halldfd78a42012-05-11 20:19:02 +0000598 long id = ((Long) (references[i].getProperty(Constants.SERVICE_ID))).longValue();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000599 if (id < minId) {
600 index = i;
601 minId = id;
602 }
603 }
604 }
605 }
606 }
607 return cachedReference = references[index];
608 }
609
610 /**
Richard S. Halldfd78a42012-05-11 20:19:02 +0000611 * Returns the service object for the specified {@code ServiceReference} if
612 * the specified referenced service is being tracked by this
613 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000614 *
615 * @param reference The reference to the desired service.
Richard S. Halldfd78a42012-05-11 20:19:02 +0000616 * @return A service object or {@code null} if the service referenced by the
617 * specified {@code ServiceReference} is not being tracked.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000618 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000619 public T getService(ServiceReference<S> reference) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000620 final Tracked t = tracked();
621 if (t == null) { /* if ServiceTracker is not open */
622 return null;
623 }
624 synchronized (t) {
625 return t.getCustomizedObject(reference);
626 }
627 }
628
629 /**
630 * Return an array of service objects for all services being tracked by this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000631 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000632 *
633 * <p>
634 * This implementation calls {@link #getServiceReferences()} to get the list
635 * of references for the tracked services and then calls
636 * {@link #getService(ServiceReference)} for each reference to get the
637 * tracked service object.
638 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000639 * @return An array of service objects or {@code null} if no services are
640 * being tracked.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000641 */
642 public Object[] getServices() {
643 final Tracked t = tracked();
644 if (t == null) { /* if ServiceTracker is not open */
645 return null;
646 }
647 synchronized (t) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000648 ServiceReference<S>[] references = getServiceReferences();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000649 int length = (references == null) ? 0 : references.length;
650 if (length == 0) {
651 return null;
652 }
653 Object[] objects = new Object[length];
654 for (int i = 0; i < length; i++) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000655 objects[i] = getService(references[i]);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000656 }
657 return objects;
658 }
659 }
660
661 /**
662 * Returns a service object for one of the services being tracked by this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000663 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000664 *
665 * <p>
666 * If any services are being tracked, this implementation returns the result
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000667 * of calling {@code getService(getServiceReference())}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000668 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000669 * @return A service object or {@code null} if no services are being
Richard S. Hall2532cf82010-03-24 09:51:11 +0000670 * tracked.
671 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000672 public T getService() {
673 T service = cachedService;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000674 if (service != null) {
675 if (DEBUG) {
Richard S. Halldfd78a42012-05-11 20:19:02 +0000676 System.out.println("ServiceTracker.getService[cached]: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000677 }
678 return service;
679 }
680 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000681 System.out.println("ServiceTracker.getService: " + filter);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000682 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000683 ServiceReference<S> reference = getServiceReference();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000684 if (reference == null) {
685 return null;
686 }
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000687 return cachedService = getService(reference);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000688 }
689
690 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000691 * Remove a service from this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000692 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000693 * The specified service will be removed from this {@code ServiceTracker}.
694 * If the specified service was being tracked then the
695 * {@code ServiceTrackerCustomizer.removedService} method will be called for
696 * that service.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000697 *
698 * @param reference The reference to the service to be removed.
699 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000700 public void remove(ServiceReference<S> reference) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000701 final Tracked t = tracked();
702 if (t == null) { /* if ServiceTracker is not open */
703 return;
704 }
705 t.untrack(reference, null);
706 }
707
708 /**
709 * Return the number of services being tracked by this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000710 * {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000711 *
712 * @return The number of services being tracked.
713 */
714 public int size() {
715 final Tracked t = tracked();
716 if (t == null) { /* if ServiceTracker is not open */
717 return 0;
718 }
719 synchronized (t) {
720 return t.size();
721 }
722 }
723
724 /**
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000725 * Returns the tracking count for this {@code ServiceTracker}.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000726 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000727 * The tracking count is initialized to 0 when this {@code ServiceTracker}
728 * is opened. Every time a service is added, modified or removed from this
729 * {@code ServiceTracker}, the tracking count is incremented.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000730 *
731 * <p>
732 * The tracking count can be used to determine if this
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000733 * {@code ServiceTracker} has added, modified or removed a service by
Richard S. Hall2532cf82010-03-24 09:51:11 +0000734 * comparing a tracking count value previously collected with the current
735 * tracking count value. If the value has not changed, then no service has
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000736 * been added, modified or removed from this {@code ServiceTracker} since
737 * the previous tracking count was collected.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000738 *
739 * @since 1.2
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000740 * @return The tracking count for this {@code ServiceTracker} or -1 if this
741 * {@code ServiceTracker} is not open.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000742 */
743 public int getTrackingCount() {
744 final Tracked t = tracked();
745 if (t == null) { /* if ServiceTracker is not open */
746 return -1;
747 }
748 synchronized (t) {
749 return t.getTrackingCount();
750 }
751 }
752
753 /**
754 * Called by the Tracked object whenever the set of tracked services is
755 * modified. Clears the cache.
756 */
757 /*
758 * This method must not be synchronized since it is called by Tracked while
759 * Tracked is synchronized. We don't want synchronization interactions
760 * between the listener thread and the user thread.
761 */
762 void modified() {
763 cachedReference = null; /* clear cached value */
764 cachedService = null; /* clear cached value */
765 if (DEBUG) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000766 System.out.println("ServiceTracker.modified: " + filter);
767 }
768 }
769
770 /**
Richard S. Halldfd78a42012-05-11 20:19:02 +0000771 * Return a {@code SortedMap} of the {@code ServiceReference}s and service
772 * objects for all services being tracked by this {@code ServiceTracker}.
773 * The map is sorted in reverse natural order of {@code ServiceReference}.
774 * That is, the first entry is the service with the highest ranking and the
775 * lowest service id.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000776 *
Richard S. Halldfd78a42012-05-11 20:19:02 +0000777 * @return A {@code SortedMap} with the {@code ServiceReference}s and
778 * service objects for all services being tracked by this
779 * {@code ServiceTracker}. If no services are being tracked, then
780 * the returned map is empty.
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000781 * @since 1.5
782 */
783 public SortedMap<ServiceReference<S>, T> getTracked() {
Richard S. Halldfd78a42012-05-11 20:19:02 +0000784 SortedMap<ServiceReference<S>, T> map = new TreeMap<ServiceReference<S>, T>(Collections.reverseOrder());
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000785 final Tracked t = tracked();
786 if (t == null) { /* if ServiceTracker is not open */
787 return map;
788 }
789 synchronized (t) {
790 return t.copyEntries(map);
791 }
792 }
793
794 /**
795 * Return if this {@code ServiceTracker} is empty.
796 *
797 * @return {@code true} if this {@code ServiceTracker} is not tracking any
798 * services.
799 * @since 1.5
800 */
801 public boolean isEmpty() {
802 final Tracked t = tracked();
803 if (t == null) { /* if ServiceTracker is not open */
804 return true;
805 }
806 synchronized (t) {
807 return t.isEmpty();
808 }
809 }
810
811 /**
812 * Return an array of service objects for all services being tracked by this
813 * {@code ServiceTracker}. The runtime type of the returned array is that of
814 * the specified array.
815 *
816 * <p>
817 * This implementation calls {@link #getServiceReferences()} to get the list
818 * of references for the tracked services and then calls
819 * {@link #getService(ServiceReference)} for each reference to get the
820 * tracked service object.
821 *
822 * @param array An array into which the tracked service objects will be
823 * stored, if the array is large enough.
824 * @return An array of service objects being tracked. If the specified array
825 * is large enough to hold the result, then the specified array is
826 * returned. If the specified array is longer then necessary to hold
827 * the result, the array element after the last service object is
828 * set to {@code null}. If the specified array is not large enough
829 * to hold the result, a new array is created and returned.
830 * @since 1.5
831 */
832 public T[] getServices(T[] array) {
833 final Tracked t = tracked();
834 if (t == null) { /* if ServiceTracker is not open */
835 if (array.length > 0) {
836 array[0] = null;
837 }
838 return array;
839 }
840 synchronized (t) {
841 ServiceReference<S>[] references = getServiceReferences();
842 int length = (references == null) ? 0 : references.length;
843 if (length == 0) {
844 if (array.length > 0) {
845 array[0] = null;
846 }
847 return array;
848 }
849 if (length > array.length) {
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000850 @SuppressWarnings("unchecked")
851 T[] newInstance = (T[]) Array.newInstance(array.getClass().getComponentType(), length);
852 array = newInstance;
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000853 }
854 for (int i = 0; i < length; i++) {
855 array[i] = getService(references[i]);
856 }
857 if (array.length > length) {
858 array[length] = null;
859 }
860 return array;
Richard S. Hall2532cf82010-03-24 09:51:11 +0000861 }
862 }
863
864 /**
865 * Inner class which subclasses AbstractTracked. This class is the
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000866 * {@code ServiceListener} object for the tracker.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000867 *
868 * @ThreadSafe
869 */
Richard S. Halldfd78a42012-05-11 20:19:02 +0000870 private class Tracked extends AbstractTracked<ServiceReference<S>, T, ServiceEvent> implements ServiceListener {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000871 /**
872 * Tracked constructor.
873 */
874 Tracked() {
875 super();
876 }
877
878 /**
Richard S. Halldfd78a42012-05-11 20:19:02 +0000879 * {@code ServiceListener} method for the {@code ServiceTracker} class.
880 * This method must NOT be synchronized to avoid deadlock potential.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000881 *
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000882 * @param event {@code ServiceEvent} object from the framework.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000883 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000884 final public void serviceChanged(final ServiceEvent event) {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000885 /*
886 * Check if we had a delayed call (which could happen when we
887 * close).
888 */
889 if (closed) {
890 return;
891 }
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000892 @SuppressWarnings("unchecked")
Richard S. Halldfd78a42012-05-11 20:19:02 +0000893 final ServiceReference<S> reference = (ServiceReference<S>) event.getServiceReference();
Richard S. Hall2532cf82010-03-24 09:51:11 +0000894 if (DEBUG) {
Richard S. Halldfd78a42012-05-11 20:19:02 +0000895 System.out.println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: " + reference);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000896 }
897
898 switch (event.getType()) {
899 case ServiceEvent.REGISTERED :
900 case ServiceEvent.MODIFIED :
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000901 track(reference, event);
902 /*
903 * If the customizer throws an unchecked exception, it is
904 * safe to let it propagate
905 */
Richard S. Hall2532cf82010-03-24 09:51:11 +0000906 break;
907 case ServiceEvent.MODIFIED_ENDMATCH :
908 case ServiceEvent.UNREGISTERING :
909 untrack(reference, event);
910 /*
911 * If the customizer throws an unchecked exception, it is
912 * safe to let it propagate
913 */
914 break;
915 }
916 }
917
918 /**
919 * Increment the tracking count and tell the tracker there was a
920 * modification.
921 *
922 * @GuardedBy this
923 */
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000924 @Override
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000925 final void modified() {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000926 super.modified(); /* increment the modification count */
927 ServiceTracker.this.modified();
928 }
929
930 /**
931 * Call the specific customizer adding method. This method must not be
932 * called while synchronized on this object.
933 *
934 * @param item Item to be tracked.
935 * @param related Action related object.
Richard S. Halldfd78a42012-05-11 20:19:02 +0000936 * @return Customized object for the tracked item or {@code null} if the
937 * item is not to be tracked.
Richard S. Hall2532cf82010-03-24 09:51:11 +0000938 */
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000939 @Override
Richard S. Halldfd78a42012-05-11 20:19:02 +0000940 final T customizerAdding(final ServiceReference<S> item, final ServiceEvent related) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000941 return customizer.addingService(item);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000942 }
943
944 /**
945 * Call the specific customizer modified method. This method must not be
946 * called while synchronized on this object.
947 *
948 * @param item Tracked item.
949 * @param related Action related object.
950 * @param object Customized object for the tracked item.
951 */
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000952 @Override
Richard S. Halldfd78a42012-05-11 20:19:02 +0000953 final void customizerModified(final ServiceReference<S> item, final ServiceEvent related, final T object) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000954 customizer.modifiedService(item, object);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000955 }
956
957 /**
958 * Call the specific customizer removed method. This method must not be
959 * called while synchronized on this object.
960 *
961 * @param item Tracked item.
962 * @param related Action related object.
963 * @param object Customized object for the tracked item.
964 */
Carsten Ziegeler3314f912014-07-30 07:22:32 +0000965 @Override
Richard S. Halldfd78a42012-05-11 20:19:02 +0000966 final void customizerRemoved(final ServiceReference<S> item, final ServiceEvent related, final T object) {
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000967 customizer.removedService(item, object);
Richard S. Hall2532cf82010-03-24 09:51:11 +0000968 }
969 }
970
971 /**
972 * Subclass of Tracked which implements the AllServiceListener interface.
973 * This class is used by the ServiceTracker if open is called with true.
974 *
975 * @since 1.3
976 * @ThreadSafe
977 */
Richard S. Halld0dca9b2011-05-18 14:52:16 +0000978 private class AllTracked extends Tracked implements AllServiceListener {
Richard S. Hall2532cf82010-03-24 09:51:11 +0000979 /**
980 * AllTracked constructor.
981 */
982 AllTracked() {
983 super();
984 }
985 }
986}