blob: 09b20c074d1484088bc425e41793163ea3e01e60 [file] [log] [blame]
Marcel Offermansa962bc92009-11-21 17:59:33 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Pierre De Ropaacb3aa2009-12-04 22:53:23 +000019package org.apache.felix.dm.impl.dependencies;
Marcel Offermansa962bc92009-11-21 17:59:33 +000020
Marcel Offermans26081d32010-07-12 12:43:42 +000021import java.lang.reflect.InvocationTargetException;
Marcel Offermansa962bc92009-11-21 17:59:33 +000022import java.lang.reflect.Proxy;
23import java.util.AbstractMap;
Marcel Offermanse14b3422009-11-25 23:04:32 +000024import java.util.ArrayList;
Marcel Offermansa962bc92009-11-21 17:59:33 +000025import java.util.Arrays;
26import java.util.Comparator;
Marcel Offermans117aa2f2009-12-10 09:48:17 +000027import java.util.Dictionary;
Marcel Offermans09e14aa2010-11-25 13:36:23 +000028import java.util.HashMap;
Marcel Offermansa962bc92009-11-21 17:59:33 +000029import java.util.HashSet;
Marcel Offermans7f0cec02011-11-04 13:39:28 +000030import java.util.Iterator;
Marcel Offermanse14b3422009-11-25 23:04:32 +000031import java.util.List;
Marcel Offermansa962bc92009-11-21 17:59:33 +000032import java.util.Map;
Marcel Offermans7f0cec02011-11-04 13:39:28 +000033import java.util.Map.Entry;
Marcel Offermans26081d32010-07-12 12:43:42 +000034import java.util.Properties;
Marcel Offermansa962bc92009-11-21 17:59:33 +000035import java.util.Set;
36
Marcel Offermans706fb272010-11-15 12:52:58 +000037import org.apache.felix.dm.Component;
Marcel Offermans9e50ef32010-10-07 11:37:00 +000038import org.apache.felix.dm.ComponentDependencyDeclaration;
Marcel Offermans8b93efa2010-07-02 18:27:21 +000039import org.apache.felix.dm.Dependency;
Marcel Offermans3d921212010-08-09 13:37:02 +000040import org.apache.felix.dm.DependencyService;
Marcel Offermans706fb272010-11-15 12:52:58 +000041import org.apache.felix.dm.InvocationUtil;
Marcel Offermans8b93efa2010-07-02 18:27:21 +000042import org.apache.felix.dm.ServiceDependency;
Marcel Offermans7f0cec02011-11-04 13:39:28 +000043import org.apache.felix.dm.ServiceUtil;
Pierre De Ropaacb3aa2009-12-04 22:53:23 +000044import org.apache.felix.dm.impl.DefaultNullObject;
45import org.apache.felix.dm.impl.Logger;
Marcel Offermansfaaed472010-09-08 10:07:32 +000046import org.apache.felix.dm.tracker.ServiceTracker;
47import org.apache.felix.dm.tracker.ServiceTrackerCustomizer;
Marcel Offermansa962bc92009-11-21 17:59:33 +000048import org.osgi.framework.BundleContext;
49import org.osgi.framework.Constants;
50import org.osgi.framework.InvalidSyntaxException;
51import org.osgi.framework.ServiceReference;
Marcel Offermans26081d32010-07-12 12:43:42 +000052import org.osgi.service.log.LogService;
Marcel Offermansa962bc92009-11-21 17:59:33 +000053
54/**
55 * Service dependency that can track an OSGi service.
56 *
57 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
58 */
Marcel Offermansfaaed472010-09-08 10:07:32 +000059public class ServiceDependencyImpl extends DependencyBase implements ServiceDependency, ServiceTrackerCustomizer, ComponentDependencyDeclaration {
Marcel Offermanse14b3422009-11-25 23:04:32 +000060 protected List m_services = new ArrayList();
Marcel Offermans74363c32009-11-23 19:56:08 +000061 protected volatile ServiceTracker m_tracker;
62 protected BundleContext m_context;
Marcel Offermans74363c32009-11-23 19:56:08 +000063 protected volatile Class m_trackedServiceName;
Marcel Offermansa962bc92009-11-21 17:59:33 +000064 private Object m_nullObject;
65 private volatile String m_trackedServiceFilter;
66 private volatile String m_trackedServiceFilterUnmodified;
67 private volatile ServiceReference m_trackedServiceReference;
Marcel Offermansa962bc92009-11-21 17:59:33 +000068 private Object m_callbackInstance;
69 private String m_callbackAdded;
70 private String m_callbackChanged;
71 private String m_callbackRemoved;
Marcel Offermans7f0cec02011-11-04 13:39:28 +000072 private String m_callbackSwapped;
Marcel Offermansa962bc92009-11-21 17:59:33 +000073 private boolean m_autoConfig;
Marcel Offermans74363c32009-11-23 19:56:08 +000074 protected ServiceReference m_reference;
75 protected Object m_serviceInstance;
Marcel Offermansa962bc92009-11-21 17:59:33 +000076 private String m_autoConfigInstance;
77 private boolean m_autoConfigInvoked;
78 private Object m_defaultImplementation;
79 private Object m_defaultImplementationInstance;
Marcel Offermansb196d722009-11-26 17:12:12 +000080 private boolean m_isAvailable;
Marcel Offermans26081d32010-07-12 12:43:42 +000081 private boolean m_propagate;
82 private Object m_propagateCallbackInstance;
83 private String m_propagateCallbackMethod;
Marcel Offermans7784e402011-01-21 20:41:50 +000084 private final Map m_sr = new HashMap(); /* <DependencyService, Set<Tuple<ServiceReference, Object>> */
Marcel Offermans7f0cec02011-11-04 13:39:28 +000085 private Map m_componentByRank = new HashMap(); /* <Component, Map<Long, Map<Integer, Tuple>>> */
Marcel Offermansa962bc92009-11-21 17:59:33 +000086
87 private static final Comparator COMPARATOR = new Comparator() {
88 public int getRank(ServiceReference ref) {
89 Object ranking = ref.getProperty(Constants.SERVICE_RANKING);
90 if (ranking != null && (ranking instanceof Integer)) {
91 return ((Integer) ranking).intValue();
92 }
93 return 0;
94 }
95
96 public int compare(Object a, Object b) {
97 ServiceReference ra = (ServiceReference) a, rb = (ServiceReference) b;
98 int ranka = getRank(ra);
99 int rankb = getRank(rb);
100 if (ranka < rankb) {
101 return -1;
102 }
103 else if (ranka > rankb) {
104 return 1;
105 }
106 return 0;
107 }
108 };
109
Marcel Offermans7784e402011-01-21 20:41:50 +0000110 private static final class Tuple /* <ServiceReference, Object> */ {
111 private final ServiceReference m_serviceReference;
112 private final Object m_service;
113
114 public Tuple(ServiceReference first, Object last) {
115 m_serviceReference = first;
116 m_service = last;
117 }
118
119 public ServiceReference getServiceReference() {
120 return m_serviceReference;
121 }
122
123 public Object getService() {
124 return m_service;
125 }
126
127 public boolean equals(Object obj) {
128 return ((Tuple) obj).getServiceReference().equals(getServiceReference());
129 }
130
131 public int hashCode() {
132 return m_serviceReference.hashCode();
133 }
134 }
135
Marcel Offermansa962bc92009-11-21 17:59:33 +0000136 /**
137 * Entry to wrap service properties behind a Map.
138 */
Marcel Offermans7784e402011-01-21 20:41:50 +0000139 private static final class ServicePropertiesMapEntry implements Map.Entry {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000140 private final String m_key;
141 private Object m_value;
142
143 public ServicePropertiesMapEntry(String key, Object value) {
144 m_key = key;
145 m_value = value;
146 }
147
148 public Object getKey() {
149 return m_key;
150 }
151
152 public Object getValue() {
153 return m_value;
154 }
155
156 public String toString() {
157 return m_key + "=" + m_value;
158 }
159
160 public Object setValue(Object value) {
161 Object oldValue = m_value;
162 m_value = value;
163 return oldValue;
164 }
165
166 public boolean equals(Object o) {
167 if (!(o instanceof Map.Entry)) {
168 return false;
169 }
170 Map.Entry e = (Map.Entry) o;
171 return eq(m_key, e.getKey()) && eq(m_value, e.getValue());
172 }
173
174 public int hashCode() {
175 return ((m_key == null) ? 0 : m_key.hashCode()) ^ ((m_value == null) ? 0 : m_value.hashCode());
176 }
177
178 private static final boolean eq(Object o1, Object o2) {
179 return (o1 == null ? o2 == null : o1.equals(o2));
180 }
181 }
182
183 /**
184 * Wraps service properties behind a Map.
185 */
186 private final static class ServicePropertiesMap extends AbstractMap {
187 private final ServiceReference m_ref;
188
189 public ServicePropertiesMap(ServiceReference ref) {
190 m_ref = ref;
191 }
192
193 public Object get(Object key) {
194 return m_ref.getProperty(key.toString());
195 }
196
197 public int size() {
198 return m_ref.getPropertyKeys().length;
199 }
200
201 public Set entrySet() {
202 Set set = new HashSet();
203 String[] keys = m_ref.getPropertyKeys();
204 for (int i = 0; i < keys.length; i++) {
205 set.add(new ServicePropertiesMapEntry(keys[i], m_ref.getProperty(keys[i])));
206 }
207 return set;
208 }
209 }
210
211 /**
212 * Creates a new service dependency.
213 *
214 * @param context the bundle context
215 * @param logger the logger
216 */
Pierre De Ropaacb3aa2009-12-04 22:53:23 +0000217 public ServiceDependencyImpl(BundleContext context, Logger logger) {
Marcel Offermansb196d722009-11-26 17:12:12 +0000218 super(logger);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000219 m_context = context;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000220 m_autoConfig = true;
221 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000222
Marcel Offermansb1959f42010-07-01 12:23:51 +0000223 /** Copying constructor that clones an existing instance. */
224 public ServiceDependencyImpl(ServiceDependencyImpl prototype) {
225 super(prototype);
Marcel Offermanse7baff52010-12-17 08:51:52 +0000226 synchronized (prototype) {
227 m_context = prototype.m_context;
228 m_autoConfig = prototype.m_autoConfig;
229 m_trackedServiceName = prototype.m_trackedServiceName;
230 m_nullObject = prototype.m_nullObject;
231 m_trackedServiceFilter = prototype.m_trackedServiceFilter;
232 m_trackedServiceFilterUnmodified = prototype.m_trackedServiceFilterUnmodified;
233 m_trackedServiceReference = prototype.m_trackedServiceReference;
234 m_callbackInstance = prototype.m_callbackInstance;
235 m_callbackAdded = prototype.m_callbackAdded;
236 m_callbackChanged = prototype.m_callbackChanged;
237 m_callbackRemoved = prototype.m_callbackRemoved;
238 m_autoConfigInstance = prototype.m_autoConfigInstance;
239 m_defaultImplementation = prototype.m_defaultImplementation;
240 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000241 }
242
243 public Dependency createCopy() {
244 return new ServiceDependencyImpl(this);
245 }
246
Marcel Offermansa962bc92009-11-21 17:59:33 +0000247 public synchronized boolean isAutoConfig() {
248 return m_autoConfig;
249 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000250
Marcel Offermansb196d722009-11-26 17:12:12 +0000251 public synchronized boolean isAvailable() {
252 return m_isAvailable;
253 }
254
Marcel Offermansa962bc92009-11-21 17:59:33 +0000255 public synchronized Object getService() {
256 Object service = null;
257 if (m_isStarted) {
258 service = m_tracker.getService();
259 }
Marcel Offermans001db052009-12-08 08:58:40 +0000260 if (service == null && isAutoConfig()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000261 service = getDefaultImplementation();
262 if (service == null) {
263 service = getNullObject();
264 }
265 }
266 return service;
267 }
268
269 public Object lookupService() {
270 Object service = null;
271 if (m_isStarted) {
Marcel Offermans001db052009-12-08 08:58:40 +0000272 service = getService();
Marcel Offermansa962bc92009-11-21 17:59:33 +0000273 }
274 else {
275 ServiceReference[] refs = null;
276 ServiceReference ref = null;
277 if (m_trackedServiceName != null) {
278 if (m_trackedServiceFilter != null) {
279 try {
280 refs = m_context.getServiceReferences(m_trackedServiceName.getName(), m_trackedServiceFilter);
281 if (refs != null) {
282 Arrays.sort(refs, COMPARATOR);
283 ref = refs[0];
284 }
285 }
286 catch (InvalidSyntaxException e) {
287 throw new IllegalStateException("Invalid filter definition for dependency.");
288 }
289 }
290 else if (m_trackedServiceReference != null) {
291 ref = m_trackedServiceReference;
292 }
293 else {
294 ref = m_context.getServiceReference(m_trackedServiceName.getName());
295 }
296 if (ref != null) {
297 service = m_context.getService(ref);
298 }
299 }
300 else {
301 throw new IllegalStateException("Could not lookup dependency, no service name specified.");
302 }
303 }
Marcel Offermans001db052009-12-08 08:58:40 +0000304 if (service == null && isAutoConfig()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000305 service = getDefaultImplementation();
306 if (service == null) {
307 service = getNullObject();
308 }
309 }
310 return service;
311 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000312
Marcel Offermanse14b3422009-11-25 23:04:32 +0000313 // TODO lots of duplication in lookupService()
314 public ServiceReference lookupServiceReference() {
315 ServiceReference service = null;
316 if (m_isStarted) {
317 service = m_tracker.getServiceReference();
318 }
319 else {
320 ServiceReference[] refs = null;
321 ServiceReference ref = null;
322 if (m_trackedServiceName != null) {
323 if (m_trackedServiceFilter != null) {
324 try {
325 refs = m_context.getServiceReferences(m_trackedServiceName.getName(), m_trackedServiceFilter);
326 if (refs != null) {
327 Arrays.sort(refs, COMPARATOR);
328 ref = refs[0];
329 }
330 }
331 catch (InvalidSyntaxException e) {
332 throw new IllegalStateException("Invalid filter definition for dependency.");
333 }
334 }
335 else if (m_trackedServiceReference != null) {
336 ref = m_trackedServiceReference;
337 }
338 else {
339 ref = m_context.getServiceReference(m_trackedServiceName.getName());
340 }
341 if (ref != null) {
342 service = ref;
343 }
344 }
345 else {
346 throw new IllegalStateException("Could not lookup dependency, no service name specified.");
347 }
348 }
349 return service;
350 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000351
352 private Object getNullObject() {
353 if (m_nullObject == null) {
354 Class trackedServiceName;
355 synchronized (this) {
356 trackedServiceName = m_trackedServiceName;
357 }
358 try {
359 m_nullObject = Proxy.newProxyInstance(trackedServiceName.getClassLoader(), new Class[] {trackedServiceName}, new DefaultNullObject());
360 }
361 catch (Exception e) {
362 m_logger.log(Logger.LOG_ERROR, "Could not create null object for " + trackedServiceName + ".", e);
363 }
364 }
365 return m_nullObject;
366 }
367
368 private Object getDefaultImplementation() {
369 if (m_defaultImplementation != null) {
370 if (m_defaultImplementation instanceof Class) {
371 try {
372 m_defaultImplementationInstance = ((Class) m_defaultImplementation).newInstance();
373 }
374 catch (Exception e) {
375 m_logger.log(Logger.LOG_ERROR, "Could not create default implementation instance of class " + m_defaultImplementation + ".", e);
376 }
377 }
378 else {
379 m_defaultImplementationInstance = m_defaultImplementation;
380 }
381 }
382 return m_defaultImplementationInstance;
383 }
384
385 public synchronized Class getInterface() {
386 return m_trackedServiceName;
387 }
388
Marcel Offermanse14b3422009-11-25 23:04:32 +0000389 public void start(DependencyService service) {
390 boolean needsStarting = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000391 synchronized (this) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000392 m_services.add(service);
393 if (!m_isStarted) {
394 if (m_trackedServiceName != null) {
395 if (m_trackedServiceFilter != null) {
396 try {
397 m_tracker = new ServiceTracker(m_context, m_context.createFilter(m_trackedServiceFilter), this);
398 }
399 catch (InvalidSyntaxException e) {
Marcel Offermansad760672010-03-03 15:30:01 +0000400 throw new IllegalStateException("Invalid filter definition for dependency: " + m_trackedServiceFilter);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000401 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000402 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000403 else if (m_trackedServiceReference != null) {
404 m_tracker = new ServiceTracker(m_context, m_trackedServiceReference, this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000405 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000406 else {
407 m_tracker = new ServiceTracker(m_context, m_trackedServiceName.getName(), this);
408 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000409 }
410 else {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000411 throw new IllegalStateException("Could not create tracker for dependency, no service name specified.");
Marcel Offermansa962bc92009-11-21 17:59:33 +0000412 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000413 m_isStarted = true;
414 needsStarting = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000415 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000416 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000417 if (needsStarting) {
418 m_tracker.open();
419 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000420 }
421
Marcel Offermanse14b3422009-11-25 23:04:32 +0000422 public void stop(DependencyService service) {
423 boolean needsStopping = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000424 synchronized (this) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000425 if (m_services.size() == 1 && m_services.contains(service)) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000426 m_isStarted = false;
427 needsStopping = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000428 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000429 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000430 if (needsStopping) {
431 m_tracker.close();
432 m_tracker = null;
433 }
Marcel Offermans1c944ec2010-10-11 13:55:02 +0000434 //moved this down
435 synchronized (this) {
436 m_services.remove(service);
437 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000438 }
439
440 public Object addingService(ServiceReference ref) {
441 Object service = m_context.getService(ref);
442 // first check to make sure the service is actually an instance of our service
443 if (!m_trackedServiceName.isInstance(service)) {
444 return null;
445 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000446 return service;
447 }
448
449 public void addedService(ServiceReference ref, Object service) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000450 boolean makeAvailable = makeAvailable();
451
Marcel Offermans203bdad2009-12-04 09:23:04 +0000452 Object[] services;
453 synchronized (this) {
454 services = m_services.toArray();
455 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000456 for (int i = 0; i < services.length; i++) {
457 DependencyService ds = (DependencyService) services[i];
458 if (makeAvailable) {
Marcel Offermansfea14842010-10-14 14:45:36 +0000459 if (ds.isInstantiated() && isInstanceBound() && isRequired()) {
460 invokeAdded(ds, ref, service);
461 }
Pierre De Rop1785c332010-06-11 06:03:53 +0000462 // The dependency callback will be defered until all required dependency are available.
463 ds.dependencyAvailable(this);
464 if (!isRequired()) {
465 // For optional dependency, we always invoke callback, because at this point, we know
466 // that the service has been started, and the service start method has been called.
467 // (See the ServiceImpl.bindService method, which will activate optional dependencies using
468 // startTrackingOptional() method).
Marcel Offermanse14b3422009-11-25 23:04:32 +0000469 invokeAdded(ds, ref, service);
470 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000471 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000472 else {
473 ds.dependencyChanged(this);
Pierre De Rop1785c332010-06-11 06:03:53 +0000474 // At this point, either the dependency is optional (meaning that the service has been started,
475 // because if not, then our dependency would not be active); or the dependency is required,
476 // meaning that either the service is not yet started, or already started.
477 // In all cases, we have to inject the required dependency.
Marcel Offermans09e14aa2010-11-25 13:36:23 +0000478
479 // we only try to invoke the method here if we are really already instantiated
480 if (ds.isInstantiated() && ds.getCompositionInstances().length > 0) {
481 invokeAdded(ds, ref, service);
482 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000483 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000484 }
485 }
486
Marcel Offermansa962bc92009-11-21 17:59:33 +0000487 public void modifiedService(ServiceReference ref, Object service) {
Marcel Offermans203bdad2009-12-04 09:23:04 +0000488 Object[] services;
489 synchronized (this) {
490 services = m_services.toArray();
491 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000492 for (int i = 0; i < services.length; i++) {
493 DependencyService ds = (DependencyService) services[i];
494 ds.dependencyChanged(this);
495 if (ds.isRegistered()) {
496 invokeChanged(ds, ref, service);
497 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000498 }
499 }
500
Marcel Offermansa962bc92009-11-21 17:59:33 +0000501 public void removedService(ServiceReference ref, Object service) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000502 boolean makeUnavailable = makeUnavailable();
503
Marcel Offermans203bdad2009-12-04 09:23:04 +0000504 Object[] services;
505 synchronized (this) {
506 services = m_services.toArray();
507 }
Marcel Offermans1c944ec2010-10-11 13:55:02 +0000508
Marcel Offermanse14b3422009-11-25 23:04:32 +0000509 for (int i = 0; i < services.length; i++) {
510 DependencyService ds = (DependencyService) services[i];
511 if (makeUnavailable) {
512 ds.dependencyUnavailable(this);
Marcel Offermansfea14842010-10-14 14:45:36 +0000513 if (!isRequired() || (ds.isInstantiated() && isInstanceBound())) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000514 invokeRemoved(ds, ref, service);
515 }
516 }
517 else {
518 ds.dependencyChanged(this);
519 invokeRemoved(ds, ref, service);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000520 }
521 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000522 // unget what we got in addingService (see ServiceTracker 701.4.1)
523 m_context.ungetService(ref);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000524
Marcel Offermansa962bc92009-11-21 17:59:33 +0000525 }
Marcel Offermans09e14aa2010-11-25 13:36:23 +0000526
Marcel Offermansea89b862010-06-24 13:14:43 +0000527 public void invokeAdded(DependencyService dependencyService, ServiceReference reference, Object service) {
Marcel Offermanse7baff52010-12-17 08:51:52 +0000528 boolean added = false;
529 synchronized (m_sr) {
530 Set set = (Set) m_sr.get(dependencyService);
531 if (set == null) {
532 set = new HashSet();
533 m_sr.put(dependencyService, set);
534 }
Marcel Offermans7784e402011-01-21 20:41:50 +0000535 added = set.add(new Tuple(reference, service));
Marcel Offermans09e14aa2010-11-25 13:36:23 +0000536 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000537 if (added) {
538 // when a changed callback is specified we might not call the added callback just yet
539 if (m_callbackSwapped != null) {
540 handleAspectAwareAdded(dependencyService, reference, service);
Marcel Offermans4aa032c2012-01-02 19:18:22 +0000541 }
542 else {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000543 invoke(dependencyService, reference, service, m_callbackAdded);
544 }
Marcel Offermans09e14aa2010-11-25 13:36:23 +0000545 }
Marcel Offermansea89b862010-06-24 13:14:43 +0000546 }
547
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000548 private void handleAspectAwareAdded(DependencyService dependencyService, ServiceReference reference, Object service) {
549 if (componentIsDependencyManagerFactory(dependencyService)) {
550 // component is either aspect or adapter factory instance, these must be ignored.
551 return;
552 }
553 boolean invokeAdded = false;
554 Integer ranking = ServiceUtil.getRankingAsInteger(reference);
555 Tuple highestRankedService = null;
556 synchronized (m_componentByRank) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000557 Long originalServiceId = ServiceUtil.getServiceIdAsLong(reference);
558 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
559 if (componentMap == null) {
560 // create new componentMap
561 componentMap = new HashMap(); /* <Long, Map<Integer, Tuple>> */
562 m_componentByRank.put(dependencyService, componentMap);
563 }
564 Map rankings = (Map) componentMap.get(originalServiceId); /* <Integer, Tuple> */
565 if (rankings == null) {
566 // new component added
567 rankings = new HashMap(); /* <Integer, Tuple> */
568 componentMap.put(originalServiceId, rankings);
569 rankings.put(ranking, new Tuple(reference, service));
570 invokeAdded = true;
571 }
572
573 if (!invokeAdded) {
574 highestRankedService = swapHighestRankedService(dependencyService, originalServiceId, reference, service, ranking);
575 }
576 }
577 if (invokeAdded) {
578 invoke(dependencyService, reference, service, m_callbackAdded);
579 } else {
580 invokeSwappedCallback(dependencyService, highestRankedService.getServiceReference(), highestRankedService.getService(), reference, service);
581 }
582 }
583
Marcel Offermans4aa032c2012-01-02 19:18:22 +0000584 private boolean componentIsDependencyManagerFactory(DependencyService dependencyService) {
585 Object component = dependencyService.getService();
586 if (component != null) {
587 String className = component.getClass().getName();
588 return className.startsWith("org.apache.felix.dm")
589 && !className.startsWith("org.apache.felix.dm.impl.AdapterServiceImpl$AdapterImpl")
590 && !className.startsWith("org.apache.felix.dm.test");
591 }
592 return false;
593 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000594
595 private Tuple swapHighestRankedService(DependencyService dependencyService, Long serviceId, ServiceReference newReference, Object newService, Integer newRanking) {
596 // does a component with a higher ranking exists
597 synchronized (m_componentByRank) {
598 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
599 Map rankings = (Map) componentMap.get(serviceId); /* <Integer, Tuple> */
600 Entry highestEntry = getHighestRankedService(dependencyService, serviceId); /* <Integer, Tuple> */
601 rankings.remove(highestEntry.getKey());
602 rankings.put(newRanking, new Tuple(newReference, newService));
603 return (Tuple) highestEntry.getValue();
604 }
605 }
606
607 private Entry getHighestRankedService(DependencyService dependencyService, Long serviceId) { /* <Integer, Tuple> */
608 Entry highestEntry = null; /* <Integer, Tuple> */
609 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
610 Map rankings = (Map) componentMap.get(serviceId); /* <Integer, Tuple> */
611 if (rankings != null) {
612 for (Iterator entryIterator = rankings.entrySet().iterator(); entryIterator.hasNext(); ) { /* <Integer, Tuple> */
613 Entry mapEntry = (Entry) entryIterator.next();
614 if (highestEntry == null) {
615 highestEntry = mapEntry;
616 } else {
617 if (((Integer)mapEntry.getKey()).intValue() > ((Integer)highestEntry.getKey()).intValue()) {
618 highestEntry = mapEntry;
619 }
620 }
621 }
622 }
623 return highestEntry;
624 }
625
626
627
628 private boolean isLastService(DependencyService dependencyService, ServiceReference reference, Object object, Long serviceId) {
629 // get the collection of rankings
630 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
631
632 Map rankings = null; /* <Integer, Tuple> */
633 if (componentMap != null) {
634 rankings = (Map) componentMap.get(serviceId);
635 }
636 // if there is only one element left in the collection of rankings
637 // and this last element has the same ranking as the supplied service (in other words, it is the same)
638 // then this is the last service
639 // NOTE: it is possible that there is only one element, but that it's not equal to the supplied service,
640 // because an aspect on top of the original service is being removed (but the original service is still
641 // there). That in turn triggers:
642 // 1) a call to added(original-service)
643 // 2) that causes a swap
644 // 3) a call to removed(aspect-service) <-- that's what we're talking about
645 return (componentMap != null && rankings != null && rankings.size() == 1 && ((Entry)rankings.entrySet().iterator().next()).getKey()
646 .equals(ServiceUtil.getRankingAsInteger(reference)));
647 }
648
649
Marcel Offermansea89b862010-06-24 13:14:43 +0000650 public void invokeChanged(DependencyService dependencyService, ServiceReference reference, Object service) {
651 invoke(dependencyService, reference, service, m_callbackChanged);
652 }
653
Marcel Offermansb196d722009-11-26 17:12:12 +0000654 public void invokeRemoved(DependencyService dependencyService, ServiceReference reference, Object service) {
Marcel Offermanse7baff52010-12-17 08:51:52 +0000655 boolean removed = false;
656 synchronized (m_sr) {
657 Set set = (Set) m_sr.get(dependencyService);
Marcel Offermans7784e402011-01-21 20:41:50 +0000658 removed = (set != null && set.remove(new Tuple(reference, service)));
Marcel Offermanse7baff52010-12-17 08:51:52 +0000659 }
660 if (removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000661 if (m_callbackSwapped != null) {
662 handleAspectAwareRemoved(dependencyService, reference, service);
Marcel Offermans4aa032c2012-01-02 19:18:22 +0000663 }
664 else {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000665 invoke(dependencyService, reference, service, m_callbackRemoved);
666 }
Marcel Offermans09e14aa2010-11-25 13:36:23 +0000667 }
Marcel Offermansea89b862010-06-24 13:14:43 +0000668 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000669
670 private void handleAspectAwareRemoved(DependencyService dependencyService, ServiceReference reference, Object service) {
671 if (componentIsDependencyManagerFactory(dependencyService)) {
672 // component is either aspect or adapter factory instance, these must be ignored.
673 return;
674 }
675 Long serviceId = ServiceUtil.getServiceIdAsLong(reference);
676 synchronized (m_componentByRank) {
677 if (isLastService(dependencyService, reference, service, serviceId)) {
678 invoke(dependencyService, reference, service, m_callbackRemoved);
679 }
680 Long originalServiceId = ServiceUtil.getServiceIdAsLong(reference);
681 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
682 if (componentMap != null) {
683 Map rankings = (Map) componentMap.get(originalServiceId); /* <Integer, Tuple> */
684 for (Iterator entryIterator = rankings.entrySet().iterator(); entryIterator.hasNext(); ) {
685 Entry mapEntry = (Entry) entryIterator.next();
686 if (((Tuple)mapEntry.getValue()).getServiceReference().equals(reference)) {
687 // remove the reference
688 rankings.remove(mapEntry.getKey());
689 }
690 }
691 if (rankings.size() == 0) {
692 componentMap.remove(originalServiceId);
693 }
694 if (componentMap.size() == 0) {
695 m_componentByRank.remove(dependencyService);
696 }
697 }
698 }
699 }
Marcel Offermansea89b862010-06-24 13:14:43 +0000700
701 public void invoke(DependencyService dependencyService, ServiceReference reference, Object service, String name) {
702 if (name != null) {
703 dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name,
Marcel Offermans706fb272010-11-15 12:52:58 +0000704 new Class[][] {
705 {Component.class, ServiceReference.class, m_trackedServiceName}, {Component.class, ServiceReference.class, Object.class}, {Component.class, ServiceReference.class}, {Component.class, m_trackedServiceName}, {Component.class, Object.class}, {Component.class}, {Component.class, Map.class, m_trackedServiceName},
706 {ServiceReference.class, m_trackedServiceName}, {ServiceReference.class, Object.class}, {ServiceReference.class}, {m_trackedServiceName}, {Object.class}, {}, {Map.class, m_trackedServiceName}
707 },
708 new Object[][] {
709 {dependencyService, reference, service}, {dependencyService, reference, service}, {dependencyService, reference}, {dependencyService, service}, {dependencyService, service}, {dependencyService}, {dependencyService, new ServicePropertiesMap(reference), service},
710 {reference, service}, {reference, service}, {reference}, {service}, {service}, {}, {new ServicePropertiesMap(reference), service}
711 }
Marcel Offermansb196d722009-11-26 17:12:12 +0000712 );
Marcel Offermansa962bc92009-11-21 17:59:33 +0000713 }
714 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000715
716 private void invokeSwappedCallback(DependencyService component, ServiceReference previousReference, Object previous, ServiceReference currentServiceReference,
717 Object current) {
718 component.invokeCallbackMethod(getCallbackInstances(component), m_callbackSwapped, new Class[][] { { m_trackedServiceName, m_trackedServiceName },
719 { Object.class, Object.class }, { ServiceReference.class, m_trackedServiceName, ServiceReference.class, m_trackedServiceName },
720 { ServiceReference.class, Object.class, ServiceReference.class, Object.class } }, new Object[][] { { previous, current },
721 { previous, current }, { previousReference, previous, currentServiceReference, current },
722 { previousReference, previous, currentServiceReference, current } });
723 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000724
Marcel Offermans74363c32009-11-23 19:56:08 +0000725 protected synchronized boolean makeAvailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000726 if (!isAvailable()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000727 m_isAvailable = true;
728 return true;
729 }
730 return false;
731 }
732
733 private synchronized boolean makeUnavailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000734 if ((isAvailable()) && (m_tracker.getServiceReference() == null)) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000735 m_isAvailable = false;
736 return true;
737 }
738 return false;
739 }
740
Marcel Offermanse14b3422009-11-25 23:04:32 +0000741 private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
742 if (m_callbackInstance == null) {
743 return dependencyService.getCompositionInstances();
744 }
745 else {
746 return new Object[] { m_callbackInstance };
747 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000748 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000749
750 // ----- CREATION
751
752 /**
753 * Sets the name of the service that should be tracked.
754 *
755 * @param serviceName the name of the service
756 * @return this service dependency
757 */
758 public synchronized ServiceDependency setService(Class serviceName) {
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000759 setService(serviceName, null, null);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000760 return this;
761 }
762
763 /**
764 * Sets the name of the service that should be tracked. You can either specify
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000765 * only the name, only the filter, or the name and a filter.
766 * <p>
767 * If you specify name and filter, the filter is used
Marcel Offermansa962bc92009-11-21 17:59:33 +0000768 * to track the service and should only return services of the type that was specified
769 * in the name. To make sure of this, the filter is actually extended internally to
770 * filter on the correct name.
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000771 * <p>
772 * If you specify only the filter, the name is assumed to be a service of type
773 * <code>Object</code> which means that, when auto configuration is on, instances
774 * of that service will be injected in any field of type <code>Object</code>.
Marcel Offermansa962bc92009-11-21 17:59:33 +0000775 *
776 * @param serviceName the name of the service
777 * @param serviceFilter the filter condition
778 * @return this service dependency
779 */
780 public synchronized ServiceDependency setService(Class serviceName, String serviceFilter) {
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000781 setService(serviceName, null, serviceFilter);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000782 return this;
783 }
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000784
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000785 /**
786 * Sets the name of the service that should be tracked. The name is assumed to be
787 * a service of type <code>Object</code> which means that, when auto configuration
788 * is on, instances of that service will be injected in any field of type
789 * <code>Object</code>.
790 *
791 * @param serviceFilter the filter condition
792 * @return this service dependency
793 */
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000794 public synchronized ServiceDependency setService(String serviceFilter) {
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000795 if (serviceFilter == null) {
796 throw new IllegalArgumentException("Service filter cannot be null.");
797 }
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000798 setService(null, null, serviceFilter);
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000799 return this;
800 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000801
802 /**
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000803 * Sets the name of the service that should be tracked. By specifying the service
804 * reference of the service you want to track, you can directly track a single
805 * service. The name you use must match the type of service referred to by the
806 * service reference and it is up to you to make sure that is the case.
Marcel Offermansa962bc92009-11-21 17:59:33 +0000807 *
808 * @param serviceName the name of the service
809 * @param serviceReference the service reference to track
810 * @return this service dependency
811 */
812 public synchronized ServiceDependency setService(Class serviceName, ServiceReference serviceReference) {
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000813 setService(serviceName, serviceReference, null);
814 return this;
815 }
816
817 /** Internal method to set the name, service reference and/or filter. */
818 private void setService(Class serviceName, ServiceReference serviceReference, String serviceFilter) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000819 ensureNotActive();
820 if (serviceName == null) {
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000821 m_trackedServiceName = Object.class;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000822 }
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000823 else {
824 m_trackedServiceName = serviceName;
825 }
826 if (serviceFilter != null) {
827 m_trackedServiceFilterUnmodified = serviceFilter;
828 if (serviceName == null) {
829 m_trackedServiceFilter = serviceFilter;
830 }
831 else {
832 m_trackedServiceFilter ="(&(" + Constants.OBJECTCLASS + "=" + serviceName.getName() + ")" + serviceFilter + ")";
833 }
834 }
835 else {
836 m_trackedServiceFilterUnmodified = null;
837 m_trackedServiceFilter = null;
838 }
839 if (serviceReference != null) {
840 m_trackedServiceReference = serviceReference;
841 if (serviceFilter != null) {
842 throw new IllegalArgumentException("Cannot specify both a filter and a service reference.");
843 }
844 }
845 else {
846 m_trackedServiceReference = null;
847 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000848 }
849
850 /**
851 * Sets the default implementation for this service dependency. You can use this to supply
852 * your own implementation that will be used instead of a Null Object when the dependency is
853 * not available. This is also convenient if the service dependency is not an interface
854 * (which would cause the Null Object creation to fail) but a class.
855 *
856 * @param implementation the instance to use or the class to instantiate if you want to lazily
857 * instantiate this implementation
858 * @return this service dependency
859 */
860 public synchronized ServiceDependency setDefaultImplementation(Object implementation) {
861 ensureNotActive();
862 m_defaultImplementation = implementation;
863 return this;
864 }
865
866 /**
867 * Sets the required flag which determines if this service is required or not.
868 *
869 * @param required the required flag
870 * @return this service dependency
871 */
872 public synchronized ServiceDependency setRequired(boolean required) {
873 ensureNotActive();
Marcel Offermansb196d722009-11-26 17:12:12 +0000874 setIsRequired(required);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000875 return this;
876 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000877
878 public ServiceDependency setInstanceBound(boolean isInstanceBound) {
Marcel Offermans61a81142010-04-02 15:16:50 +0000879 setIsInstanceBound(isInstanceBound);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000880 return this;
881 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000882
883 /**
884 * Sets auto configuration for this service. Auto configuration allows the
885 * dependency to fill in any attributes in the service implementation that
886 * are of the same type as this dependency. Default is on.
887 *
888 * @param autoConfig the value of auto config
889 * @return this service dependency
890 */
891 public synchronized ServiceDependency setAutoConfig(boolean autoConfig) {
892 ensureNotActive();
893 m_autoConfig = autoConfig;
894 m_autoConfigInvoked = true;
895 return this;
896 }
897
898 /**
899 * Sets auto configuration for this service. Auto configuration allows the
900 * dependency to fill in the attribute in the service implementation that
901 * has the same type and instance name.
902 *
903 * @param instanceName the name of attribute to auto config
904 * @return this service dependency
905 */
906 public synchronized ServiceDependency setAutoConfig(String instanceName) {
907 ensureNotActive();
908 m_autoConfig = (instanceName != null);
909 m_autoConfigInstance = instanceName;
910 m_autoConfigInvoked = true;
911 return this;
912 }
913
914 /**
915 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
916 * dependency is added or removed. When you specify callbacks, the auto configuration
917 * feature is automatically turned off, because we're assuming you don't need it in this
918 * case.
919 *
920 * @param added the method to call when a service was added
921 * @param removed the method to call when a service was removed
922 * @return this service dependency
923 */
924 public synchronized ServiceDependency setCallbacks(String added, String removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000925 return setCallbacks((Object) null, added, null, removed);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000926 }
927
928 /**
929 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
930 * dependency is added, changed or removed. When you specify callbacks, the auto
931 * configuration feature is automatically turned off, because we're assuming you don't
932 * need it in this case.
933 *
934 * @param added the method to call when a service was added
935 * @param changed the method to call when a service was changed
936 * @param removed the method to call when a service was removed
937 * @return this service dependency
938 */
939 public synchronized ServiceDependency setCallbacks(String added, String changed, String removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000940 return setCallbacks((Object) null, added, changed, removed);
941 }
942
943 /**
944 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
945 * dependency is added, changed or removed. When you specify callbacks, the auto
946 * configuration feature is automatically turned off, because we're assuming you don't
947 * need it in this case.
948 * @param added the method to call when a service was added
949 * @param changed the method to call when a service was changed
950 * @param removed the method to call when a service was removed
951 * @param swapped the method to call when the service was swapped due to addition or
952 * removal of an aspect
953 * @return this service dependency
954 */
955 public synchronized ServiceDependency setCallbacks(String added, String changed, String removed, String swapped) {
956 return setCallbacks((Object) null, added, changed, removed, swapped);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000957 }
958
959 /**
960 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
961 * dependency is added or removed. They are called on the instance you provide. When you
962 * specify callbacks, the auto configuration feature is automatically turned off, because
963 * we're assuming you don't need it in this case.
964 *
965 * @param instance the instance to call the callbacks on
966 * @param added the method to call when a service was added
967 * @param removed the method to call when a service was removed
968 * @return this service dependency
969 */
970 public synchronized ServiceDependency setCallbacks(Object instance, String added, String removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000971 return setCallbacks(instance, added, (String) null, removed);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000972 }
973
974 /**
975 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
976 * dependency is added, changed or removed. They are called on the instance you provide. When you
977 * specify callbacks, the auto configuration feature is automatically turned off, because
978 * we're assuming you don't need it in this case.
979 *
980 * @param instance the instance to call the callbacks on
981 * @param added the method to call when a service was added
982 * @param changed the method to call when a service was changed
983 * @param removed the method to call when a service was removed
984 * @return this service dependency
985 */
986 public synchronized ServiceDependency setCallbacks(Object instance, String added, String changed, String removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000987 return setCallbacks(instance, added, changed, removed, null);
988 }
989
990 /**
991 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
992 * dependency is added, changed or removed. When you specify callbacks, the auto
993 * configuration feature is automatically turned off, because we're assuming you don't
994 * need it in this case.
995 * @param instance the instance to call the callbacks on
996 * @param added the method to call when a service was added
997 * @param changed the method to call when a service was changed
998 * @param removed the method to call when a service was removed
999 * @param swapped the method to call when the service was swapped due to addition or
1000 * removal of an aspect
1001 * @return this service dependency
1002 */
1003 public synchronized ServiceDependency setCallbacks(Object instance, String added, String changed, String removed, String swapped) {
Marcel Offermansa962bc92009-11-21 17:59:33 +00001004 ensureNotActive();
1005 // if at least one valid callback is specified, we turn off auto configuration, unless
1006 // someone already explicitly invoked autoConfig
Marcel Offermans7f0cec02011-11-04 13:39:28 +00001007 if ((added != null || removed != null || changed != null || swapped != null) && ! m_autoConfigInvoked) {
Marcel Offermansa962bc92009-11-21 17:59:33 +00001008 setAutoConfig(false);
1009 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +00001010 m_callbackInstance = instance;
Marcel Offermansa962bc92009-11-21 17:59:33 +00001011 m_callbackAdded = added;
1012 m_callbackChanged = changed;
Marcel Offermans7f0cec02011-11-04 13:39:28 +00001013 m_callbackRemoved = removed;
1014 m_callbackSwapped = swapped;
1015 return this;
Marcel Offermansa962bc92009-11-21 17:59:33 +00001016 }
1017
1018 private void ensureNotActive() {
1019 if (m_tracker != null) {
1020 throw new IllegalStateException("Cannot modify state while active.");
1021 }
1022 }
1023
1024 public synchronized String toString() {
1025 return "ServiceDependency[" + m_trackedServiceName + " " + m_trackedServiceFilterUnmodified + "]";
1026 }
1027
1028 public String getAutoConfigName() {
1029 return m_autoConfigInstance;
1030 }
Marcel Offermans001db052009-12-08 08:58:40 +00001031
1032 public Object getAutoConfigInstance() {
1033 return lookupService();
1034 }
1035
1036 public Class getAutoConfigType() {
1037 return getInterface();
1038 }
Marcel Offermansa962bc92009-11-21 17:59:33 +00001039
1040 public String getName() {
1041 StringBuilder sb = new StringBuilder();
Marcel Offermansb1959f42010-07-01 12:23:51 +00001042 if (m_trackedServiceName != null) {
1043 sb.append(m_trackedServiceName.getName());
1044 if (m_trackedServiceFilterUnmodified != null) {
1045 sb.append(' ');
1046 sb.append(m_trackedServiceFilterUnmodified);
1047 }
1048 }
1049 if (m_trackedServiceReference != null) {
Marcel Offermans9e50ef32010-10-07 11:37:00 +00001050 sb.append("{service.id=" + m_trackedServiceReference.getProperty(Constants.SERVICE_ID)+"}");
Marcel Offermansa962bc92009-11-21 17:59:33 +00001051 }
1052 return sb.toString();
1053 }
1054
Marcel Offermansa962bc92009-11-21 17:59:33 +00001055 public String getType() {
1056 return "service";
1057 }
Marcel Offermans001db052009-12-08 08:58:40 +00001058
1059 public void invokeAdded(DependencyService service) {
Marcel Offermansbde9a432010-05-11 08:01:28 +00001060 ServiceReference[] refs = m_tracker.getServiceReferences();
1061 if (refs != null) {
1062 for (int i = 0; i < refs.length; i++) {
1063 ServiceReference sr = refs[i];
1064 Object svc = m_context.getService(sr);
1065 invokeAdded(service, sr, svc);
1066 }
1067 }
Marcel Offermans001db052009-12-08 08:58:40 +00001068 }
Marcel Offermansbde9a432010-05-11 08:01:28 +00001069
Marcel Offermans001db052009-12-08 08:58:40 +00001070 public void invokeRemoved(DependencyService service) {
Marcel Offermanse7baff52010-12-17 08:51:52 +00001071 Set references = null;
1072 synchronized (m_sr) {
1073 references = (Set) m_sr.get(service);
1074 }
Marcel Offermans7784e402011-01-21 20:41:50 +00001075 Tuple[] refs = (Tuple[]) (references != null ? references.toArray(new Tuple[references.size()]) : new Tuple[0]);
Marcel Offermans09e14aa2010-11-25 13:36:23 +00001076
1077 for (int i = 0; i < refs.length; i++) {
Marcel Offermans7784e402011-01-21 20:41:50 +00001078 ServiceReference sr = refs[i].getServiceReference();
1079 Object svc = refs[i].getService();
Marcel Offermans09e14aa2010-11-25 13:36:23 +00001080 invokeRemoved(service, sr, svc);
Marcel Offermansbde9a432010-05-11 08:01:28 +00001081 }
Marcel Offermans09e14aa2010-11-25 13:36:23 +00001082 if (references != null) {
1083 references.clear();
1084 }
Marcel Offermans001db052009-12-08 08:58:40 +00001085 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +00001086
1087 public Dictionary getProperties() {
Marcel Offermans26081d32010-07-12 12:43:42 +00001088 ServiceReference reference = lookupServiceReference();
1089 Object service = lookupService();
1090 if (reference != null) {
1091 if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
1092 try {
1093 return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ ServiceReference.class, Object.class }, { ServiceReference.class }}, new Object[][] {{ reference, service }, { reference }});
1094 }
1095 catch (InvocationTargetException e) {
1096 m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
1097 }
1098 catch (Exception e) {
1099 m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
1100 }
1101 throw new IllegalStateException("Could not invoke callback");
1102 }
1103 else {
1104 Properties props = new Properties();
1105 String[] keys = reference.getPropertyKeys();
1106 for (int i = 0; i < keys.length; i++) {
1107 if (!(keys[i].equals(Constants.SERVICE_ID) || keys[i].equals(Constants.SERVICE_PID))) {
1108 props.put(keys[i], reference.getProperty(keys[i]));
1109 }
1110 }
1111 return props;
1112 }
1113 }
1114 else {
1115 throw new IllegalStateException("cannot find service reference");
1116 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +00001117 }
1118
1119 public boolean isPropagated() {
Marcel Offermans26081d32010-07-12 12:43:42 +00001120 return m_propagate;
1121 }
1122
1123 public ServiceDependency setPropagate(boolean propagate) {
1124 ensureNotActive();
1125 m_propagate = propagate;
1126 return this;
1127 }
1128
1129 public ServiceDependency setPropagate(Object instance, String method) {
1130 setPropagate(instance != null && method != null);
1131 m_propagateCallbackInstance = instance;
1132 m_propagateCallbackMethod = method;
1133 return this;
Marcel Offermans117aa2f2009-12-10 09:48:17 +00001134 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +00001135
Marcel Offermansa962bc92009-11-21 17:59:33 +00001136}