blob: f5f4c90c37206e3de9994f521b74dbfbc94d4f30 [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 */
19package org.apache.felix.dependencymanager;
20
21import java.lang.reflect.Constructor;
22import java.lang.reflect.Field;
23import java.lang.reflect.InvocationTargetException;
24import java.lang.reflect.Method;
25import java.lang.reflect.Proxy;
26import java.util.ArrayList;
27import java.util.Dictionary;
28import java.util.Enumeration;
29import java.util.HashMap;
30import java.util.Hashtable;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34import java.util.Properties;
35
36import org.osgi.framework.BundleContext;
37import org.osgi.framework.ServiceRegistration;
38
39/**
40 * Service implementation.
41 *
42 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
43 */
44public class ServiceImpl implements Service, ServiceComponent {
45 private static final Class[] VOID = new Class[] {};
46 private static final ServiceRegistration NULL_REGISTRATION;
47 private static final ServiceStateListener[] SERVICE_STATE_LISTENER_TYPE = new ServiceStateListener[] {};
48
49 private final BundleContext m_context;
50 private final DependencyManager m_manager;
51
52 // configuration (static)
53 private String m_callbackInit;
54 private String m_callbackStart;
55 private String m_callbackStop;
56 private String m_callbackDestroy;
57 private Object m_serviceName;
58 private Object m_implementation;
59
60 // configuration (dynamic, but does not affect state)
61 private Dictionary m_serviceProperties;
62
63 // configuration (dynamic, and affects state)
64 private ArrayList m_dependencies = new ArrayList();
65
66 // runtime state (calculated from dependencies)
67 private State m_state;
68
69 // runtime state (changes because of state changes)
70 private Object m_serviceInstance;
71 private ServiceRegistration m_registration;
72
73 // service state listeners
74 private final List m_stateListeners = new ArrayList();
75
76 // work queue
77 private final SerialExecutor m_executor = new SerialExecutor();
78
79 // instance factory
80 private Object m_instanceFactory;
81 private String m_instanceFactoryCreateMethod;
82
83 // composition manager
84 private Object m_compositionManager;
85 private String m_compositionManagerGetMethod;
86 private Object m_compositionManagerInstance;
87
88 // internal logging
89 private final Logger m_logger;
90 private ServiceRegistration m_serviceRegistration;
91 private Map m_autoConfig = new HashMap();
92 private Map m_autoConfigInstance = new HashMap();
93
94 public ServiceImpl(BundleContext context, DependencyManager manager, Logger logger) {
95 m_logger = logger;
96 m_state = new State((List) m_dependencies.clone(), false);
97 m_context = context;
98 m_manager = manager;
99 m_callbackInit = "init";
100 m_callbackStart = "start";
101 m_callbackStop = "stop";
102 m_callbackDestroy = "destroy";
103 m_implementation = null;
104 m_autoConfig.put(BundleContext.class, Boolean.TRUE);
105 m_autoConfig.put(ServiceRegistration.class, Boolean.TRUE);
106 m_autoConfig.put(DependencyManager.class, Boolean.TRUE);
107 }
108
109 private void calculateStateChanges(final State oldState, final State newState) {
110 if (oldState.isWaitingForRequired() && newState.isTrackingOptional()) {
111 m_executor.enqueue(new Runnable() {
112 public void run() {
113 activateService(newState);
114 }});
115 }
116 if (oldState.isTrackingOptional() && newState.isWaitingForRequired()) {
117 m_executor.enqueue(new Runnable() {
118 public void run() {
119 deactivateService(oldState);
120 }});
121 }
122 if (oldState.isInactive() && (newState.isTrackingOptional())) {
123 m_executor.enqueue(new Runnable() {
124 public void run() {
125 activateService(newState);
126 }});
127 }
128 if (oldState.isInactive() && (newState.isWaitingForRequired())) {
129 m_executor.enqueue(new Runnable() {
130 public void run() {
131 startTrackingRequired(newState);
132 }});
133 }
134 if ((oldState.isWaitingForRequired()) && newState.isInactive()) {
135 m_executor.enqueue(new Runnable() {
136 public void run() {
137 stopTrackingRequired(oldState);
138 }});
139 }
140 if ((oldState.isTrackingOptional()) && newState.isInactive()) {
141 m_executor.enqueue(new Runnable() {
142 public void run() {
143 deactivateService(oldState);
144 stopTrackingRequired(oldState);
145 }});
146 }
147 m_executor.execute();
148 }
149
150 public Service add(final Dependency dependency) {
151 State oldState, newState;
152 synchronized (m_dependencies) {
153 oldState = m_state;
154 m_dependencies.add(dependency);
155 }
156 if (oldState.isTrackingOptional() || (oldState.isWaitingForRequired() && dependency.isRequired())) {
157 dependency.start(this);
158 }
159 synchronized (m_dependencies) {
160 newState = new State((List) m_dependencies.clone(), !oldState.isInactive());
161 m_state = newState;
162 calculateStateChanges(oldState, newState);
163 }
164 return this;
165 }
166
167 public Service remove(Dependency dependency) {
168 State oldState, newState;
169 synchronized (m_dependencies) {
170 oldState = m_state;
171 m_dependencies.remove(dependency);
172 }
173 if (oldState.isTrackingOptional() || (oldState.isWaitingForRequired() && dependency.isRequired())) {
174 dependency.stop(this);
175 }
176 synchronized (m_dependencies) {
177 newState = new State((List) m_dependencies.clone(), !oldState.isInactive());
178 m_state = newState;
179 }
180 calculateStateChanges(oldState, newState);
181 return this;
182 }
183
184 public List getDependencies() {
185 synchronized (m_dependencies) {
186 return (List) m_dependencies.clone();
187 }
188 }
189
190 public ServiceRegistration getServiceRegistration() {
191 return m_registration;
192 }
193
194 public Object getService() {
195 return m_serviceInstance;
196 }
197
198 public void dependencyAvailable(final Dependency dependency) {
199 State oldState, newState;
200 synchronized (m_dependencies) {
201 oldState = m_state;
202 newState = new State((List) m_dependencies.clone(), !oldState.isInactive());
203 m_state = newState;
204 }
205 calculateStateChanges(oldState, newState);
206 if (newState.isTrackingOptional()) {
207 m_executor.enqueue(new Runnable() {
208 public void run() {
209 updateInstance(dependency);
210 }
211 });
212 m_executor.execute();
213 }
214 }
215
216 public void dependencyChanged(final Dependency dependency) {
217 State state;
218 synchronized (m_dependencies) {
219 state = m_state;
220 }
221 if (state.isTrackingOptional()) {
222 m_executor.enqueue(new Runnable() {
223 public void run() {
224 updateInstance(dependency);
225 }
226 });
227 m_executor.execute();
228 }
229 }
230
231 public void dependencyUnavailable(final Dependency dependency) {
232 State oldState, newState;
233 synchronized (m_dependencies) {
234 oldState = m_state;
235 newState = new State((List) m_dependencies.clone(), !oldState.isInactive());
236 m_state = newState;
237 }
238 calculateStateChanges(oldState, newState);
239 if (newState.isTrackingOptional()) {
240 m_executor.enqueue(new Runnable() {
241 public void run() {
242 updateInstance(dependency);
243 }
244 });
245 m_executor.execute();
246 }
247 }
248
249 public synchronized void start() {
250 m_serviceRegistration = m_context.registerService(ServiceComponent.class.getName(), this, null);
251 State oldState, newState;
252 synchronized (m_dependencies) {
253 oldState = m_state;
254 newState = new State((List) m_dependencies.clone(), true);
255 m_state = newState;
256 }
257 calculateStateChanges(oldState, newState);
258 }
259
260 public synchronized void stop() {
261 State oldState, newState;
262 synchronized (m_dependencies) {
263 oldState = m_state;
264 newState = new State((List) m_dependencies.clone(), false);
265 m_state = newState;
266 }
267 calculateStateChanges(oldState, newState);
268 m_serviceRegistration.unregister();
269 }
270
271 public synchronized Service setInterface(String serviceName, Dictionary properties) {
272 ensureNotActive();
273 m_serviceName = serviceName;
274 m_serviceProperties = properties;
275 return this;
276 }
277
278 public synchronized Service setInterface(String[] serviceName, Dictionary properties) {
279 ensureNotActive();
280 m_serviceName = serviceName;
281 m_serviceProperties = properties;
282 return this;
283 }
284
285 public synchronized Service setCallbacks(String init, String start, String stop, String destroy) {
286 ensureNotActive();
287 m_callbackInit = init;
288 m_callbackStart = start;
289 m_callbackStop = stop;
290 m_callbackDestroy = destroy;
291 return this;
292 }
293
294 public synchronized Service setImplementation(Object implementation) {
295 ensureNotActive();
296 m_implementation = implementation;
297 return this;
298 }
299
300 public synchronized Service setFactory(Object factory, String createMethod) {
301 ensureNotActive();
302 m_instanceFactory = factory;
303 m_instanceFactoryCreateMethod = createMethod;
304 return this;
305 }
306
307 public synchronized Service setFactory(String createMethod) {
308 return setFactory(null, createMethod);
309 }
310
311 public synchronized Service setComposition(Object instance, String getMethod) {
312 ensureNotActive();
313 m_compositionManager = instance;
314 m_compositionManagerGetMethod = getMethod;
315 return this;
316 }
317
318 public synchronized Service setComposition(String getMethod) {
319 return setComposition(null, getMethod);
320 }
321
322 public String toString() {
323 return "ServiceImpl[" + m_serviceName + " " + m_implementation + "]";
324 }
325
326 public synchronized Dictionary getServiceProperties() {
327 if (m_serviceProperties != null) {
328 return (Dictionary) ((Hashtable) m_serviceProperties).clone();
329 }
330 return null;
331 }
332
333 public synchronized void setServiceProperties(Dictionary serviceProperties) {
334 m_serviceProperties = serviceProperties;
335 if (isRegistered() && (m_serviceName != null)) {
336 m_registration.setProperties(calculateServiceProperties());
337 }
338 }
339
340 // service state listener methods
341 public void addStateListener(ServiceStateListener listener) {
342 synchronized (m_stateListeners) {
343 m_stateListeners.add(listener);
344 }
345 // when we register as a listener and the service is already started
346 // make sure we invoke the right callbacks so the listener knows
347 State state;
348 synchronized (m_dependencies) {
349 state = m_state;
350 }
351 if (state.isTrackingOptional()) {
352 listener.starting(this);
353 listener.started(this);
354 }
355 }
356
357 public void removeStateListener(ServiceStateListener listener) {
358 synchronized (m_stateListeners) {
359 m_stateListeners.remove(listener);
360 }
361 }
362
363 void removeStateListeners() {
364 synchronized (m_stateListeners) {
365 m_stateListeners.clear();
366 }
367 }
368
369 private void stateListenersStarting() {
370 ServiceStateListener[] list = getListeners();
371 for (int i = 0; i < list.length; i++) {
372 try {
373 list[i].starting(this);
374 }
375 catch (Throwable t) {
376 m_logger.log(Logger.LOG_ERROR, "Error invoking listener starting method.", t);
377 }
378 }
379 }
380
381 private void stateListenersStarted() {
382 ServiceStateListener[] list = getListeners();
383 for (int i = 0; i < list.length; i++) {
384 try {
385 list[i].started(this);
386 }
387 catch (Throwable t) {
388 m_logger.log(Logger.LOG_ERROR, "Error invoking listener started method.", t);
389 }
390 }
391 }
392
393 private void stateListenersStopping() {
394 ServiceStateListener[] list = getListeners();
395 for (int i = 0; i < list.length; i++) {
396 try {
397 list[i].stopping(this);
398 }
399 catch (Throwable t) {
400 m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopping method.", t);
401 }
402 }
403 }
404
405 private void stateListenersStopped() {
406 ServiceStateListener[] list = getListeners();
407 for (int i = 0; i < list.length; i++) {
408 try {
409 list[i].stopped(this);
410 }
411 catch (Throwable t) {
412 m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopped method.", t);
413 }
414 }
415 }
416
417 private ServiceStateListener[] getListeners() {
418 synchronized (m_stateListeners) {
419 return (ServiceStateListener[]) m_stateListeners.toArray(SERVICE_STATE_LISTENER_TYPE);
420 }
421 }
422
423 private void activateService(State state) {
424 String init, start;
425 synchronized (this) {
426 init = m_callbackInit;
427 start = m_callbackStart;
428 }
429 // service activation logic, first we initialize the service instance itself
430 // meaning it is created if necessary and the bundle context is set
431 initService();
432 // then we invoke the init callback so the service can further initialize
433 // itself
434 invoke(init);
435 // now is the time to configure the service, meaning all required
436 // dependencies will be set and any callbacks called
437 configureService(state);
438 // inform the state listeners we're starting
439 stateListenersStarting();
440 // invoke the start callback, since we're now ready to be used
441 invoke(start);
442 // start tracking optional services
443 startTrackingOptional(state);
444 // register the service in the framework's service registry
445 registerService();
446 // inform the state listeners we've started
447 stateListenersStarted();
448 }
449
450 private void deactivateService(State state) {
451 String stop, destroy;
452 synchronized (this) {
453 stop = m_callbackStop;
454 destroy = m_callbackDestroy;
455 }
456 // service deactivation logic, first inform the state listeners
457 // we're stopping
458 stateListenersStopping();
459 // then, unregister the service from the framework
460 unregisterService();
461 // stop tracking optional services
462 stopTrackingOptional(state);
463 // invoke the stop callback
464 invoke(stop);
465 // inform the state listeners we've stopped
466 stateListenersStopped();
467 // invoke the destroy callback
468 invoke(destroy);
469 // destroy the service instance
470 destroyService(state);
471 }
472
473 private void invoke(String name) {
474 if (name != null) {
475 // invoke method if it exists
476 try {
477 Class clazz = m_serviceInstance.getClass();
478 while (clazz != null) {
479 try {
480 Method method = clazz.getDeclaredMethod(name, null);
481 if (method != null) {
482 method.setAccessible(true);
483 try {
484 method.invoke(m_serviceInstance, null);
485 }
486 catch (InvocationTargetException e) {
487 m_logger.log(Logger.LOG_ERROR, "Exception while invoking method " + method + ".", e);
488 }
489 return;
490 }
491 }
492 catch (NoSuchMethodException e) {
493 // ignore this, we keep searching if the method does not exist
494 }
495 clazz = clazz.getSuperclass();
496 }
497 }
498 catch (Exception e) {
499 m_logger.log(Logger.LOG_ERROR, "Error trying to invoke method named " + name + ".", e);
500 }
501 }
502 }
503
504 private void startTrackingOptional(State state) {
505 Iterator i = state.getDependencies().iterator();
506 while (i.hasNext()) {
507 Dependency dependency = (Dependency) i.next();
508 if (!dependency.isRequired()) {
509 dependency.start(this);
510 }
511 }
512 }
513
514 private void stopTrackingOptional(State state) {
515 Iterator i = state.getDependencies().iterator();
516 while (i.hasNext()) {
517 Dependency dependency = (Dependency) i.next();
518 if (!dependency.isRequired()) {
519 dependency.stop(this);
520 }
521 }
522 }
523
524 private void startTrackingRequired(State state) {
525 Iterator i = state.getDependencies().iterator();
526 while (i.hasNext()) {
527 Dependency dependency = (Dependency) i.next();
528 if (dependency.isRequired()) {
529 dependency.start(this);
530 }
531 }
532 }
533
534 private void stopTrackingRequired(State state) {
535 Iterator i = state.getDependencies().iterator();
536 while (i.hasNext()) {
537 Dependency dependency = (Dependency) i.next();
538 if (dependency.isRequired()) {
539 dependency.stop(this);
540 }
541 }
542 }
543
544 private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
545 Constructor constructor = clazz.getConstructor(VOID);
546 constructor.setAccessible(true);
547 return clazz.newInstance();
548 }
549
550 void initService() {
551 if (m_serviceInstance == null) {
552 if (m_implementation instanceof Class) {
553 // instantiate
554 try {
555 m_serviceInstance = createInstance((Class) m_implementation);
556 }
557 catch (Exception e) {
558 m_logger.log(Logger.LOG_ERROR, "Could not create service instance of class " + m_implementation + ".", e);
559 }
560 }
561 else {
562 if (m_instanceFactoryCreateMethod != null) {
563 Object factory = null;
564 if (m_instanceFactory != null) {
565 if (m_instanceFactory instanceof Class) {
566 try {
567 factory = createInstance((Class) m_instanceFactory);
568 }
569 catch (Exception e) {
570 m_logger.log(Logger.LOG_ERROR, "Could not create factory instance of class " + m_instanceFactory + ".", e);
571 }
572 }
573 else {
574 factory = m_instanceFactory;
575 }
576 }
577 else {
578 // TODO review if we want to try to default to something if not specified
579 // for now the JavaDoc of setFactory(method) reflects the fact that we need
580 // to review it
581 }
582 if (factory == null) {
583 m_logger.log(Logger.LOG_ERROR, "Factory cannot be null.");
584 }
585 else {
586 try {
587 Method m = factory.getClass().getDeclaredMethod(m_instanceFactoryCreateMethod, null);
588 m_serviceInstance = m.invoke(factory, null);
589 }
590 catch (Exception e) {
591 m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
592 }
593 }
594 }
595 if (m_implementation == null) {
596 m_logger.log(Logger.LOG_ERROR, "Implementation cannot be null.");
597 }
598 if (m_serviceInstance == null) {
599 m_serviceInstance = m_implementation;
600 }
601 }
602 // configure the bundle context
603 if (((Boolean) m_autoConfig.get(BundleContext.class)).booleanValue()) {
604 configureImplementation(BundleContext.class, m_context, (String) m_autoConfigInstance.get(BundleContext.class));
605 }
606 if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
607 configureImplementation(ServiceRegistration.class, NULL_REGISTRATION, (String) m_autoConfigInstance.get(ServiceRegistration.class));
608 }
609 if (((Boolean) m_autoConfig.get(DependencyManager.class)).booleanValue()) {
610 configureImplementation(DependencyManager.class, m_manager, (String) m_autoConfigInstance.get(DependencyManager.class));
611 }
612 }
613 }
614
615 public void setAutoConfig(Class clazz, boolean autoConfig) {
616 m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
617 }
618
619 public void setAutoConfig(Class clazz, String instanceName) {
620 m_autoConfig.put(clazz, Boolean.valueOf(instanceName != null));
621 m_autoConfigInstance.put(clazz, instanceName);
622 }
623
624 private void configureService(State state) {
625 // configure all services (the optional dependencies might be configured
626 // as null objects but that's what we want at this point)
627 configureServices(state);
628 }
629
630 private void destroyService(State state) {
631 unconfigureServices(state);
632 m_serviceInstance = null;
633 }
634
635 private void registerService() {
636 if (m_serviceName != null) {
637 ServiceRegistrationImpl wrapper = new ServiceRegistrationImpl();
638 m_registration = wrapper;
639 if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
640 configureImplementation(ServiceRegistration.class, m_registration, (String) m_autoConfigInstance.get(ServiceRegistration.class));
641 }
642
643 // service name can either be a string or an array of strings
644 ServiceRegistration registration;
645
646 // determine service properties
647 Dictionary properties = calculateServiceProperties();
648
649 // register the service
650 try {
651 if (m_serviceName instanceof String) {
652 registration = m_context.registerService((String) m_serviceName, m_serviceInstance, properties);
653 }
654 else {
655 registration = m_context.registerService((String[]) m_serviceName, m_serviceInstance, properties);
656 }
657 wrapper.setServiceRegistration(registration);
658 }
659 catch (IllegalArgumentException iae) {
660 m_logger.log(Logger.LOG_ERROR, "Could not register service " + m_serviceInstance, iae);
661 // set the registration to an illegal state object, which will make all invocations on this
662 // wrapper fail with an ISE (which also occurs when the SR becomes invalid)
663 wrapper.setIllegalState();
664 }
665 }
666 }
667
668 private Dictionary calculateServiceProperties() {
669 Dictionary properties = new Properties();
670 addTo(properties, m_serviceProperties);
671 for (int i = 0; i < m_dependencies.size(); i++) {
672 Dependency d = (Dependency) m_dependencies.get(i);
673 if (d instanceof ConfigurationDependency) {
674 ConfigurationDependency cd = (ConfigurationDependency) d;
675 if (cd.isPropagated()) {
676 Dictionary dict = cd.getConfiguration();
677 addTo(properties, dict);
678 }
679 }
680 }
681 if (properties.size() == 0) {
682 properties = null;
683 }
684 return properties;
685 }
686
687 private void addTo(Dictionary properties, Dictionary additional) {
688 if (properties == null) {
689 throw new IllegalArgumentException("Dictionary to add to cannot be null.");
690 }
691 if (additional != null) {
692 Enumeration e = additional.keys();
693 while (e.hasMoreElements()) {
694 Object key = e.nextElement();
695 properties.put(key, additional.get(key));
696 }
697 }
698 }
699
700 private void unregisterService() {
701 if (m_serviceName != null) {
702 m_registration.unregister();
703 configureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
704 }
705 }
706
707 private void updateInstance(Dependency dependency) {
708 if (dependency instanceof ServiceDependency) {
709 ServiceDependency sd = (ServiceDependency) dependency;
710 // update the dependency in the service instance (it will use
711 // a null object if necessary)
712 if (sd.isAutoConfig()) {
713 configureImplementation(sd.getInterface(), sd.getService(), sd.getAutoConfigName());
714 }
715 }
716 else if (dependency instanceof ConfigurationDependency) {
717 ConfigurationDependency cd = (ConfigurationDependency) dependency;
718 if (cd.isPropagated()) {
719 // change service properties accordingly
720 Dictionary props = calculateServiceProperties();
721 m_registration.setProperties(props);
722 }
723 }
724 }
725
726 /**
727 * Configure a field in the service implementation. The service implementation
728 * is searched for fields that have the same type as the class that was specified
729 * and for each of these fields, the specified instance is filled in.
730 *
731 * @param clazz the class to search for
732 * @param instance the instance to fill in
733 * @param instanceName the name of the instance to fill in, or <code>null</code> if not used
734 */
735 private void configureImplementation(Class clazz, Object instance, String instanceName) {
736 Object[] instances = getCompositionInstances();
737 if (instances != null) {
738 for (int i = 0; i < instances.length; i++) {
739 Object serviceInstance = instances[i];
740 Class serviceClazz = serviceInstance.getClass();
741 while (serviceClazz != null) {
742 Field[] fields = serviceClazz.getDeclaredFields();
743 for (int j = 0; j < fields.length; j++) {
744 if (fields[j].getType().equals(clazz) && (instanceName == null || fields[j].getName().equals(instanceName))) {
745 try {
746 fields[j].setAccessible(true);
747 // synchronized makes sure the field is actually written to immediately
748 synchronized (new Object()) {
749 fields[j].set(serviceInstance, instance);
750 }
751 }
752 catch (Exception e) {
753 m_logger.log(Logger.LOG_ERROR, "Could not set field " + fields[j], e);
754 return;
755 }
756 }
757 }
758 serviceClazz = serviceClazz.getSuperclass();
759 }
760 }
761 }
762 }
763
764 public Object[] getCompositionInstances() {
765 Object[] instances = null;
766 if (m_compositionManagerGetMethod != null) {
767 if (m_compositionManager != null) {
768 m_compositionManagerInstance = m_compositionManager;
769 }
770 else {
771 m_compositionManagerInstance = m_serviceInstance;
772 }
773 if (m_compositionManagerInstance != null) {
774 try {
775 Method m = m_compositionManagerInstance.getClass().getDeclaredMethod(m_compositionManagerGetMethod, null);
776 m.setAccessible(true);
777 instances = (Object[]) m.invoke(m_compositionManagerInstance, null);
778 }
779 catch (Exception e) {
780 m_logger.log(Logger.LOG_ERROR, "Could not obtain instances from the composition manager.", e);
781 instances = new Object[] { m_serviceInstance };
782 }
783 }
784 }
785 else {
786 instances = new Object[] { m_serviceInstance };
787 }
788 return instances;
789 }
790
791 private void configureImplementation(Class clazz, Object instance) {
792 configureImplementation(clazz, instance, null);
793 }
794
795 private void configureServices(State state) {
796 Iterator i = state.getDependencies().iterator();
797 while (i.hasNext()) {
798 Dependency dependency = (Dependency) i.next();
799 if (dependency instanceof ServiceDependency) {
800 ServiceDependency sd = (ServiceDependency) dependency;
801 if (sd.isAutoConfig()) {
802 if (sd.isRequired()) {
803 configureImplementation(sd.getInterface(), sd.getService(), sd.getAutoConfigName());
804 }
805 else {
806 // for optional services, we do an "ad-hoc" lookup to inject the service if it is
807 // already available even though the tracker has not yet been started
808 configureImplementation(sd.getInterface(), sd.lookupService(), sd.getAutoConfigName());
809 }
810 }
811 // for required dependencies, we invoke any callbacks here
812 if (sd.isRequired()) {
813 sd.invokeAdded();
814 }
815 }
816 }
817 }
818
819 private void unconfigureServices(State state) {
820 Iterator i = state.getDependencies().iterator();
821 while (i.hasNext()) {
822 Dependency dependency = (Dependency) i.next();
823 if (dependency instanceof ServiceDependency) {
824 ServiceDependency sd = (ServiceDependency) dependency;
825 // for required dependencies, we invoke any callbacks here
826 if (sd.isRequired()) {
827 sd.invokeRemoved();
828 }
829 }
830 }
831 }
832
833 private void ensureNotActive() {
834 State state;
835 synchronized (m_dependencies) {
836 state = m_state;
837 }
838 if (!state.isInactive()) {
839 throw new IllegalStateException("Cannot modify state while active.");
840 }
841 }
842 boolean isRegistered() {
843 State state;
844 synchronized (m_dependencies) {
845 state = m_state;
846 }
847 return (state.isTrackingOptional());
848 }
849
850 // ServiceComponent interface
851
852 static class SCDImpl implements ServiceComponentDependency {
853 private final String m_name;
854 private final int m_state;
855 private final String m_type;
856
857 public SCDImpl(String name, int state, String type) {
858 m_name = name;
859 m_state = state;
860 m_type = type;
861 }
862
863 public String getName() {
864 return m_name;
865 }
866
867 public int getState() {
868 return m_state;
869 }
870
871 public String getType() {
872 return m_type;
873 }
874 }
875
876 public ServiceComponentDependency[] getComponentDependencies() {
877 List deps = getDependencies();
878 if (deps != null) {
879 ServiceComponentDependency[] result = new ServiceComponentDependency[deps.size()];
880 for (int i = 0; i < result.length; i++) {
881 Dependency dep = (Dependency) deps.get(i);
882 if (dep instanceof ServiceComponentDependency) {
883 result[i] = (ServiceComponentDependency) dep;
884 }
885 else {
886 result[i] = new SCDImpl(dep.toString(), (dep.isAvailable() ? 1 : 0) + (dep.isRequired() ? 2 : 0), dep.getClass().getName());
887 }
888 }
889 return result;
890 }
891 return null;
892 }
893
894 public String getName() {
895 if (m_serviceName instanceof String[]) {
896 StringBuffer sb = new StringBuffer();
897 String[] names = (String[]) m_serviceName;
898 for (int i = 0; i < names.length; i++) {
899 if (i > 0) {
900 sb.append(", ");
901 }
902 sb.append(names[i]);
903 }
904 return sb.toString();
905 }
906 else if (m_serviceName instanceof String) {
907 return m_serviceName.toString();
908 }
909 else {
910 return m_implementation.toString();
911 }
912 }
913
914 public int getState() {
915 return (isRegistered() ? 1 : 0);
916 }
917
918 static {
919 NULL_REGISTRATION = (ServiceRegistration) Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(), new Class[] {ServiceRegistration.class}, new DefaultNullObject());
920 }
921}