blob: 163e3e3406174ef356d988f42c1349c035e6a205 [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
Marcel Offermansb1959f42010-07-01 12:23:51 +000032import org.apache.felix.dm.dependencies.Dependency;
Pierre De Ropaacb3aa2009-12-04 22:53:23 +000033import org.apache.felix.dm.dependencies.ServiceDependency;
34import org.apache.felix.dm.impl.DefaultNullObject;
35import org.apache.felix.dm.impl.Logger;
36import org.apache.felix.dm.impl.tracker.ServiceTracker;
37import org.apache.felix.dm.impl.tracker.ServiceTrackerCustomizer;
38import org.apache.felix.dm.management.ServiceComponentDependency;
Marcel Offermansa962bc92009-11-21 17:59:33 +000039import org.osgi.framework.BundleContext;
40import org.osgi.framework.Constants;
41import org.osgi.framework.InvalidSyntaxException;
42import org.osgi.framework.ServiceReference;
43
44/**
45 * Service dependency that can track an OSGi service.
46 *
47 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
48 */
Marcel Offermans61a81142010-04-02 15:16:50 +000049public class ServiceDependencyImpl extends DependencyBase implements ServiceDependency, ServiceTrackerCustomizer, ServiceComponentDependency {
Marcel Offermanse14b3422009-11-25 23:04:32 +000050 protected List m_services = new ArrayList();
Marcel Offermans74363c32009-11-23 19:56:08 +000051 protected volatile ServiceTracker m_tracker;
52 protected BundleContext m_context;
Marcel Offermans74363c32009-11-23 19:56:08 +000053 protected volatile Class m_trackedServiceName;
Marcel Offermansa962bc92009-11-21 17:59:33 +000054 private Object m_nullObject;
55 private volatile String m_trackedServiceFilter;
56 private volatile String m_trackedServiceFilterUnmodified;
57 private volatile ServiceReference m_trackedServiceReference;
58 private volatile boolean m_isStarted;
59 private Object m_callbackInstance;
60 private String m_callbackAdded;
61 private String m_callbackChanged;
62 private String m_callbackRemoved;
63 private boolean m_autoConfig;
Marcel Offermans74363c32009-11-23 19:56:08 +000064 protected ServiceReference m_reference;
65 protected Object m_serviceInstance;
Marcel Offermansa962bc92009-11-21 17:59:33 +000066 private String m_autoConfigInstance;
67 private boolean m_autoConfigInvoked;
68 private Object m_defaultImplementation;
69 private Object m_defaultImplementationInstance;
Marcel Offermansb196d722009-11-26 17:12:12 +000070 private boolean m_isAvailable;
Marcel Offermansbde9a432010-05-11 08:01:28 +000071 private ServiceReference[] m_references;
Marcel Offermansa962bc92009-11-21 17:59:33 +000072
73 private static final Comparator COMPARATOR = new Comparator() {
74 public int getRank(ServiceReference ref) {
75 Object ranking = ref.getProperty(Constants.SERVICE_RANKING);
76 if (ranking != null && (ranking instanceof Integer)) {
77 return ((Integer) ranking).intValue();
78 }
79 return 0;
80 }
81
82 public int compare(Object a, Object b) {
83 ServiceReference ra = (ServiceReference) a, rb = (ServiceReference) b;
84 int ranka = getRank(ra);
85 int rankb = getRank(rb);
86 if (ranka < rankb) {
87 return -1;
88 }
89 else if (ranka > rankb) {
90 return 1;
91 }
92 return 0;
93 }
94 };
95
96 /**
97 * Entry to wrap service properties behind a Map.
98 */
99 private final static class ServicePropertiesMapEntry implements Map.Entry {
100 private final String m_key;
101 private Object m_value;
102
103 public ServicePropertiesMapEntry(String key, Object value) {
104 m_key = key;
105 m_value = value;
106 }
107
108 public Object getKey() {
109 return m_key;
110 }
111
112 public Object getValue() {
113 return m_value;
114 }
115
116 public String toString() {
117 return m_key + "=" + m_value;
118 }
119
120 public Object setValue(Object value) {
121 Object oldValue = m_value;
122 m_value = value;
123 return oldValue;
124 }
125
126 public boolean equals(Object o) {
127 if (!(o instanceof Map.Entry)) {
128 return false;
129 }
130 Map.Entry e = (Map.Entry) o;
131 return eq(m_key, e.getKey()) && eq(m_value, e.getValue());
132 }
133
134 public int hashCode() {
135 return ((m_key == null) ? 0 : m_key.hashCode()) ^ ((m_value == null) ? 0 : m_value.hashCode());
136 }
137
138 private static final boolean eq(Object o1, Object o2) {
139 return (o1 == null ? o2 == null : o1.equals(o2));
140 }
141 }
142
143 /**
144 * Wraps service properties behind a Map.
145 */
146 private final static class ServicePropertiesMap extends AbstractMap {
147 private final ServiceReference m_ref;
148
149 public ServicePropertiesMap(ServiceReference ref) {
150 m_ref = ref;
151 }
152
153 public Object get(Object key) {
154 return m_ref.getProperty(key.toString());
155 }
156
157 public int size() {
158 return m_ref.getPropertyKeys().length;
159 }
160
161 public Set entrySet() {
162 Set set = new HashSet();
163 String[] keys = m_ref.getPropertyKeys();
164 for (int i = 0; i < keys.length; i++) {
165 set.add(new ServicePropertiesMapEntry(keys[i], m_ref.getProperty(keys[i])));
166 }
167 return set;
168 }
169 }
170
171 /**
172 * Creates a new service dependency.
173 *
174 * @param context the bundle context
175 * @param logger the logger
176 */
Pierre De Ropaacb3aa2009-12-04 22:53:23 +0000177 public ServiceDependencyImpl(BundleContext context, Logger logger) {
Marcel Offermansb196d722009-11-26 17:12:12 +0000178 super(logger);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000179 m_context = context;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000180 m_autoConfig = true;
181 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000182
Marcel Offermansb1959f42010-07-01 12:23:51 +0000183 /** Copying constructor that clones an existing instance. */
184 public ServiceDependencyImpl(ServiceDependencyImpl prototype) {
185 super(prototype);
186 m_context = prototype.m_context;
187 m_autoConfig = prototype.m_autoConfig;
188 m_trackedServiceName = prototype.m_trackedServiceName;
189 m_nullObject = prototype.m_nullObject;
190 m_trackedServiceFilter = prototype.m_trackedServiceFilter;
191 m_trackedServiceFilterUnmodified = prototype.m_trackedServiceFilterUnmodified;
192 m_trackedServiceReference = prototype.m_trackedServiceReference;
193 m_callbackInstance = prototype.m_callbackInstance;
194 m_callbackAdded = prototype.m_callbackAdded;
195 m_callbackChanged = prototype.m_callbackChanged;
196 m_callbackRemoved = prototype.m_callbackRemoved;
197 m_autoConfigInstance = prototype.m_autoConfigInstance;
198 m_defaultImplementation = prototype.m_defaultImplementation;
199 }
200
201 public Dependency createCopy() {
202 return new ServiceDependencyImpl(this);
203 }
204
Marcel Offermansa962bc92009-11-21 17:59:33 +0000205 public synchronized boolean isAutoConfig() {
206 return m_autoConfig;
207 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000208
Marcel Offermansb196d722009-11-26 17:12:12 +0000209 public synchronized boolean isAvailable() {
210 return m_isAvailable;
211 }
212
Marcel Offermansa962bc92009-11-21 17:59:33 +0000213 public synchronized Object getService() {
214 Object service = null;
215 if (m_isStarted) {
216 service = m_tracker.getService();
217 }
Marcel Offermans001db052009-12-08 08:58:40 +0000218 if (service == null && isAutoConfig()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000219 service = getDefaultImplementation();
220 if (service == null) {
221 service = getNullObject();
222 }
223 }
224 return service;
225 }
226
227 public Object lookupService() {
228 Object service = null;
229 if (m_isStarted) {
Marcel Offermans001db052009-12-08 08:58:40 +0000230 service = getService();
Marcel Offermansa962bc92009-11-21 17:59:33 +0000231 }
232 else {
233 ServiceReference[] refs = null;
234 ServiceReference ref = null;
235 if (m_trackedServiceName != null) {
236 if (m_trackedServiceFilter != null) {
237 try {
238 refs = m_context.getServiceReferences(m_trackedServiceName.getName(), m_trackedServiceFilter);
239 if (refs != null) {
240 Arrays.sort(refs, COMPARATOR);
241 ref = refs[0];
242 }
243 }
244 catch (InvalidSyntaxException e) {
245 throw new IllegalStateException("Invalid filter definition for dependency.");
246 }
247 }
248 else if (m_trackedServiceReference != null) {
249 ref = m_trackedServiceReference;
250 }
251 else {
252 ref = m_context.getServiceReference(m_trackedServiceName.getName());
253 }
254 if (ref != null) {
255 service = m_context.getService(ref);
256 }
257 }
258 else {
259 throw new IllegalStateException("Could not lookup dependency, no service name specified.");
260 }
261 }
Marcel Offermans001db052009-12-08 08:58:40 +0000262 if (service == null && isAutoConfig()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000263 service = getDefaultImplementation();
264 if (service == null) {
265 service = getNullObject();
266 }
267 }
268 return service;
269 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000270
Marcel Offermanse14b3422009-11-25 23:04:32 +0000271 // TODO lots of duplication in lookupService()
272 public ServiceReference lookupServiceReference() {
273 ServiceReference service = null;
274 if (m_isStarted) {
275 service = m_tracker.getServiceReference();
276 }
277 else {
278 ServiceReference[] refs = null;
279 ServiceReference ref = null;
280 if (m_trackedServiceName != null) {
281 if (m_trackedServiceFilter != null) {
282 try {
283 refs = m_context.getServiceReferences(m_trackedServiceName.getName(), m_trackedServiceFilter);
284 if (refs != null) {
285 Arrays.sort(refs, COMPARATOR);
286 ref = refs[0];
287 }
288 }
289 catch (InvalidSyntaxException e) {
290 throw new IllegalStateException("Invalid filter definition for dependency.");
291 }
292 }
293 else if (m_trackedServiceReference != null) {
294 ref = m_trackedServiceReference;
295 }
296 else {
297 ref = m_context.getServiceReference(m_trackedServiceName.getName());
298 }
299 if (ref != null) {
300 service = ref;
301 }
302 }
303 else {
304 throw new IllegalStateException("Could not lookup dependency, no service name specified.");
305 }
306 }
307 return service;
308 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000309
310 private Object getNullObject() {
311 if (m_nullObject == null) {
312 Class trackedServiceName;
313 synchronized (this) {
314 trackedServiceName = m_trackedServiceName;
315 }
316 try {
317 m_nullObject = Proxy.newProxyInstance(trackedServiceName.getClassLoader(), new Class[] {trackedServiceName}, new DefaultNullObject());
318 }
319 catch (Exception e) {
320 m_logger.log(Logger.LOG_ERROR, "Could not create null object for " + trackedServiceName + ".", e);
321 }
322 }
323 return m_nullObject;
324 }
325
326 private Object getDefaultImplementation() {
327 if (m_defaultImplementation != null) {
328 if (m_defaultImplementation instanceof Class) {
329 try {
330 m_defaultImplementationInstance = ((Class) m_defaultImplementation).newInstance();
331 }
332 catch (Exception e) {
333 m_logger.log(Logger.LOG_ERROR, "Could not create default implementation instance of class " + m_defaultImplementation + ".", e);
334 }
335 }
336 else {
337 m_defaultImplementationInstance = m_defaultImplementation;
338 }
339 }
340 return m_defaultImplementationInstance;
341 }
342
343 public synchronized Class getInterface() {
344 return m_trackedServiceName;
345 }
346
Marcel Offermanse14b3422009-11-25 23:04:32 +0000347 public void start(DependencyService service) {
348 boolean needsStarting = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000349 synchronized (this) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000350 m_services.add(service);
351 if (!m_isStarted) {
352 if (m_trackedServiceName != null) {
353 if (m_trackedServiceFilter != null) {
354 try {
355 m_tracker = new ServiceTracker(m_context, m_context.createFilter(m_trackedServiceFilter), this);
356 }
357 catch (InvalidSyntaxException e) {
Marcel Offermansad760672010-03-03 15:30:01 +0000358 throw new IllegalStateException("Invalid filter definition for dependency: " + m_trackedServiceFilter);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000359 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000360 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000361 else if (m_trackedServiceReference != null) {
362 m_tracker = new ServiceTracker(m_context, m_trackedServiceReference, this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000363 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000364 else {
365 m_tracker = new ServiceTracker(m_context, m_trackedServiceName.getName(), this);
366 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000367 }
368 else {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000369 throw new IllegalStateException("Could not create tracker for dependency, no service name specified.");
Marcel Offermansa962bc92009-11-21 17:59:33 +0000370 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000371 m_isStarted = true;
372 needsStarting = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000373 }
Marcel Offermansb1959f42010-07-01 12:23:51 +0000374 else { System.out.println("ALREADY STARTED..."); } // TODO REMOVE, FOR DEBUGGING
Marcel Offermansa962bc92009-11-21 17:59:33 +0000375 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000376 if (needsStarting) {
377 m_tracker.open();
378 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000379 }
380
Marcel Offermanse14b3422009-11-25 23:04:32 +0000381 public void stop(DependencyService service) {
382 boolean needsStopping = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000383 synchronized (this) {
Marcel Offermanscae61362009-12-01 08:37:10 +0000384 if (m_services.size() == 1 && m_services.contains(service)) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000385 m_isStarted = false;
386 needsStopping = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000387 }
Marcel Offermans203bdad2009-12-04 09:23:04 +0000388 m_services.remove(service);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000389 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000390 if (needsStopping) {
391 m_tracker.close();
392 m_tracker = null;
393 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000394 }
395
396 public Object addingService(ServiceReference ref) {
397 Object service = m_context.getService(ref);
398 // first check to make sure the service is actually an instance of our service
399 if (!m_trackedServiceName.isInstance(service)) {
400 return null;
401 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000402 return service;
403 }
404
405 public void addedService(ServiceReference ref, Object service) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000406 boolean makeAvailable = makeAvailable();
407
Marcel Offermans203bdad2009-12-04 09:23:04 +0000408 Object[] services;
409 synchronized (this) {
410 services = m_services.toArray();
411 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000412 for (int i = 0; i < services.length; i++) {
413 DependencyService ds = (DependencyService) services[i];
414 if (makeAvailable) {
Pierre De Rop1785c332010-06-11 06:03:53 +0000415 // The dependency callback will be defered until all required dependency are available.
416 ds.dependencyAvailable(this);
417 if (!isRequired()) {
418 // For optional dependency, we always invoke callback, because at this point, we know
419 // that the service has been started, and the service start method has been called.
420 // (See the ServiceImpl.bindService method, which will activate optional dependencies using
421 // startTrackingOptional() method).
Marcel Offermanse14b3422009-11-25 23:04:32 +0000422 invokeAdded(ds, ref, service);
423 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000424 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000425 else {
426 ds.dependencyChanged(this);
Pierre De Rop1785c332010-06-11 06:03:53 +0000427 // At this point, either the dependency is optional (meaning that the service has been started,
428 // because if not, then our dependency would not be active); or the dependency is required,
429 // meaning that either the service is not yet started, or already started.
430 // In all cases, we have to inject the required dependency.
Marcel Offermanse14b3422009-11-25 23:04:32 +0000431 invokeAdded(ds, ref, service);
432 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000433 }
434 }
435
Marcel Offermansa962bc92009-11-21 17:59:33 +0000436 public void modifiedService(ServiceReference ref, Object service) {
Marcel Offermans203bdad2009-12-04 09:23:04 +0000437 Object[] services;
438 synchronized (this) {
439 services = m_services.toArray();
440 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000441 for (int i = 0; i < services.length; i++) {
442 DependencyService ds = (DependencyService) services[i];
443 ds.dependencyChanged(this);
444 if (ds.isRegistered()) {
445 invokeChanged(ds, ref, service);
446 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000447 }
448 }
449
Marcel Offermansa962bc92009-11-21 17:59:33 +0000450 public void removedService(ServiceReference ref, Object service) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000451 boolean makeUnavailable = makeUnavailable();
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 (makeUnavailable) {
460 ds.dependencyUnavailable(this);
461 if (!isRequired()) {
462 invokeRemoved(ds, ref, service);
463 }
464 }
465 else {
466 ds.dependencyChanged(this);
467 invokeRemoved(ds, ref, service);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000468 }
469 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000470 // unget what we got in addingService (see ServiceTracker 701.4.1)
471 m_context.ungetService(ref);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000472
Marcel Offermansa962bc92009-11-21 17:59:33 +0000473 }
474
Marcel Offermansea89b862010-06-24 13:14:43 +0000475 public void invokeAdded(DependencyService dependencyService, ServiceReference reference, Object service) {
476 invoke(dependencyService, reference, service, m_callbackAdded);
477 }
478
479 public void invokeChanged(DependencyService dependencyService, ServiceReference reference, Object service) {
480 invoke(dependencyService, reference, service, m_callbackChanged);
481 }
482
Marcel Offermansb196d722009-11-26 17:12:12 +0000483 public void invokeRemoved(DependencyService dependencyService, ServiceReference reference, Object service) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000484 invoke(dependencyService, reference, service, m_callbackRemoved);
485 }
486
487 public void invoke(DependencyService dependencyService, ServiceReference reference, Object service, String name) {
488 if (name != null) {
489 dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name,
Marcel Offermansb196d722009-11-26 17:12:12 +0000490 new Class[][] {{ServiceReference.class, m_trackedServiceName}, {ServiceReference.class, Object.class}, {ServiceReference.class}, {m_trackedServiceName}, {Object.class}, {}, {Map.class, m_trackedServiceName}},
491 new Object[][] {{reference, service}, {reference, service}, {reference}, {service}, {service}, {}, {new ServicePropertiesMap(reference), service}}
492 );
Marcel Offermansa962bc92009-11-21 17:59:33 +0000493 }
494 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000495
Marcel Offermans74363c32009-11-23 19:56:08 +0000496 protected synchronized boolean makeAvailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000497 if (!isAvailable()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000498 m_isAvailable = true;
499 return true;
500 }
501 return false;
502 }
503
504 private synchronized boolean makeUnavailable() {
Marcel Offermansb196d722009-11-26 17:12:12 +0000505 if ((isAvailable()) && (m_tracker.getServiceReference() == null)) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000506 m_isAvailable = false;
507 return true;
508 }
509 return false;
510 }
511
Marcel Offermanse14b3422009-11-25 23:04:32 +0000512 private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
513 if (m_callbackInstance == null) {
514 return dependencyService.getCompositionInstances();
515 }
516 else {
517 return new Object[] { m_callbackInstance };
518 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000519 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000520
521 // ----- CREATION
522
523 /**
524 * Sets the name of the service that should be tracked.
525 *
526 * @param serviceName the name of the service
527 * @return this service dependency
528 */
529 public synchronized ServiceDependency setService(Class serviceName) {
530 ensureNotActive();
531 if (serviceName == null) {
532 throw new IllegalArgumentException("Service name cannot be null.");
533 }
534 m_trackedServiceName = serviceName;
535 m_trackedServiceReference = null;
536 m_trackedServiceFilter = null;
537 return this;
538 }
539
540 /**
541 * Sets the name of the service that should be tracked. You can either specify
542 * only the name, or the name and a filter. In the latter case, the filter is used
543 * to track the service and should only return services of the type that was specified
544 * in the name. To make sure of this, the filter is actually extended internally to
545 * filter on the correct name.
546 *
547 * @param serviceName the name of the service
548 * @param serviceFilter the filter condition
549 * @return this service dependency
550 */
551 public synchronized ServiceDependency setService(Class serviceName, String serviceFilter) {
552 ensureNotActive();
553 if (serviceName == null) {
554 throw new IllegalArgumentException("Service name cannot be null.");
555 }
556 m_trackedServiceName = serviceName;
557 if (serviceFilter != null) {
558 m_trackedServiceFilterUnmodified = serviceFilter;
559 m_trackedServiceFilter ="(&(" + Constants.OBJECTCLASS + "=" + serviceName.getName() + ")" + serviceFilter + ")";
560 }
561 else {
562 m_trackedServiceFilterUnmodified = null;
563 m_trackedServiceFilter = null;
564 }
565 m_trackedServiceReference = null;
566 return this;
567 }
Marcel Offermansa83c25a2009-12-22 13:38:38 +0000568
569 public synchronized ServiceDependency setService(String serviceFilter) {
570 ensureNotActive();
571 if (serviceFilter == null) {
572 throw new IllegalArgumentException("Service filter cannot be null.");
573 }
574 m_trackedServiceName = Object.class;
575 if (serviceFilter != null) {
576 m_trackedServiceFilterUnmodified = serviceFilter;
577 m_trackedServiceFilter = serviceFilter;
578 }
579 m_trackedServiceReference = null;
580 return this;
581 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000582
583 /**
584 * Sets the name of the service that should be tracked. You can either specify
585 * only the name, or the name and a reference. In the latter case, the service reference
586 * is used to track the service and should only return services of the type that was
587 * specified in the name.
588 *
589 * @param serviceName the name of the service
590 * @param serviceReference the service reference to track
591 * @return this service dependency
592 */
593 public synchronized ServiceDependency setService(Class serviceName, ServiceReference serviceReference) {
594 ensureNotActive();
595 if (serviceName == null) {
596 throw new IllegalArgumentException("Service name cannot be null.");
597 }
598 m_trackedServiceName = serviceName;
599 m_trackedServiceReference = serviceReference;
600 m_trackedServiceFilterUnmodified = null;
601 m_trackedServiceFilter = null;
602 return this;
603 }
604
605 /**
606 * Sets the default implementation for this service dependency. You can use this to supply
607 * your own implementation that will be used instead of a Null Object when the dependency is
608 * not available. This is also convenient if the service dependency is not an interface
609 * (which would cause the Null Object creation to fail) but a class.
610 *
611 * @param implementation the instance to use or the class to instantiate if you want to lazily
612 * instantiate this implementation
613 * @return this service dependency
614 */
615 public synchronized ServiceDependency setDefaultImplementation(Object implementation) {
616 ensureNotActive();
617 m_defaultImplementation = implementation;
618 return this;
619 }
620
621 /**
622 * Sets the required flag which determines if this service is required or not.
623 *
624 * @param required the required flag
625 * @return this service dependency
626 */
627 public synchronized ServiceDependency setRequired(boolean required) {
628 ensureNotActive();
Marcel Offermansb196d722009-11-26 17:12:12 +0000629 setIsRequired(required);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000630 return this;
631 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000632
633 public ServiceDependency setInstanceBound(boolean isInstanceBound) {
Marcel Offermans61a81142010-04-02 15:16:50 +0000634 setIsInstanceBound(isInstanceBound);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000635 return this;
636 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000637
638 /**
639 * Sets auto configuration for this service. Auto configuration allows the
640 * dependency to fill in any attributes in the service implementation that
641 * are of the same type as this dependency. Default is on.
642 *
643 * @param autoConfig the value of auto config
644 * @return this service dependency
645 */
646 public synchronized ServiceDependency setAutoConfig(boolean autoConfig) {
647 ensureNotActive();
648 m_autoConfig = autoConfig;
649 m_autoConfigInvoked = true;
650 return this;
651 }
652
653 /**
654 * Sets auto configuration for this service. Auto configuration allows the
655 * dependency to fill in the attribute in the service implementation that
656 * has the same type and instance name.
657 *
658 * @param instanceName the name of attribute to auto config
659 * @return this service dependency
660 */
661 public synchronized ServiceDependency setAutoConfig(String instanceName) {
662 ensureNotActive();
663 m_autoConfig = (instanceName != null);
664 m_autoConfigInstance = instanceName;
665 m_autoConfigInvoked = true;
666 return this;
667 }
668
669 /**
670 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
671 * dependency is added or removed. When you specify callbacks, the auto configuration
672 * feature is automatically turned off, because we're assuming you don't need it in this
673 * case.
674 *
675 * @param added the method to call when a service was added
676 * @param removed the method to call when a service was removed
677 * @return this service dependency
678 */
679 public synchronized ServiceDependency setCallbacks(String added, String removed) {
680 return setCallbacks(null, added, null, removed);
681 }
682
683 /**
684 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
685 * dependency is added, changed or removed. When you specify callbacks, the auto
686 * configuration feature is automatically turned off, because we're assuming you don't
687 * need it in this case.
688 *
689 * @param added the method to call when a service was added
690 * @param changed the method to call when a service was changed
691 * @param removed the method to call when a service was removed
692 * @return this service dependency
693 */
694 public synchronized ServiceDependency setCallbacks(String added, String changed, String removed) {
695 return setCallbacks(null, added, changed, removed);
696 }
697
698 /**
699 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
700 * dependency is added or removed. They are called on the instance you provide. When you
701 * specify callbacks, the auto configuration feature is automatically turned off, because
702 * we're assuming you don't need it in this case.
703 *
704 * @param instance the instance to call the callbacks on
705 * @param added the method to call when a service was added
706 * @param removed the method to call when a service was removed
707 * @return this service dependency
708 */
709 public synchronized ServiceDependency setCallbacks(Object instance, String added, String removed) {
710 return setCallbacks(instance, added, null, removed);
711 }
712
713 /**
714 * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
715 * dependency is added, changed or removed. They are called on the instance you provide. When you
716 * specify callbacks, the auto configuration feature is automatically turned off, because
717 * we're assuming you don't need it in this case.
718 *
719 * @param instance the instance to call the callbacks on
720 * @param added the method to call when a service was added
721 * @param changed the method to call when a service was changed
722 * @param removed the method to call when a service was removed
723 * @return this service dependency
724 */
725 public synchronized ServiceDependency setCallbacks(Object instance, String added, String changed, String removed) {
726 ensureNotActive();
727 // if at least one valid callback is specified, we turn off auto configuration, unless
728 // someone already explicitly invoked autoConfig
729 if ((added != null || removed != null || changed != null) && ! m_autoConfigInvoked) {
730 setAutoConfig(false);
731 }
732 m_callbackInstance = instance;
733 m_callbackAdded = added;
734 m_callbackChanged = changed;
735 m_callbackRemoved = removed;
736 return this;
737 }
738
739 private void ensureNotActive() {
740 if (m_tracker != null) {
741 throw new IllegalStateException("Cannot modify state while active.");
742 }
743 }
744
745 public synchronized String toString() {
746 return "ServiceDependency[" + m_trackedServiceName + " " + m_trackedServiceFilterUnmodified + "]";
747 }
748
749 public String getAutoConfigName() {
750 return m_autoConfigInstance;
751 }
Marcel Offermans001db052009-12-08 08:58:40 +0000752
753 public Object getAutoConfigInstance() {
754 return lookupService();
755 }
756
757 public Class getAutoConfigType() {
758 return getInterface();
759 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000760
761 public String getName() {
762 StringBuilder sb = new StringBuilder();
Marcel Offermansb1959f42010-07-01 12:23:51 +0000763 if (m_trackedServiceName != null) {
764 sb.append(m_trackedServiceName.getName());
765 if (m_trackedServiceFilterUnmodified != null) {
766 sb.append(' ');
767 sb.append(m_trackedServiceFilterUnmodified);
768 }
769 }
770 if (m_trackedServiceReference != null) {
771 sb.append("service.id=" + m_trackedServiceReference.getProperty(Constants.SERVICE_ID));
Marcel Offermansa962bc92009-11-21 17:59:33 +0000772 }
773 return sb.toString();
774 }
775
776 public int getState() {
777 return (isAvailable() ? 1 : 0) + (isRequired() ? 2 : 0);
778 }
779
780 public String getType() {
781 return "service";
782 }
Marcel Offermans001db052009-12-08 08:58:40 +0000783
784 public void invokeAdded(DependencyService service) {
Marcel Offermansbde9a432010-05-11 08:01:28 +0000785 ServiceReference[] refs = m_tracker.getServiceReferences();
786 if (refs != null) {
787 for (int i = 0; i < refs.length; i++) {
788 ServiceReference sr = refs[i];
789 Object svc = m_context.getService(sr);
790 invokeAdded(service, sr, svc);
791 }
792 }
793 m_references = refs;
Marcel Offermans001db052009-12-08 08:58:40 +0000794 }
Marcel Offermansbde9a432010-05-11 08:01:28 +0000795
Marcel Offermans001db052009-12-08 08:58:40 +0000796 public void invokeRemoved(DependencyService service) {
Marcel Offermansbde9a432010-05-11 08:01:28 +0000797 ServiceReference[] refs = m_references;
798 if (refs != null) {
799 for (int i = 0; i < refs.length; i++) {
800 ServiceReference sr = refs[i];
801 Object svc = m_context.getService(sr);
802 invokeRemoved(service, sr, svc);
803 }
804 }
805 m_references = null;
Marcel Offermans001db052009-12-08 08:58:40 +0000806 }
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000807
808 public Dictionary getProperties() {
809 // TODO Auto-generated method stub
810 return null;
811 }
812
813 public boolean isPropagated() {
814 // TODO Auto-generated method stub
815 return false;
816 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000817}