blob: 4d2f769012c96a6267e9247affc69ae3df7f4476 [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;
68 private volatile boolean m_isStarted;
69 private Object m_callbackInstance;
70 private String m_callbackAdded;
71 private String m_callbackChanged;
72 private String m_callbackRemoved;
Marcel Offermans7f0cec02011-11-04 13:39:28 +000073 private String m_callbackSwapped;
Marcel Offermansa962bc92009-11-21 17:59:33 +000074 private boolean m_autoConfig;
Marcel Offermans74363c32009-11-23 19:56:08 +000075 protected ServiceReference m_reference;
76 protected Object m_serviceInstance;
Marcel Offermansa962bc92009-11-21 17:59:33 +000077 private String m_autoConfigInstance;
78 private boolean m_autoConfigInvoked;
79 private Object m_defaultImplementation;
80 private Object m_defaultImplementationInstance;
Marcel Offermansb196d722009-11-26 17:12:12 +000081 private boolean m_isAvailable;
Marcel Offermans26081d32010-07-12 12:43:42 +000082 private boolean m_propagate;
83 private Object m_propagateCallbackInstance;
84 private String m_propagateCallbackMethod;
Marcel Offermans7784e402011-01-21 20:41:50 +000085 private final Map m_sr = new HashMap(); /* <DependencyService, Set<Tuple<ServiceReference, Object>> */
Marcel Offermans7f0cec02011-11-04 13:39:28 +000086 private Map m_componentByRank = new HashMap(); /* <Component, Map<Long, Map<Integer, Tuple>>> */
Marcel Offermansa962bc92009-11-21 17:59:33 +000087
88 private static final Comparator COMPARATOR = new Comparator() {
89 public int getRank(ServiceReference ref) {
90 Object ranking = ref.getProperty(Constants.SERVICE_RANKING);
91 if (ranking != null && (ranking instanceof Integer)) {
92 return ((Integer) ranking).intValue();
93 }
94 return 0;
95 }
96
97 public int compare(Object a, Object b) {
98 ServiceReference ra = (ServiceReference) a, rb = (ServiceReference) b;
99 int ranka = getRank(ra);
100 int rankb = getRank(rb);
101 if (ranka < rankb) {
102 return -1;
103 }
104 else if (ranka > rankb) {
105 return 1;
106 }
107 return 0;
108 }
109 };
110
Marcel Offermans7784e402011-01-21 20:41:50 +0000111 private static final class Tuple /* <ServiceReference, Object> */ {
112 private final ServiceReference m_serviceReference;
113 private final Object m_service;
114
115 public Tuple(ServiceReference first, Object last) {
116 m_serviceReference = first;
117 m_service = last;
118 }
119
120 public ServiceReference getServiceReference() {
121 return m_serviceReference;
122 }
123
124 public Object getService() {
125 return m_service;
126 }
127
128 public boolean equals(Object obj) {
129 return ((Tuple) obj).getServiceReference().equals(getServiceReference());
130 }
131
132 public int hashCode() {
133 return m_serviceReference.hashCode();
134 }
135 }
136
Marcel Offermansa962bc92009-11-21 17:59:33 +0000137 /**
138 * Entry to wrap service properties behind a Map.
139 */
Marcel Offermans7784e402011-01-21 20:41:50 +0000140 private static final class ServicePropertiesMapEntry implements Map.Entry {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000141 private final String m_key;
142 private Object m_value;
143
144 public ServicePropertiesMapEntry(String key, Object value) {
145 m_key = key;
146 m_value = value;
147 }
148
149 public Object getKey() {
150 return m_key;
151 }
152
153 public Object getValue() {
154 return m_value;
155 }
156
157 public String toString() {
158 return m_key + "=" + m_value;
159 }
160
161 public Object setValue(Object value) {
162 Object oldValue = m_value;
163 m_value = value;
164 return oldValue;
165 }
166
167 public boolean equals(Object o) {
168 if (!(o instanceof Map.Entry)) {
169 return false;
170 }
171 Map.Entry e = (Map.Entry) o;
172 return eq(m_key, e.getKey()) && eq(m_value, e.getValue());
173 }
174
175 public int hashCode() {
176 return ((m_key == null) ? 0 : m_key.hashCode()) ^ ((m_value == null) ? 0 : m_value.hashCode());
177 }
178
179 private static final boolean eq(Object o1, Object o2) {
180 return (o1 == null ? o2 == null : o1.equals(o2));
181 }
182 }
183
184 /**
185 * Wraps service properties behind a Map.
186 */
187 private final static class ServicePropertiesMap extends AbstractMap {
188 private final ServiceReference m_ref;
189
190 public ServicePropertiesMap(ServiceReference ref) {
191 m_ref = ref;
192 }
193
194 public Object get(Object key) {
195 return m_ref.getProperty(key.toString());
196 }
197
198 public int size() {
199 return m_ref.getPropertyKeys().length;
200 }
201
202 public Set entrySet() {
203 Set set = new HashSet();
204 String[] keys = m_ref.getPropertyKeys();
205 for (int i = 0; i < keys.length; i++) {
206 set.add(new ServicePropertiesMapEntry(keys[i], m_ref.getProperty(keys[i])));
207 }
208 return set;
209 }
210 }
211
212 /**
213 * Creates a new service dependency.
214 *
215 * @param context the bundle context
216 * @param logger the logger
217 */
Pierre De Ropaacb3aa2009-12-04 22:53:23 +0000218 public ServiceDependencyImpl(BundleContext context, Logger logger) {
Marcel Offermansb196d722009-11-26 17:12:12 +0000219 super(logger);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000220 m_context = context;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000221 m_autoConfig = true;
222 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000223
Marcel Offermansb1959f42010-07-01 12:23:51 +0000224 /** Copying constructor that clones an existing instance. */
225 public ServiceDependencyImpl(ServiceDependencyImpl prototype) {
226 super(prototype);
Marcel Offermanse7baff52010-12-17 08:51:52 +0000227 synchronized (prototype) {
228 m_context = prototype.m_context;
229 m_autoConfig = prototype.m_autoConfig;
230 m_trackedServiceName = prototype.m_trackedServiceName;
231 m_nullObject = prototype.m_nullObject;
232 m_trackedServiceFilter = prototype.m_trackedServiceFilter;
233 m_trackedServiceFilterUnmodified = prototype.m_trackedServiceFilterUnmodified;
234 m_trackedServiceReference = prototype.m_trackedServiceReference;
235 m_callbackInstance = prototype.m_callbackInstance;
236 m_callbackAdded = prototype.m_callbackAdded;
237 m_callbackChanged = prototype.m_callbackChanged;
238 m_callbackRemoved = prototype.m_callbackRemoved;
239 m_autoConfigInstance = prototype.m_autoConfigInstance;
240 m_defaultImplementation = prototype.m_defaultImplementation;
241 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000242 }
243
244 public Dependency createCopy() {
245 return new ServiceDependencyImpl(this);
246 }
247
Marcel Offermansa962bc92009-11-21 17:59:33 +0000248 public synchronized boolean isAutoConfig() {
249 return m_autoConfig;
250 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000251
Marcel Offermansb196d722009-11-26 17:12:12 +0000252 public synchronized boolean isAvailable() {
253 return m_isAvailable;
254 }
255
Marcel Offermansa962bc92009-11-21 17:59:33 +0000256 public synchronized Object getService() {
257 Object service = null;
258 if (m_isStarted) {
259 service = m_tracker.getService();
260 }
Marcel Offermans001db052009-12-08 08:58:40 +0000261 if (service == null && isAutoConfig()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000262 service = getDefaultImplementation();
263 if (service == null) {
264 service = getNullObject();
265 }
266 }
267 return service;
268 }
269
270 public Object lookupService() {
271 Object service = null;
272 if (m_isStarted) {
Marcel Offermans001db052009-12-08 08:58:40 +0000273 service = getService();
Marcel Offermansa962bc92009-11-21 17:59:33 +0000274 }
275 else {
276 ServiceReference[] refs = null;
277 ServiceReference ref = null;
278 if (m_trackedServiceName != null) {
279 if (m_trackedServiceFilter != null) {
280 try {
281 refs = m_context.getServiceReferences(m_trackedServiceName.getName(), m_trackedServiceFilter);
282 if (refs != null) {
283 Arrays.sort(refs, COMPARATOR);
284 ref = refs[0];
285 }
286 }
287 catch (InvalidSyntaxException e) {
288 throw new IllegalStateException("Invalid filter definition for dependency.");
289 }
290 }
291 else if (m_trackedServiceReference != null) {
292 ref = m_trackedServiceReference;
293 }
294 else {
295 ref = m_context.getServiceReference(m_trackedServiceName.getName());
296 }
297 if (ref != null) {
298 service = m_context.getService(ref);
299 }
300 }
301 else {
302 throw new IllegalStateException("Could not lookup dependency, no service name specified.");
303 }
304 }
Marcel Offermans001db052009-12-08 08:58:40 +0000305 if (service == null && isAutoConfig()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000306 service = getDefaultImplementation();
307 if (service == null) {
308 service = getNullObject();
309 }
310 }
311 return service;
312 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000313
Marcel Offermanse14b3422009-11-25 23:04:32 +0000314 // TODO lots of duplication in lookupService()
315 public ServiceReference lookupServiceReference() {
316 ServiceReference service = null;
317 if (m_isStarted) {
318 service = m_tracker.getServiceReference();
319 }
320 else {
321 ServiceReference[] refs = null;
322 ServiceReference ref = null;
323 if (m_trackedServiceName != null) {
324 if (m_trackedServiceFilter != null) {
325 try {
326 refs = m_context.getServiceReferences(m_trackedServiceName.getName(), m_trackedServiceFilter);
327 if (refs != null) {
328 Arrays.sort(refs, COMPARATOR);
329 ref = refs[0];
330 }
331 }
332 catch (InvalidSyntaxException e) {
333 throw new IllegalStateException("Invalid filter definition for dependency.");
334 }
335 }
336 else if (m_trackedServiceReference != null) {
337 ref = m_trackedServiceReference;
338 }
339 else {
340 ref = m_context.getServiceReference(m_trackedServiceName.getName());
341 }
342 if (ref != null) {
343 service = ref;
344 }
345 }
346 else {
347 throw new IllegalStateException("Could not lookup dependency, no service name specified.");
348 }
349 }
350 return service;
351 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000352
353 private Object getNullObject() {
354 if (m_nullObject == null) {
355 Class trackedServiceName;
356 synchronized (this) {
357 trackedServiceName = m_trackedServiceName;
358 }
359 try {
360 m_nullObject = Proxy.newProxyInstance(trackedServiceName.getClassLoader(), new Class[] {trackedServiceName}, new DefaultNullObject());
361 }
362 catch (Exception e) {
363 m_logger.log(Logger.LOG_ERROR, "Could not create null object for " + trackedServiceName + ".", e);
364 }
365 }
366 return m_nullObject;
367 }
368
369 private Object getDefaultImplementation() {
370 if (m_defaultImplementation != null) {
371 if (m_defaultImplementation instanceof Class) {
372 try {
373 m_defaultImplementationInstance = ((Class) m_defaultImplementation).newInstance();
374 }
375 catch (Exception e) {
376 m_logger.log(Logger.LOG_ERROR, "Could not create default implementation instance of class " + m_defaultImplementation + ".", e);
377 }
378 }
379 else {
380 m_defaultImplementationInstance = m_defaultImplementation;
381 }
382 }
383 return m_defaultImplementationInstance;
384 }
385
386 public synchronized Class getInterface() {
387 return m_trackedServiceName;
388 }
389
Marcel Offermanse14b3422009-11-25 23:04:32 +0000390 public void start(DependencyService service) {
391 boolean needsStarting = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000392 synchronized (this) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000393 m_services.add(service);
394 if (!m_isStarted) {
395 if (m_trackedServiceName != null) {
396 if (m_trackedServiceFilter != null) {
397 try {
398 m_tracker = new ServiceTracker(m_context, m_context.createFilter(m_trackedServiceFilter), this);
399 }
400 catch (InvalidSyntaxException e) {
Marcel Offermansad760672010-03-03 15:30:01 +0000401 throw new IllegalStateException("Invalid filter definition for dependency: " + m_trackedServiceFilter);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000402 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000403 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000404 else if (m_trackedServiceReference != null) {
405 m_tracker = new ServiceTracker(m_context, m_trackedServiceReference, this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000406 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000407 else {
408 m_tracker = new ServiceTracker(m_context, m_trackedServiceName.getName(), this);
409 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000410 }
411 else {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000412 throw new IllegalStateException("Could not create tracker for dependency, no service name specified.");
Marcel Offermansa962bc92009-11-21 17:59:33 +0000413 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000414 m_isStarted = true;
415 needsStarting = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000416 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000417 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000418 if (needsStarting) {
419 m_tracker.open();
420 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000421 }
422
Marcel Offermanse14b3422009-11-25 23:04:32 +0000423 public void stop(DependencyService service) {
424 boolean needsStopping = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000425 synchronized (this) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000426 if (m_services.size() == 1 && m_services.contains(service)) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000427 m_isStarted = false;
428 needsStopping = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000429 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000430 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000431 if (needsStopping) {
432 m_tracker.close();
433 m_tracker = null;
434 }
Marcel Offermans1c944ec2010-10-11 13:55:02 +0000435 //moved this down
436 synchronized (this) {
437 m_services.remove(service);
438 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000439 }
440
441 public Object addingService(ServiceReference ref) {
442 Object service = m_context.getService(ref);
443 // first check to make sure the service is actually an instance of our service
444 if (!m_trackedServiceName.isInstance(service)) {
445 return null;
446 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000447 return service;
448 }
449
450 public void addedService(ServiceReference ref, Object service) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000451 boolean makeAvailable = makeAvailable();
452
Marcel Offermans203bdad2009-12-04 09:23:04 +0000453 Object[] services;
454 synchronized (this) {
455 services = m_services.toArray();
456 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000457 for (int i = 0; i < services.length; i++) {
458 DependencyService ds = (DependencyService) services[i];
459 if (makeAvailable) {
Marcel Offermansfea14842010-10-14 14:45:36 +0000460 if (ds.isInstantiated() && isInstanceBound() && isRequired()) {
461 invokeAdded(ds, ref, service);
462 }
Pierre De Rop1785c332010-06-11 06:03:53 +0000463 // The dependency callback will be defered until all required dependency are available.
464 ds.dependencyAvailable(this);
465 if (!isRequired()) {
466 // For optional dependency, we always invoke callback, because at this point, we know
467 // that the service has been started, and the service start method has been called.
468 // (See the ServiceImpl.bindService method, which will activate optional dependencies using
469 // startTrackingOptional() method).
Marcel Offermanse14b3422009-11-25 23:04:32 +0000470 invokeAdded(ds, ref, service);
471 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000472 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000473 else {
474 ds.dependencyChanged(this);
Pierre De Rop1785c332010-06-11 06:03:53 +0000475 // At this point, either the dependency is optional (meaning that the service has been started,
476 // because if not, then our dependency would not be active); or the dependency is required,
477 // meaning that either the service is not yet started, or already started.
478 // In all cases, we have to inject the required dependency.
Marcel Offermans09e14aa2010-11-25 13:36:23 +0000479
480 // we only try to invoke the method here if we are really already instantiated
481 if (ds.isInstantiated() && ds.getCompositionInstances().length > 0) {
482 invokeAdded(ds, ref, service);
483 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000484 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000485 }
486 }
487
Marcel Offermansa962bc92009-11-21 17:59:33 +0000488 public void modifiedService(ServiceReference ref, Object service) {
Marcel Offermans203bdad2009-12-04 09:23:04 +0000489 Object[] services;
490 synchronized (this) {
491 services = m_services.toArray();
492 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000493 for (int i = 0; i < services.length; i++) {
494 DependencyService ds = (DependencyService) services[i];
495 ds.dependencyChanged(this);
496 if (ds.isRegistered()) {
497 invokeChanged(ds, ref, service);
498 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000499 }
500 }
501
Marcel Offermansa962bc92009-11-21 17:59:33 +0000502 public void removedService(ServiceReference ref, Object service) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000503 boolean makeUnavailable = makeUnavailable();
504
Marcel Offermans203bdad2009-12-04 09:23:04 +0000505 Object[] services;
506 synchronized (this) {
507 services = m_services.toArray();
508 }
Marcel Offermans1c944ec2010-10-11 13:55:02 +0000509
Marcel Offermanse14b3422009-11-25 23:04:32 +0000510 for (int i = 0; i < services.length; i++) {
511 DependencyService ds = (DependencyService) services[i];
512 if (makeUnavailable) {
513 ds.dependencyUnavailable(this);
Marcel Offermansfea14842010-10-14 14:45:36 +0000514 if (!isRequired() || (ds.isInstantiated() && isInstanceBound())) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000515 invokeRemoved(ds, ref, service);
516 }
517 }
518 else {
519 ds.dependencyChanged(this);
520 invokeRemoved(ds, ref, service);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000521 }
522 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000523 // unget what we got in addingService (see ServiceTracker 701.4.1)
524 m_context.ungetService(ref);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000525
Marcel Offermansa962bc92009-11-21 17:59:33 +0000526 }
Marcel Offermans09e14aa2010-11-25 13:36:23 +0000527
Marcel Offermansea89b862010-06-24 13:14:43 +0000528 public void invokeAdded(DependencyService dependencyService, ServiceReference reference, Object service) {
Marcel Offermanse7baff52010-12-17 08:51:52 +0000529 boolean added = false;
530 synchronized (m_sr) {
531 Set set = (Set) m_sr.get(dependencyService);
532 if (set == null) {
533 set = new HashSet();
534 m_sr.put(dependencyService, set);
535 }
Marcel Offermans7784e402011-01-21 20:41:50 +0000536 added = set.add(new Tuple(reference, service));
Marcel Offermans09e14aa2010-11-25 13:36:23 +0000537 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000538 if (added) {
539 // when a changed callback is specified we might not call the added callback just yet
540 if (m_callbackSwapped != null) {
541 handleAspectAwareAdded(dependencyService, reference, service);
542 } else {
543 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) {
557 // TODO would be nicer if there was a ServiceUtil method for this...
558 Long originalServiceId = ServiceUtil.getServiceIdAsLong(reference);
559 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
560 if (componentMap == null) {
561 // create new componentMap
562 componentMap = new HashMap(); /* <Long, Map<Integer, Tuple>> */
563 m_componentByRank.put(dependencyService, componentMap);
564 }
565 Map rankings = (Map) componentMap.get(originalServiceId); /* <Integer, Tuple> */
566 if (rankings == null) {
567 // new component added
568 rankings = new HashMap(); /* <Integer, Tuple> */
569 componentMap.put(originalServiceId, rankings);
570 rankings.put(ranking, new Tuple(reference, service));
571 invokeAdded = true;
572 }
573
574 if (!invokeAdded) {
575 highestRankedService = swapHighestRankedService(dependencyService, originalServiceId, reference, service, ranking);
576 }
577 }
578 if (invokeAdded) {
579 invoke(dependencyService, reference, service, m_callbackAdded);
580 } else {
581 invokeSwappedCallback(dependencyService, highestRankedService.getServiceReference(), highestRankedService.getService(), reference, service);
582 }
583 }
584
585 private boolean componentIsDependencyManagerFactory(DependencyService dependencyService) {
586 // TODO review if we can be a bit smarter with these package name checks
587 return dependencyService.getService() != null && dependencyService.getService().getClass().getName().startsWith("org.apache.felix.dm")
588 && !dependencyService.getService().getClass().getName().startsWith("org.apache.felix.dm.test");
589 }
590
591 private Tuple swapHighestRankedService(DependencyService dependencyService, Long serviceId, ServiceReference newReference, Object newService, Integer newRanking) {
592 // does a component with a higher ranking exists
593 synchronized (m_componentByRank) {
594 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
595 Map rankings = (Map) componentMap.get(serviceId); /* <Integer, Tuple> */
596 Entry highestEntry = getHighestRankedService(dependencyService, serviceId); /* <Integer, Tuple> */
597 rankings.remove(highestEntry.getKey());
598 rankings.put(newRanking, new Tuple(newReference, newService));
599 return (Tuple) highestEntry.getValue();
600 }
601 }
602
603 private Entry getHighestRankedService(DependencyService dependencyService, Long serviceId) { /* <Integer, Tuple> */
604 Entry highestEntry = null; /* <Integer, Tuple> */
605 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
606 Map rankings = (Map) componentMap.get(serviceId); /* <Integer, Tuple> */
607 if (rankings != null) {
608 for (Iterator entryIterator = rankings.entrySet().iterator(); entryIterator.hasNext(); ) { /* <Integer, Tuple> */
609 Entry mapEntry = (Entry) entryIterator.next();
610 if (highestEntry == null) {
611 highestEntry = mapEntry;
612 } else {
613 if (((Integer)mapEntry.getKey()).intValue() > ((Integer)highestEntry.getKey()).intValue()) {
614 highestEntry = mapEntry;
615 }
616 }
617 }
618 }
619 return highestEntry;
620 }
621
622
623
624 private boolean isLastService(DependencyService dependencyService, ServiceReference reference, Object object, Long serviceId) {
625 // get the collection of rankings
626 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
627
628 Map rankings = null; /* <Integer, Tuple> */
629 if (componentMap != null) {
630 rankings = (Map) componentMap.get(serviceId);
631 }
632 // if there is only one element left in the collection of rankings
633 // and this last element has the same ranking as the supplied service (in other words, it is the same)
634 // then this is the last service
635 // NOTE: it is possible that there is only one element, but that it's not equal to the supplied service,
636 // because an aspect on top of the original service is being removed (but the original service is still
637 // there). That in turn triggers:
638 // 1) a call to added(original-service)
639 // 2) that causes a swap
640 // 3) a call to removed(aspect-service) <-- that's what we're talking about
641 return (componentMap != null && rankings != null && rankings.size() == 1 && ((Entry)rankings.entrySet().iterator().next()).getKey()
642 .equals(ServiceUtil.getRankingAsInteger(reference)));
643 }
644
645
Marcel Offermansea89b862010-06-24 13:14:43 +0000646 public void invokeChanged(DependencyService dependencyService, ServiceReference reference, Object service) {
647 invoke(dependencyService, reference, service, m_callbackChanged);
648 }
649
Marcel Offermansb196d722009-11-26 17:12:12 +0000650 public void invokeRemoved(DependencyService dependencyService, ServiceReference reference, Object service) {
Marcel Offermanse7baff52010-12-17 08:51:52 +0000651 boolean removed = false;
652 synchronized (m_sr) {
653 Set set = (Set) m_sr.get(dependencyService);
Marcel Offermans7784e402011-01-21 20:41:50 +0000654 removed = (set != null && set.remove(new Tuple(reference, service)));
Marcel Offermanse7baff52010-12-17 08:51:52 +0000655 }
656 if (removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000657 if (m_callbackSwapped != null) {
658 handleAspectAwareRemoved(dependencyService, reference, service);
659 } else {
660 invoke(dependencyService, reference, service, m_callbackRemoved);
661 }
Marcel Offermans09e14aa2010-11-25 13:36:23 +0000662 }
Marcel Offermansea89b862010-06-24 13:14:43 +0000663 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000664
665 private void handleAspectAwareRemoved(DependencyService dependencyService, ServiceReference reference, Object service) {
666 if (componentIsDependencyManagerFactory(dependencyService)) {
667 // component is either aspect or adapter factory instance, these must be ignored.
668 return;
669 }
670 Long serviceId = ServiceUtil.getServiceIdAsLong(reference);
671 synchronized (m_componentByRank) {
672 if (isLastService(dependencyService, reference, service, serviceId)) {
673 invoke(dependencyService, reference, service, m_callbackRemoved);
674 }
675 Long originalServiceId = ServiceUtil.getServiceIdAsLong(reference);
676 Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
677 if (componentMap != null) {
678 Map rankings = (Map) componentMap.get(originalServiceId); /* <Integer, Tuple> */
679 for (Iterator entryIterator = rankings.entrySet().iterator(); entryIterator.hasNext(); ) {
680 Entry mapEntry = (Entry) entryIterator.next();
681 if (((Tuple)mapEntry.getValue()).getServiceReference().equals(reference)) {
682 // remove the reference
683 rankings.remove(mapEntry.getKey());
684 }
685 }
686 if (rankings.size() == 0) {
687 componentMap.remove(originalServiceId);
688 }
689 if (componentMap.size() == 0) {
690 m_componentByRank.remove(dependencyService);
691 }
692 }
693 }
694 }
Marcel Offermansea89b862010-06-24 13:14:43 +0000695
696 public void invoke(DependencyService dependencyService, ServiceReference reference, Object service, String name) {
697 if (name != null) {
698 dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name,
Marcel Offermans706fb272010-11-15 12:52:58 +0000699 new Class[][] {
700 {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},
701 {ServiceReference.class, m_trackedServiceName}, {ServiceReference.class, Object.class}, {ServiceReference.class}, {m_trackedServiceName}, {Object.class}, {}, {Map.class, m_trackedServiceName}
702 },
703 new Object[][] {
704 {dependencyService, reference, service}, {dependencyService, reference, service}, {dependencyService, reference}, {dependencyService, service}, {dependencyService, service}, {dependencyService}, {dependencyService, new ServicePropertiesMap(reference), service},
705 {reference, service}, {reference, service}, {reference}, {service}, {service}, {}, {new ServicePropertiesMap(reference), service}
706 }
Marcel Offermansb196d722009-11-26 17:12:12 +0000707 );
Marcel Offermansa962bc92009-11-21 17:59:33 +0000708 }
709 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000710
711 private void invokeSwappedCallback(DependencyService component, ServiceReference previousReference, Object previous, ServiceReference currentServiceReference,
712 Object current) {
713 component.invokeCallbackMethod(getCallbackInstances(component), m_callbackSwapped, new Class[][] { { m_trackedServiceName, m_trackedServiceName },
714 { Object.class, Object.class }, { ServiceReference.class, m_trackedServiceName, ServiceReference.class, m_trackedServiceName },
715 { ServiceReference.class, Object.class, ServiceReference.class, Object.class } }, new Object[][] { { previous, current },
716 { previous, current }, { previousReference, previous, currentServiceReference, current },
717 { previousReference, previous, currentServiceReference, current } });
718 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000719
Marcel Offermans74363c32009-11-23 19:56:08 +0000720 protected synchronized boolean makeAvailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000721 if (!isAvailable()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000722 m_isAvailable = true;
723 return true;
724 }
725 return false;
726 }
727
728 private synchronized boolean makeUnavailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000729 if ((isAvailable()) && (m_tracker.getServiceReference() == null)) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000730 m_isAvailable = false;
731 return true;
732 }
733 return false;
734 }
735
Marcel Offermanse14b3422009-11-25 23:04:32 +0000736 private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
737 if (m_callbackInstance == null) {
738 return dependencyService.getCompositionInstances();
739 }
740 else {
741 return new Object[] { m_callbackInstance };
742 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000743 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000744
745 // ----- CREATION
746
747 /**
748 * Sets the name of the service that should be tracked.
749 *
750 * @param serviceName the name of the service
751 * @return this service dependency
752 */
753 public synchronized ServiceDependency setService(Class serviceName) {
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000754 setService(serviceName, null, null);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000755 return this;
756 }
757
758 /**
759 * Sets the name of the service that should be tracked. You can either specify
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000760 * only the name, only the filter, or the name and a filter.
761 * <p>
762 * If you specify name and filter, the filter is used
Marcel Offermansa962bc92009-11-21 17:59:33 +0000763 * to track the service and should only return services of the type that was specified
764 * in the name. To make sure of this, the filter is actually extended internally to
765 * filter on the correct name.
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000766 * <p>
767 * If you specify only the filter, the name is assumed to be a service of type
768 * <code>Object</code> which means that, when auto configuration is on, instances
769 * of that service will be injected in any field of type <code>Object</code>.
Marcel Offermansa962bc92009-11-21 17:59:33 +0000770 *
771 * @param serviceName the name of the service
772 * @param serviceFilter the filter condition
773 * @return this service dependency
774 */
775 public synchronized ServiceDependency setService(Class serviceName, String serviceFilter) {
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000776 setService(serviceName, null, serviceFilter);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000777 return this;
778 }
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000779
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000780 /**
781 * Sets the name of the service that should be tracked. The name is assumed to be
782 * a service of type <code>Object</code> which means that, when auto configuration
783 * is on, instances of that service will be injected in any field of type
784 * <code>Object</code>.
785 *
786 * @param serviceFilter the filter condition
787 * @return this service dependency
788 */
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000789 public synchronized ServiceDependency setService(String serviceFilter) {
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000790 if (serviceFilter == null) {
791 throw new IllegalArgumentException("Service filter cannot be null.");
792 }
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000793 setService(null, null, serviceFilter);
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000794 return this;
795 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000796
797 /**
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000798 * Sets the name of the service that should be tracked. By specifying the service
799 * reference of the service you want to track, you can directly track a single
800 * service. The name you use must match the type of service referred to by the
801 * service reference and it is up to you to make sure that is the case.
Marcel Offermansa962bc92009-11-21 17:59:33 +0000802 *
803 * @param serviceName the name of the service
804 * @param serviceReference the service reference to track
805 * @return this service dependency
806 */
807 public synchronized ServiceDependency setService(Class serviceName, ServiceReference serviceReference) {
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000808 setService(serviceName, serviceReference, null);
809 return this;
810 }
811
812 /** Internal method to set the name, service reference and/or filter. */
813 private void setService(Class serviceName, ServiceReference serviceReference, String serviceFilter) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000814 ensureNotActive();
815 if (serviceName == null) {
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000816 m_trackedServiceName = Object.class;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000817 }
Marcel Offermans8a1fa512011-03-08 15:33:01 +0000818 else {
819 m_trackedServiceName = serviceName;
820 }
821 if (serviceFilter != null) {
822 m_trackedServiceFilterUnmodified = serviceFilter;
823 if (serviceName == null) {
824 m_trackedServiceFilter = serviceFilter;
825 }
826 else {
827 m_trackedServiceFilter ="(&(" + Constants.OBJECTCLASS + "=" + serviceName.getName() + ")" + serviceFilter + ")";
828 }
829 }
830 else {
831 m_trackedServiceFilterUnmodified = null;
832 m_trackedServiceFilter = null;
833 }
834 if (serviceReference != null) {
835 m_trackedServiceReference = serviceReference;
836 if (serviceFilter != null) {
837 throw new IllegalArgumentException("Cannot specify both a filter and a service reference.");
838 }
839 }
840 else {
841 m_trackedServiceReference = null;
842 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000843 }
844
845 /**
846 * Sets the default implementation for this service dependency. You can use this to supply
847 * your own implementation that will be used instead of a Null Object when the dependency is
848 * not available. This is also convenient if the service dependency is not an interface
849 * (which would cause the Null Object creation to fail) but a class.
850 *
851 * @param implementation the instance to use or the class to instantiate if you want to lazily
852 * instantiate this implementation
853 * @return this service dependency
854 */
855 public synchronized ServiceDependency setDefaultImplementation(Object implementation) {
856 ensureNotActive();
857 m_defaultImplementation = implementation;
858 return this;
859 }
860
861 /**
862 * Sets the required flag which determines if this service is required or not.
863 *
864 * @param required the required flag
865 * @return this service dependency
866 */
867 public synchronized ServiceDependency setRequired(boolean required) {
868 ensureNotActive();
Marcel Offermansb196d722009-11-26 17:12:12 +0000869 setIsRequired(required);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000870 return this;
871 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000872
873 public ServiceDependency setInstanceBound(boolean isInstanceBound) {
Marcel Offermans61a81142010-04-02 15:16:50 +0000874 setIsInstanceBound(isInstanceBound);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000875 return this;
876 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000877
878 /**
879 * Sets auto configuration for this service. Auto configuration allows the
880 * dependency to fill in any attributes in the service implementation that
881 * are of the same type as this dependency. Default is on.
882 *
883 * @param autoConfig the value of auto config
884 * @return this service dependency
885 */
886 public synchronized ServiceDependency setAutoConfig(boolean autoConfig) {
887 ensureNotActive();
888 m_autoConfig = autoConfig;
889 m_autoConfigInvoked = true;
890 return this;
891 }
892
893 /**
894 * Sets auto configuration for this service. Auto configuration allows the
895 * dependency to fill in the attribute in the service implementation that
896 * has the same type and instance name.
897 *
898 * @param instanceName the name of attribute to auto config
899 * @return this service dependency
900 */
901 public synchronized ServiceDependency setAutoConfig(String instanceName) {
902 ensureNotActive();
903 m_autoConfig = (instanceName != null);
904 m_autoConfigInstance = instanceName;
905 m_autoConfigInvoked = true;
906 return this;
907 }
908
909 /**
910 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
911 * dependency is added or removed. When you specify callbacks, the auto configuration
912 * feature is automatically turned off, because we're assuming you don't need it in this
913 * case.
914 *
915 * @param added the method to call when a service was added
916 * @param removed the method to call when a service was removed
917 * @return this service dependency
918 */
919 public synchronized ServiceDependency setCallbacks(String added, String removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000920 return setCallbacks((Object) null, added, null, removed);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000921 }
922
923 /**
924 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
925 * dependency is added, changed or removed. When you specify callbacks, the auto
926 * configuration feature is automatically turned off, because we're assuming you don't
927 * need it in this case.
928 *
929 * @param added the method to call when a service was added
930 * @param changed the method to call when a service was changed
931 * @param removed the method to call when a service was removed
932 * @return this service dependency
933 */
934 public synchronized ServiceDependency setCallbacks(String added, String changed, String removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000935 return setCallbacks((Object) null, added, changed, removed);
936 }
937
938 /**
939 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
940 * dependency is added, changed or removed. When you specify callbacks, the auto
941 * configuration feature is automatically turned off, because we're assuming you don't
942 * need it in this case.
943 * @param added the method to call when a service was added
944 * @param changed the method to call when a service was changed
945 * @param removed the method to call when a service was removed
946 * @param swapped the method to call when the service was swapped due to addition or
947 * removal of an aspect
948 * @return this service dependency
949 */
950 public synchronized ServiceDependency setCallbacks(String added, String changed, String removed, String swapped) {
951 return setCallbacks((Object) null, added, changed, removed, swapped);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000952 }
953
954 /**
955 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
956 * dependency is added or removed. They are called on the instance you provide. When you
957 * specify callbacks, the auto configuration feature is automatically turned off, because
958 * we're assuming you don't need it in this case.
959 *
960 * @param instance the instance to call the callbacks on
961 * @param added the method to call when a service was added
962 * @param removed the method to call when a service was removed
963 * @return this service dependency
964 */
965 public synchronized ServiceDependency setCallbacks(Object instance, String added, String removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000966 return setCallbacks(instance, added, (String) null, removed);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000967 }
968
969 /**
970 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
971 * dependency is added, changed or removed. They are called on the instance you provide. When you
972 * specify callbacks, the auto configuration feature is automatically turned off, because
973 * we're assuming you don't need it in this case.
974 *
975 * @param instance the instance to call the callbacks on
976 * @param added the method to call when a service was added
977 * @param changed the method to call when a service was changed
978 * @param removed the method to call when a service was removed
979 * @return this service dependency
980 */
981 public synchronized ServiceDependency setCallbacks(Object instance, String added, String changed, String removed) {
Marcel Offermans7f0cec02011-11-04 13:39:28 +0000982 return setCallbacks(instance, added, changed, removed, null);
983 }
984
985 /**
986 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
987 * dependency is added, changed or removed. When you specify callbacks, the auto
988 * configuration feature is automatically turned off, because we're assuming you don't
989 * need it in this case.
990 * @param instance the instance to call the callbacks on
991 * @param added the method to call when a service was added
992 * @param changed the method to call when a service was changed
993 * @param removed the method to call when a service was removed
994 * @param swapped the method to call when the service was swapped due to addition or
995 * removal of an aspect
996 * @return this service dependency
997 */
998 public synchronized ServiceDependency setCallbacks(Object instance, String added, String changed, String removed, String swapped) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000999 ensureNotActive();
1000 // if at least one valid callback is specified, we turn off auto configuration, unless
1001 // someone already explicitly invoked autoConfig
Marcel Offermans7f0cec02011-11-04 13:39:28 +00001002 if ((added != null || removed != null || changed != null || swapped != null) && ! m_autoConfigInvoked) {
Marcel Offermansa962bc92009-11-21 17:59:33 +00001003 setAutoConfig(false);
1004 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +00001005 m_callbackInstance = instance;
Marcel Offermansa962bc92009-11-21 17:59:33 +00001006 m_callbackAdded = added;
1007 m_callbackChanged = changed;
Marcel Offermans7f0cec02011-11-04 13:39:28 +00001008 m_callbackRemoved = removed;
1009 m_callbackSwapped = swapped;
1010 return this;
Marcel Offermansa962bc92009-11-21 17:59:33 +00001011 }
1012
1013 private void ensureNotActive() {
1014 if (m_tracker != null) {
1015 throw new IllegalStateException("Cannot modify state while active.");
1016 }
1017 }
1018
1019 public synchronized String toString() {
1020 return "ServiceDependency[" + m_trackedServiceName + " " + m_trackedServiceFilterUnmodified + "]";
1021 }
1022
1023 public String getAutoConfigName() {
1024 return m_autoConfigInstance;
1025 }
Marcel Offermans001db052009-12-08 08:58:40 +00001026
1027 public Object getAutoConfigInstance() {
1028 return lookupService();
1029 }
1030
1031 public Class getAutoConfigType() {
1032 return getInterface();
1033 }
Marcel Offermansa962bc92009-11-21 17:59:33 +00001034
1035 public String getName() {
1036 StringBuilder sb = new StringBuilder();
Marcel Offermansb1959f42010-07-01 12:23:51 +00001037 if (m_trackedServiceName != null) {
1038 sb.append(m_trackedServiceName.getName());
1039 if (m_trackedServiceFilterUnmodified != null) {
1040 sb.append(' ');
1041 sb.append(m_trackedServiceFilterUnmodified);
1042 }
1043 }
1044 if (m_trackedServiceReference != null) {
Marcel Offermans9e50ef32010-10-07 11:37:00 +00001045 sb.append("{service.id=" + m_trackedServiceReference.getProperty(Constants.SERVICE_ID)+"}");
Marcel Offermansa962bc92009-11-21 17:59:33 +00001046 }
1047 return sb.toString();
1048 }
1049
1050 public int getState() {
1051 return (isAvailable() ? 1 : 0) + (isRequired() ? 2 : 0);
1052 }
1053
1054 public String getType() {
1055 return "service";
1056 }
Marcel Offermans001db052009-12-08 08:58:40 +00001057
1058 public void invokeAdded(DependencyService service) {
Marcel Offermansbde9a432010-05-11 08:01:28 +00001059 ServiceReference[] refs = m_tracker.getServiceReferences();
1060 if (refs != null) {
1061 for (int i = 0; i < refs.length; i++) {
1062 ServiceReference sr = refs[i];
1063 Object svc = m_context.getService(sr);
1064 invokeAdded(service, sr, svc);
1065 }
1066 }
Marcel Offermans001db052009-12-08 08:58:40 +00001067 }
Marcel Offermansbde9a432010-05-11 08:01:28 +00001068
Marcel Offermans001db052009-12-08 08:58:40 +00001069 public void invokeRemoved(DependencyService service) {
Marcel Offermanse7baff52010-12-17 08:51:52 +00001070 Set references = null;
1071 synchronized (m_sr) {
1072 references = (Set) m_sr.get(service);
1073 }
Marcel Offermans7784e402011-01-21 20:41:50 +00001074 Tuple[] refs = (Tuple[]) (references != null ? references.toArray(new Tuple[references.size()]) : new Tuple[0]);
Marcel Offermans09e14aa2010-11-25 13:36:23 +00001075
1076 for (int i = 0; i < refs.length; i++) {
Marcel Offermans7784e402011-01-21 20:41:50 +00001077 ServiceReference sr = refs[i].getServiceReference();
1078 Object svc = refs[i].getService();
Marcel Offermans09e14aa2010-11-25 13:36:23 +00001079 invokeRemoved(service, sr, svc);
Marcel Offermansbde9a432010-05-11 08:01:28 +00001080 }
Marcel Offermans09e14aa2010-11-25 13:36:23 +00001081 if (references != null) {
1082 references.clear();
1083 }
Marcel Offermans001db052009-12-08 08:58:40 +00001084 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +00001085
1086 public Dictionary getProperties() {
Marcel Offermans26081d32010-07-12 12:43:42 +00001087 ServiceReference reference = lookupServiceReference();
1088 Object service = lookupService();
1089 if (reference != null) {
1090 if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
1091 try {
1092 return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ ServiceReference.class, Object.class }, { ServiceReference.class }}, new Object[][] {{ reference, service }, { reference }});
1093 }
1094 catch (InvocationTargetException e) {
1095 m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
1096 }
1097 catch (Exception e) {
1098 m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
1099 }
1100 throw new IllegalStateException("Could not invoke callback");
1101 }
1102 else {
1103 Properties props = new Properties();
1104 String[] keys = reference.getPropertyKeys();
1105 for (int i = 0; i < keys.length; i++) {
1106 if (!(keys[i].equals(Constants.SERVICE_ID) || keys[i].equals(Constants.SERVICE_PID))) {
1107 props.put(keys[i], reference.getProperty(keys[i]));
1108 }
1109 }
1110 return props;
1111 }
1112 }
1113 else {
1114 throw new IllegalStateException("cannot find service reference");
1115 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +00001116 }
1117
1118 public boolean isPropagated() {
Marcel Offermans26081d32010-07-12 12:43:42 +00001119 return m_propagate;
1120 }
1121
1122 public ServiceDependency setPropagate(boolean propagate) {
1123 ensureNotActive();
1124 m_propagate = propagate;
1125 return this;
1126 }
1127
1128 public ServiceDependency setPropagate(Object instance, String method) {
1129 setPropagate(instance != null && method != null);
1130 m_propagateCallbackInstance = instance;
1131 m_propagateCallbackMethod = method;
1132 return this;
Marcel Offermans117aa2f2009-12-10 09:48:17 +00001133 }
Marcel Offermans7f0cec02011-11-04 13:39:28 +00001134
Marcel Offermansa962bc92009-11-21 17:59:33 +00001135}