blob: 7abcffdb59dfb992cb1f86f0f1d1e630fd3c513d [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 Offermansa962bc92009-11-21 17:59:33 +000021import java.lang.reflect.Proxy;
22import java.util.AbstractMap;
Marcel Offermanse14b3422009-11-25 23:04:32 +000023import java.util.ArrayList;
Marcel Offermansa962bc92009-11-21 17:59:33 +000024import java.util.Arrays;
25import java.util.Comparator;
Marcel Offermans117aa2f2009-12-10 09:48:17 +000026import java.util.Dictionary;
Marcel Offermansa962bc92009-11-21 17:59:33 +000027import java.util.HashSet;
Marcel Offermanse14b3422009-11-25 23:04:32 +000028import java.util.List;
Marcel Offermansa962bc92009-11-21 17:59:33 +000029import java.util.Map;
30import java.util.Set;
31
Pierre De Ropaacb3aa2009-12-04 22:53:23 +000032import org.apache.felix.dm.dependencies.ServiceDependency;
33import org.apache.felix.dm.impl.DefaultNullObject;
34import org.apache.felix.dm.impl.Logger;
35import org.apache.felix.dm.impl.tracker.ServiceTracker;
36import org.apache.felix.dm.impl.tracker.ServiceTrackerCustomizer;
37import org.apache.felix.dm.management.ServiceComponentDependency;
Marcel Offermansa962bc92009-11-21 17:59:33 +000038import org.osgi.framework.BundleContext;
39import org.osgi.framework.Constants;
40import org.osgi.framework.InvalidSyntaxException;
41import org.osgi.framework.ServiceReference;
42
43/**
44 * Service dependency that can track an OSGi service.
45 *
46 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
47 */
Marcel Offermans61a81142010-04-02 15:16:50 +000048public class ServiceDependencyImpl extends DependencyBase implements ServiceDependency, ServiceTrackerCustomizer, ServiceComponentDependency {
Marcel Offermanse14b3422009-11-25 23:04:32 +000049 protected List m_services = new ArrayList();
Marcel Offermans74363c32009-11-23 19:56:08 +000050 protected volatile ServiceTracker m_tracker;
51 protected BundleContext m_context;
Marcel Offermans74363c32009-11-23 19:56:08 +000052 protected volatile Class m_trackedServiceName;
Marcel Offermansa962bc92009-11-21 17:59:33 +000053 private Object m_nullObject;
54 private volatile String m_trackedServiceFilter;
55 private volatile String m_trackedServiceFilterUnmodified;
56 private volatile ServiceReference m_trackedServiceReference;
57 private volatile boolean m_isStarted;
58 private Object m_callbackInstance;
59 private String m_callbackAdded;
60 private String m_callbackChanged;
61 private String m_callbackRemoved;
62 private boolean m_autoConfig;
Marcel Offermans74363c32009-11-23 19:56:08 +000063 protected ServiceReference m_reference;
64 protected Object m_serviceInstance;
Marcel Offermansa962bc92009-11-21 17:59:33 +000065 private String m_autoConfigInstance;
66 private boolean m_autoConfigInvoked;
67 private Object m_defaultImplementation;
68 private Object m_defaultImplementationInstance;
Marcel Offermansb196d722009-11-26 17:12:12 +000069 private boolean m_isAvailable;
Marcel Offermansbde9a432010-05-11 08:01:28 +000070 private ServiceReference[] m_references;
Marcel Offermansa962bc92009-11-21 17:59:33 +000071
72 private static final Comparator COMPARATOR = new Comparator() {
73 public int getRank(ServiceReference ref) {
74 Object ranking = ref.getProperty(Constants.SERVICE_RANKING);
75 if (ranking != null && (ranking instanceof Integer)) {
76 return ((Integer) ranking).intValue();
77 }
78 return 0;
79 }
80
81 public int compare(Object a, Object b) {
82 ServiceReference ra = (ServiceReference) a, rb = (ServiceReference) b;
83 int ranka = getRank(ra);
84 int rankb = getRank(rb);
85 if (ranka < rankb) {
86 return -1;
87 }
88 else if (ranka > rankb) {
89 return 1;
90 }
91 return 0;
92 }
93 };
94
95 /**
96 * Entry to wrap service properties behind a Map.
97 */
98 private final static class ServicePropertiesMapEntry implements Map.Entry {
99 private final String m_key;
100 private Object m_value;
101
102 public ServicePropertiesMapEntry(String key, Object value) {
103 m_key = key;
104 m_value = value;
105 }
106
107 public Object getKey() {
108 return m_key;
109 }
110
111 public Object getValue() {
112 return m_value;
113 }
114
115 public String toString() {
116 return m_key + "=" + m_value;
117 }
118
119 public Object setValue(Object value) {
120 Object oldValue = m_value;
121 m_value = value;
122 return oldValue;
123 }
124
125 public boolean equals(Object o) {
126 if (!(o instanceof Map.Entry)) {
127 return false;
128 }
129 Map.Entry e = (Map.Entry) o;
130 return eq(m_key, e.getKey()) && eq(m_value, e.getValue());
131 }
132
133 public int hashCode() {
134 return ((m_key == null) ? 0 : m_key.hashCode()) ^ ((m_value == null) ? 0 : m_value.hashCode());
135 }
136
137 private static final boolean eq(Object o1, Object o2) {
138 return (o1 == null ? o2 == null : o1.equals(o2));
139 }
140 }
141
142 /**
143 * Wraps service properties behind a Map.
144 */
145 private final static class ServicePropertiesMap extends AbstractMap {
146 private final ServiceReference m_ref;
147
148 public ServicePropertiesMap(ServiceReference ref) {
149 m_ref = ref;
150 }
151
152 public Object get(Object key) {
153 return m_ref.getProperty(key.toString());
154 }
155
156 public int size() {
157 return m_ref.getPropertyKeys().length;
158 }
159
160 public Set entrySet() {
161 Set set = new HashSet();
162 String[] keys = m_ref.getPropertyKeys();
163 for (int i = 0; i < keys.length; i++) {
164 set.add(new ServicePropertiesMapEntry(keys[i], m_ref.getProperty(keys[i])));
165 }
166 return set;
167 }
168 }
169
170 /**
171 * Creates a new service dependency.
172 *
173 * @param context the bundle context
174 * @param logger the logger
175 */
Pierre De Ropaacb3aa2009-12-04 22:53:23 +0000176 public ServiceDependencyImpl(BundleContext context, Logger logger) {
Marcel Offermansb196d722009-11-26 17:12:12 +0000177 super(logger);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000178 m_context = context;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000179 m_autoConfig = true;
180 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000181
182 public synchronized boolean isAutoConfig() {
183 return m_autoConfig;
184 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000185
Marcel Offermansb196d722009-11-26 17:12:12 +0000186 public synchronized boolean isAvailable() {
187 return m_isAvailable;
188 }
189
Marcel Offermansa962bc92009-11-21 17:59:33 +0000190 public synchronized Object getService() {
191 Object service = null;
192 if (m_isStarted) {
193 service = m_tracker.getService();
194 }
Marcel Offermans001db052009-12-08 08:58:40 +0000195 if (service == null && isAutoConfig()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000196 service = getDefaultImplementation();
197 if (service == null) {
198 service = getNullObject();
199 }
200 }
201 return service;
202 }
203
204 public Object lookupService() {
205 Object service = null;
206 if (m_isStarted) {
Marcel Offermans001db052009-12-08 08:58:40 +0000207 service = getService();
Marcel Offermansa962bc92009-11-21 17:59:33 +0000208 }
209 else {
210 ServiceReference[] refs = null;
211 ServiceReference ref = null;
212 if (m_trackedServiceName != null) {
213 if (m_trackedServiceFilter != null) {
214 try {
215 refs = m_context.getServiceReferences(m_trackedServiceName.getName(), m_trackedServiceFilter);
216 if (refs != null) {
217 Arrays.sort(refs, COMPARATOR);
218 ref = refs[0];
219 }
220 }
221 catch (InvalidSyntaxException e) {
222 throw new IllegalStateException("Invalid filter definition for dependency.");
223 }
224 }
225 else if (m_trackedServiceReference != null) {
226 ref = m_trackedServiceReference;
227 }
228 else {
229 ref = m_context.getServiceReference(m_trackedServiceName.getName());
230 }
231 if (ref != null) {
232 service = m_context.getService(ref);
233 }
234 }
235 else {
236 throw new IllegalStateException("Could not lookup dependency, no service name specified.");
237 }
238 }
Marcel Offermans001db052009-12-08 08:58:40 +0000239 if (service == null && isAutoConfig()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000240 service = getDefaultImplementation();
241 if (service == null) {
242 service = getNullObject();
243 }
244 }
245 return service;
246 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000247
248 // TODO lots of duplication in lookupService()
249 public ServiceReference lookupServiceReference() {
250 ServiceReference service = null;
251 if (m_isStarted) {
252 service = m_tracker.getServiceReference();
253 }
254 else {
255 ServiceReference[] refs = null;
256 ServiceReference ref = null;
257 if (m_trackedServiceName != null) {
258 if (m_trackedServiceFilter != null) {
259 try {
260 refs = m_context.getServiceReferences(m_trackedServiceName.getName(), m_trackedServiceFilter);
261 if (refs != null) {
262 Arrays.sort(refs, COMPARATOR);
263 ref = refs[0];
264 }
265 }
266 catch (InvalidSyntaxException e) {
267 throw new IllegalStateException("Invalid filter definition for dependency.");
268 }
269 }
270 else if (m_trackedServiceReference != null) {
271 ref = m_trackedServiceReference;
272 }
273 else {
274 ref = m_context.getServiceReference(m_trackedServiceName.getName());
275 }
276 if (ref != null) {
277 service = ref;
278 }
279 }
280 else {
281 throw new IllegalStateException("Could not lookup dependency, no service name specified.");
282 }
283 }
284 return service;
285 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000286
287 private Object getNullObject() {
288 if (m_nullObject == null) {
289 Class trackedServiceName;
290 synchronized (this) {
291 trackedServiceName = m_trackedServiceName;
292 }
293 try {
294 m_nullObject = Proxy.newProxyInstance(trackedServiceName.getClassLoader(), new Class[] {trackedServiceName}, new DefaultNullObject());
295 }
296 catch (Exception e) {
297 m_logger.log(Logger.LOG_ERROR, "Could not create null object for " + trackedServiceName + ".", e);
298 }
299 }
300 return m_nullObject;
301 }
302
303 private Object getDefaultImplementation() {
304 if (m_defaultImplementation != null) {
305 if (m_defaultImplementation instanceof Class) {
306 try {
307 m_defaultImplementationInstance = ((Class) m_defaultImplementation).newInstance();
308 }
309 catch (Exception e) {
310 m_logger.log(Logger.LOG_ERROR, "Could not create default implementation instance of class " + m_defaultImplementation + ".", e);
311 }
312 }
313 else {
314 m_defaultImplementationInstance = m_defaultImplementation;
315 }
316 }
317 return m_defaultImplementationInstance;
318 }
319
320 public synchronized Class getInterface() {
321 return m_trackedServiceName;
322 }
323
Marcel Offermanse14b3422009-11-25 23:04:32 +0000324 public void start(DependencyService service) {
325 boolean needsStarting = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000326 synchronized (this) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000327 m_services.add(service);
328 if (!m_isStarted) {
329 if (m_trackedServiceName != null) {
330 if (m_trackedServiceFilter != null) {
331 try {
332 m_tracker = new ServiceTracker(m_context, m_context.createFilter(m_trackedServiceFilter), this);
333 }
334 catch (InvalidSyntaxException e) {
Marcel Offermansad760672010-03-03 15:30:01 +0000335 throw new IllegalStateException("Invalid filter definition for dependency: " + m_trackedServiceFilter);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000336 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000337 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000338 else if (m_trackedServiceReference != null) {
339 m_tracker = new ServiceTracker(m_context, m_trackedServiceReference, this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000340 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000341 else {
342 m_tracker = new ServiceTracker(m_context, m_trackedServiceName.getName(), this);
343 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000344 }
345 else {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000346 throw new IllegalStateException("Could not create tracker for dependency, no service name specified.");
Marcel Offermansa962bc92009-11-21 17:59:33 +0000347 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000348 m_isStarted = true;
349 needsStarting = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000350 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000351 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000352 if (needsStarting) {
353 m_tracker.open();
354 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000355 }
356
Marcel Offermanse14b3422009-11-25 23:04:32 +0000357 public void stop(DependencyService service) {
358 boolean needsStopping = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000359 synchronized (this) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000360 if (m_services.size() == 1 && m_services.contains(service)) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000361 m_isStarted = false;
362 needsStopping = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000363 }
Marcel Offermans203bdad2009-12-04 09:23:04 +0000364 m_services.remove(service);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000365 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000366 if (needsStopping) {
367 m_tracker.close();
368 m_tracker = null;
369 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000370 }
371
372 public Object addingService(ServiceReference ref) {
373 Object service = m_context.getService(ref);
374 // first check to make sure the service is actually an instance of our service
375 if (!m_trackedServiceName.isInstance(service)) {
376 return null;
377 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000378 return service;
379 }
380
381 public void addedService(ServiceReference ref, Object service) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000382 boolean makeAvailable = makeAvailable();
383
Marcel Offermans203bdad2009-12-04 09:23:04 +0000384 Object[] services;
385 synchronized (this) {
386 services = m_services.toArray();
387 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000388 for (int i = 0; i < services.length; i++) {
389 DependencyService ds = (DependencyService) services[i];
390 if (makeAvailable) {
Pierre De Rop1785c332010-06-11 06:03:53 +0000391 // The dependency callback will be defered until all required dependency are available.
392 ds.dependencyAvailable(this);
393 if (!isRequired()) {
394 // For optional dependency, we always invoke callback, because at this point, we know
395 // that the service has been started, and the service start method has been called.
396 // (See the ServiceImpl.bindService method, which will activate optional dependencies using
397 // startTrackingOptional() method).
Marcel Offermanse14b3422009-11-25 23:04:32 +0000398 invokeAdded(ds, ref, service);
399 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000400 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000401 else {
402 ds.dependencyChanged(this);
Pierre De Rop1785c332010-06-11 06:03:53 +0000403 // At this point, either the dependency is optional (meaning that the service has been started,
404 // because if not, then our dependency would not be active); or the dependency is required,
405 // meaning that either the service is not yet started, or already started.
406 // In all cases, we have to inject the required dependency.
Marcel Offermanse14b3422009-11-25 23:04:32 +0000407 invokeAdded(ds, ref, service);
408 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000409 }
410 }
411
Marcel Offermansa962bc92009-11-21 17:59:33 +0000412 public void modifiedService(ServiceReference ref, Object service) {
Marcel Offermans203bdad2009-12-04 09:23:04 +0000413 Object[] services;
414 synchronized (this) {
415 services = m_services.toArray();
416 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000417 for (int i = 0; i < services.length; i++) {
418 DependencyService ds = (DependencyService) services[i];
419 ds.dependencyChanged(this);
420 if (ds.isRegistered()) {
421 invokeChanged(ds, ref, service);
422 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000423 }
424 }
425
Marcel Offermansa962bc92009-11-21 17:59:33 +0000426 public void removedService(ServiceReference ref, Object service) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000427 boolean makeUnavailable = makeUnavailable();
428
Marcel Offermans203bdad2009-12-04 09:23:04 +0000429 Object[] services;
430 synchronized (this) {
431 services = m_services.toArray();
432 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000433 for (int i = 0; i < services.length; i++) {
434 DependencyService ds = (DependencyService) services[i];
435 if (makeUnavailable) {
436 ds.dependencyUnavailable(this);
437 if (!isRequired()) {
438 invokeRemoved(ds, ref, service);
439 }
440 }
441 else {
442 ds.dependencyChanged(this);
443 invokeRemoved(ds, ref, service);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000444 }
445 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000446 // unget what we got in addingService (see ServiceTracker 701.4.1)
447 m_context.ungetService(ref);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000448
Marcel Offermansa962bc92009-11-21 17:59:33 +0000449 }
450
Marcel Offermansea89b862010-06-24 13:14:43 +0000451 public void invokeAdded(DependencyService dependencyService, ServiceReference reference, Object service) {
452 invoke(dependencyService, reference, service, m_callbackAdded);
453 }
454
455 public void invokeChanged(DependencyService dependencyService, ServiceReference reference, Object service) {
456 invoke(dependencyService, reference, service, m_callbackChanged);
457 }
458
Marcel Offermansb196d722009-11-26 17:12:12 +0000459 public void invokeRemoved(DependencyService dependencyService, ServiceReference reference, Object service) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000460 invoke(dependencyService, reference, service, m_callbackRemoved);
461 }
462
463 public void invoke(DependencyService dependencyService, ServiceReference reference, Object service, String name) {
464 if (name != null) {
465 dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name,
Marcel Offermansb196d722009-11-26 17:12:12 +0000466 new Class[][] {{ServiceReference.class, m_trackedServiceName}, {ServiceReference.class, Object.class}, {ServiceReference.class}, {m_trackedServiceName}, {Object.class}, {}, {Map.class, m_trackedServiceName}},
467 new Object[][] {{reference, service}, {reference, service}, {reference}, {service}, {service}, {}, {new ServicePropertiesMap(reference), service}}
468 );
Marcel Offermansa962bc92009-11-21 17:59:33 +0000469 }
470 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000471
Marcel Offermans74363c32009-11-23 19:56:08 +0000472 protected synchronized boolean makeAvailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000473 if (!isAvailable()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000474 m_isAvailable = true;
475 return true;
476 }
477 return false;
478 }
479
480 private synchronized boolean makeUnavailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000481 if ((isAvailable()) && (m_tracker.getServiceReference() == null)) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000482 m_isAvailable = false;
483 return true;
484 }
485 return false;
486 }
487
Marcel Offermanse14b3422009-11-25 23:04:32 +0000488 private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
489 if (m_callbackInstance == null) {
490 return dependencyService.getCompositionInstances();
491 }
492 else {
493 return new Object[] { m_callbackInstance };
494 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000495 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000496
497 // ----- CREATION
498
499 /**
500 * Sets the name of the service that should be tracked.
501 *
502 * @param serviceName the name of the service
503 * @return this service dependency
504 */
505 public synchronized ServiceDependency setService(Class serviceName) {
506 ensureNotActive();
507 if (serviceName == null) {
508 throw new IllegalArgumentException("Service name cannot be null.");
509 }
510 m_trackedServiceName = serviceName;
511 m_trackedServiceReference = null;
512 m_trackedServiceFilter = null;
513 return this;
514 }
515
516 /**
517 * Sets the name of the service that should be tracked. You can either specify
518 * only the name, or the name and a filter. In the latter case, the filter is used
519 * to track the service and should only return services of the type that was specified
520 * in the name. To make sure of this, the filter is actually extended internally to
521 * filter on the correct name.
522 *
523 * @param serviceName the name of the service
524 * @param serviceFilter the filter condition
525 * @return this service dependency
526 */
527 public synchronized ServiceDependency setService(Class serviceName, String serviceFilter) {
528 ensureNotActive();
529 if (serviceName == null) {
530 throw new IllegalArgumentException("Service name cannot be null.");
531 }
532 m_trackedServiceName = serviceName;
533 if (serviceFilter != null) {
534 m_trackedServiceFilterUnmodified = serviceFilter;
535 m_trackedServiceFilter ="(&(" + Constants.OBJECTCLASS + "=" + serviceName.getName() + ")" + serviceFilter + ")";
536 }
537 else {
538 m_trackedServiceFilterUnmodified = null;
539 m_trackedServiceFilter = null;
540 }
541 m_trackedServiceReference = null;
542 return this;
543 }
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000544
545 public synchronized ServiceDependency setService(String serviceFilter) {
546 ensureNotActive();
547 if (serviceFilter == null) {
548 throw new IllegalArgumentException("Service filter cannot be null.");
549 }
550 m_trackedServiceName = Object.class;
551 if (serviceFilter != null) {
552 m_trackedServiceFilterUnmodified = serviceFilter;
553 m_trackedServiceFilter = serviceFilter;
554 }
555 m_trackedServiceReference = null;
556 return this;
557 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000558
559 /**
560 * Sets the name of the service that should be tracked. You can either specify
561 * only the name, or the name and a reference. In the latter case, the service reference
562 * is used to track the service and should only return services of the type that was
563 * specified in the name.
564 *
565 * @param serviceName the name of the service
566 * @param serviceReference the service reference to track
567 * @return this service dependency
568 */
569 public synchronized ServiceDependency setService(Class serviceName, ServiceReference serviceReference) {
570 ensureNotActive();
571 if (serviceName == null) {
572 throw new IllegalArgumentException("Service name cannot be null.");
573 }
574 m_trackedServiceName = serviceName;
575 m_trackedServiceReference = serviceReference;
576 m_trackedServiceFilterUnmodified = null;
577 m_trackedServiceFilter = null;
578 return this;
579 }
580
581 /**
582 * Sets the default implementation for this service dependency. You can use this to supply
583 * your own implementation that will be used instead of a Null Object when the dependency is
584 * not available. This is also convenient if the service dependency is not an interface
585 * (which would cause the Null Object creation to fail) but a class.
586 *
587 * @param implementation the instance to use or the class to instantiate if you want to lazily
588 * instantiate this implementation
589 * @return this service dependency
590 */
591 public synchronized ServiceDependency setDefaultImplementation(Object implementation) {
592 ensureNotActive();
593 m_defaultImplementation = implementation;
594 return this;
595 }
596
597 /**
598 * Sets the required flag which determines if this service is required or not.
599 *
600 * @param required the required flag
601 * @return this service dependency
602 */
603 public synchronized ServiceDependency setRequired(boolean required) {
604 ensureNotActive();
Marcel Offermansb196d722009-11-26 17:12:12 +0000605 setIsRequired(required);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000606 return this;
607 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000608
609 public ServiceDependency setInstanceBound(boolean isInstanceBound) {
Marcel Offermans61a81142010-04-02 15:16:50 +0000610 setIsInstanceBound(isInstanceBound);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000611 return this;
612 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000613
614 /**
615 * Sets auto configuration for this service. Auto configuration allows the
616 * dependency to fill in any attributes in the service implementation that
617 * are of the same type as this dependency. Default is on.
618 *
619 * @param autoConfig the value of auto config
620 * @return this service dependency
621 */
622 public synchronized ServiceDependency setAutoConfig(boolean autoConfig) {
623 ensureNotActive();
624 m_autoConfig = autoConfig;
625 m_autoConfigInvoked = true;
626 return this;
627 }
628
629 /**
630 * Sets auto configuration for this service. Auto configuration allows the
631 * dependency to fill in the attribute in the service implementation that
632 * has the same type and instance name.
633 *
634 * @param instanceName the name of attribute to auto config
635 * @return this service dependency
636 */
637 public synchronized ServiceDependency setAutoConfig(String instanceName) {
638 ensureNotActive();
639 m_autoConfig = (instanceName != null);
640 m_autoConfigInstance = instanceName;
641 m_autoConfigInvoked = true;
642 return this;
643 }
644
645 /**
646 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
647 * dependency is added or removed. When you specify callbacks, the auto configuration
648 * feature is automatically turned off, because we're assuming you don't need it in this
649 * case.
650 *
651 * @param added the method to call when a service was added
652 * @param removed the method to call when a service was removed
653 * @return this service dependency
654 */
655 public synchronized ServiceDependency setCallbacks(String added, String removed) {
656 return setCallbacks(null, added, null, removed);
657 }
658
659 /**
660 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
661 * dependency is added, changed or removed. When you specify callbacks, the auto
662 * configuration feature is automatically turned off, because we're assuming you don't
663 * need it in this case.
664 *
665 * @param added the method to call when a service was added
666 * @param changed the method to call when a service was changed
667 * @param removed the method to call when a service was removed
668 * @return this service dependency
669 */
670 public synchronized ServiceDependency setCallbacks(String added, String changed, String removed) {
671 return setCallbacks(null, added, changed, removed);
672 }
673
674 /**
675 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
676 * dependency is added or removed. They are called on the instance you provide. When you
677 * specify callbacks, the auto configuration feature is automatically turned off, because
678 * we're assuming you don't need it in this case.
679 *
680 * @param instance the instance to call the callbacks on
681 * @param added the method to call when a service was added
682 * @param removed the method to call when a service was removed
683 * @return this service dependency
684 */
685 public synchronized ServiceDependency setCallbacks(Object instance, String added, String removed) {
686 return setCallbacks(instance, added, null, removed);
687 }
688
689 /**
690 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
691 * dependency is added, changed or removed. They are called on the instance you provide. When you
692 * specify callbacks, the auto configuration feature is automatically turned off, because
693 * we're assuming you don't need it in this case.
694 *
695 * @param instance the instance to call the callbacks on
696 * @param added the method to call when a service was added
697 * @param changed the method to call when a service was changed
698 * @param removed the method to call when a service was removed
699 * @return this service dependency
700 */
701 public synchronized ServiceDependency setCallbacks(Object instance, String added, String changed, String removed) {
702 ensureNotActive();
703 // if at least one valid callback is specified, we turn off auto configuration, unless
704 // someone already explicitly invoked autoConfig
705 if ((added != null || removed != null || changed != null) && ! m_autoConfigInvoked) {
706 setAutoConfig(false);
707 }
708 m_callbackInstance = instance;
709 m_callbackAdded = added;
710 m_callbackChanged = changed;
711 m_callbackRemoved = removed;
712 return this;
713 }
714
715 private void ensureNotActive() {
716 if (m_tracker != null) {
717 throw new IllegalStateException("Cannot modify state while active.");
718 }
719 }
720
721 public synchronized String toString() {
722 return "ServiceDependency[" + m_trackedServiceName + " " + m_trackedServiceFilterUnmodified + "]";
723 }
724
725 public String getAutoConfigName() {
726 return m_autoConfigInstance;
727 }
Marcel Offermans001db052009-12-08 08:58:40 +0000728
729 public Object getAutoConfigInstance() {
730 return lookupService();
731 }
732
733 public Class getAutoConfigType() {
734 return getInterface();
735 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000736
737 public String getName() {
738 StringBuilder sb = new StringBuilder();
739 sb.append(m_trackedServiceName.getName());
740 if (m_trackedServiceFilterUnmodified != null) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000741 sb.append(' ');
Marcel Offermansa962bc92009-11-21 17:59:33 +0000742 sb.append(m_trackedServiceFilterUnmodified);
743 }
744 return sb.toString();
745 }
746
747 public int getState() {
748 return (isAvailable() ? 1 : 0) + (isRequired() ? 2 : 0);
749 }
750
751 public String getType() {
752 return "service";
753 }
Marcel Offermans001db052009-12-08 08:58:40 +0000754
755 public void invokeAdded(DependencyService service) {
Marcel Offermansbde9a432010-05-11 08:01:28 +0000756 ServiceReference[] refs = m_tracker.getServiceReferences();
757 if (refs != null) {
758 for (int i = 0; i < refs.length; i++) {
759 ServiceReference sr = refs[i];
760 Object svc = m_context.getService(sr);
761 invokeAdded(service, sr, svc);
762 }
763 }
764 m_references = refs;
Marcel Offermans001db052009-12-08 08:58:40 +0000765 }
Marcel Offermansbde9a432010-05-11 08:01:28 +0000766
Marcel Offermans001db052009-12-08 08:58:40 +0000767 public void invokeRemoved(DependencyService service) {
Marcel Offermansbde9a432010-05-11 08:01:28 +0000768 ServiceReference[] refs = m_references;
769 if (refs != null) {
770 for (int i = 0; i < refs.length; i++) {
771 ServiceReference sr = refs[i];
772 Object svc = m_context.getService(sr);
773 invokeRemoved(service, sr, svc);
774 }
775 }
776 m_references = null;
Marcel Offermans001db052009-12-08 08:58:40 +0000777 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000778
779 public Dictionary getProperties() {
780 // TODO Auto-generated method stub
781 return null;
782 }
783
784 public boolean isPropagated() {
785 // TODO Auto-generated method stub
786 return false;
787 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000788}