blob: 13ff38e2a67b9495b66851d56f86240c6ac40522 [file] [log] [blame]
Pierre De Rop3a00a212015-03-01 09:27:46 +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.dm.impl;
20
21import static org.apache.felix.dm.ComponentState.INACTIVE;
22import static org.apache.felix.dm.ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED;
23import static org.apache.felix.dm.ComponentState.TRACKING_OPTIONAL;
24import static org.apache.felix.dm.ComponentState.WAITING_FOR_REQUIRED;
25
26import java.lang.reflect.Constructor;
27import java.lang.reflect.InvocationTargetException;
28import java.lang.reflect.Method;
29import java.lang.reflect.Proxy;
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.Dictionary;
33import java.util.Enumeration;
34import java.util.HashMap;
35import java.util.Hashtable;
Pierre De Ropc8295c22015-06-04 10:15:35 +000036import java.util.IdentityHashMap;
Pierre De Rop3a00a212015-03-01 09:27:46 +000037import java.util.List;
38import java.util.Map;
39import java.util.Set;
40import java.util.concurrent.ConcurrentHashMap;
41import java.util.concurrent.ConcurrentSkipListSet;
42import java.util.concurrent.CopyOnWriteArrayList;
43import java.util.concurrent.Executor;
44import java.util.concurrent.atomic.AtomicBoolean;
45import java.util.concurrent.atomic.AtomicLong;
46
47import org.apache.felix.dm.Component;
48import org.apache.felix.dm.ComponentDeclaration;
49import org.apache.felix.dm.ComponentDependencyDeclaration;
Pierre De Ropc8295c22015-06-04 10:15:35 +000050import org.apache.felix.dm.ComponentExecutorFactory;
Pierre De Rop3a00a212015-03-01 09:27:46 +000051import org.apache.felix.dm.ComponentState;
52import org.apache.felix.dm.ComponentStateListener;
53import org.apache.felix.dm.Dependency;
54import org.apache.felix.dm.DependencyManager;
55import org.apache.felix.dm.Logger;
56import org.apache.felix.dm.context.ComponentContext;
57import org.apache.felix.dm.context.DependencyContext;
Pierre De Rop3a00a212015-03-01 09:27:46 +000058import org.apache.felix.dm.context.Event;
Pierre De Ropc8295c22015-06-04 10:15:35 +000059import org.apache.felix.dm.context.EventType;
Pierre De Rop3a00a212015-03-01 09:27:46 +000060import org.osgi.framework.Bundle;
61import org.osgi.framework.BundleContext;
62import org.osgi.framework.ServiceRegistration;
63import org.osgi.service.log.LogService;
64
65/**
66 * Dependency Manager Component implementation.
67 *
68 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
69 */
70public class ComponentImpl implements Component, ComponentContext, ComponentDeclaration {
Pierre De Ropc8295c22015-06-04 10:15:35 +000071 /**
72 * NullObject ServiceRegistration that is injected in components that don't provide any services.
73 */
Pierre De Rop3a00a212015-03-01 09:27:46 +000074 private static final ServiceRegistration NULL_REGISTRATION = (ServiceRegistration) Proxy
75 .newProxyInstance(ComponentImpl.class.getClassLoader(),
76 new Class[] { ServiceRegistration.class },
77 new DefaultNullObject());
Pierre De Ropc8295c22015-06-04 10:15:35 +000078
79 /**
80 * Constant Used to get empty constructor by reflection.
81 */
Pierre De Rop3a00a212015-03-01 09:27:46 +000082 private static final Class<?>[] VOID = new Class[] {};
Pierre De Ropc8295c22015-06-04 10:15:35 +000083
84 /**
85 * Default Component Executor, which is by default single threaded. The first thread which schedules a task
86 * is the master thread and will execute all tasks that are scheduled by other threads at the time the master
87 * thread is executing. Internal tasks scheduled by the master thread are executed immediately (inline execution).
88 *
89 * If a ComponentExecutorFactory is provided in the OSGI registry, then this executor will be replaced by the
90 * executor returned by the ComponentExecutorFactory (however, the same semantic of the default executor is used:
91 * all tasks are serially executed).
92 *
93 * @see @link {@link ComponentExecutorFactory}
94 */
Pierre De Rop3a00a212015-03-01 09:27:46 +000095 private volatile Executor m_executor = new SerialExecutor(new Logger(null));
Pierre De Ropc8295c22015-06-04 10:15:35 +000096
97 /**
98 * The current state of the component state machine.
99 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000100 private ComponentState m_state = ComponentState.INACTIVE;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000101
102 /**
103 * Indicates that the handleChange method is currently being executed.
104 */
105 private boolean m_handlingChange;
106
107 /**
108 * List of dependencies. We use a COW list in order to avoid ConcurrentModificationException while iterating on the
109 * list and while a component synchronously add more dependencies from one of its callback method.
110 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000111 private final CopyOnWriteArrayList<DependencyContext> m_dependencies = new CopyOnWriteArrayList<>();
Pierre De Ropc8295c22015-06-04 10:15:35 +0000112
113 /**
114 * List of Component state listeners. We use a COW list in order to avoid ConcurrentModificationException while iterating on the
115 * list and while a component synchronously add more listeners from one of its callback method.
116 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000117 private final List<ComponentStateListener> m_listeners = new CopyOnWriteArrayList<>();
Pierre De Ropc8295c22015-06-04 10:15:35 +0000118
119 /**
120 * Is the component active ?
121 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000122 private boolean m_isStarted;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000123
124 /**
125 * The Component logger.
126 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000127 private final Logger m_logger;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000128
129 /**
130 * The Component bundle context.
131 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000132 private final BundleContext m_context;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000133
134 /**
135 * The DependencyManager object that has created this component.
136 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000137 private final DependencyManager m_manager;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000138
139 /**
140 * The object used to create the component. Can be a class name, or the component implementation instance.
141 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000142 private Object m_componentDefinition;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000143
144 /**
145 * The component instance.
146 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000147 private Object m_componentInstance;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000148
149 /**
150 * The service(s) provided by this component. Can be a String, or a String array.
151 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000152 private volatile Object m_serviceName;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000153
154 /**
155 * The service properties, if this component is providing a service.
156 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000157 private volatile Dictionary<Object, Object> m_serviceProperties;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000158
159 /**
160 * The component service registration. Can be a NullObject in case the component does not provide a service.
161 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000162 private volatile ServiceRegistration m_registration;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000163
164 /**
165 * Map of auto configured fields (BundleContext, ServiceRegistration, DependencyManager, or Component).
166 * By default, all fields mentioned above are auto configured (injected in class fields having the same type).
167 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000168 private final Map<Class<?>, Boolean> m_autoConfig = new ConcurrentHashMap<>();
Pierre De Ropc8295c22015-06-04 10:15:35 +0000169
170 /**
171 * Map of auto configured instance fields that will be used when injected auto configured fields.
172 * @see #m_autoConfig
173 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000174 private final Map<Class<?>, String> m_autoConfigInstance = new ConcurrentHashMap<>();
Pierre De Ropc8295c22015-06-04 10:15:35 +0000175
176 /**
177 * Data structure used to record the elapsed time used by component lifecycle callbacks.
178 * Key = callback name ("init", "start", "stop", "destroy").
179 * Value = elapsed time in nanos.
180 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000181 private final Map<String, Long> m_stopwatch = new ConcurrentHashMap<>();
Pierre De Ropc8295c22015-06-04 10:15:35 +0000182
183 /**
184 * Unique component id.
185 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000186 private final long m_id;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000187
188 /**
189 * Unique ID generator.
190 */
191 private final static AtomicLong m_idGenerator = new AtomicLong();
192
193 /**
194 * Holds all the services of a given dependency context. Caution: the last entry in the skiplist is the highest
195 * ranked service.
196 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000197 private final Map<DependencyContext, ConcurrentSkipListSet<Event>> m_dependencyEvents = new HashMap<>();
Pierre De Ropc8295c22015-06-04 10:15:35 +0000198
199 /**
200 * Flag used to check if this component has been added in a DependencyManager object.
201 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000202 private final AtomicBoolean m_active = new AtomicBoolean(false);
203
Pierre De Ropc8295c22015-06-04 10:15:35 +0000204 /**
205 * Init lifecycle callback. From that method, component are expected to add more extra dependencies.
206 * When this callback is invoked, all required dependencies have been injected.
207 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000208 private volatile String m_callbackInit;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000209
210 /**
211 * Start lifecycle callback. When this method is called, all required + all extra required dependencies defined in the
212 * init callback have been injected. The component may then perform its initialization.
213 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000214 private volatile String m_callbackStart;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000215
216 /**
217 * Stop callback. When this method is called, the component has been unregistered (if it provides any services),
218 * and all optional dependencies have been unbound.
219 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000220 private volatile String m_callbackStop;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000221
222 /**
223 * Destroy callback. When this method is called, all required dependencies defined in the init method have been unbound.
224 * After this method is called, then all required dependencies defined in the Activator will be unbound.
225 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000226 private volatile String m_callbackDestroy;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000227
228 /**
229 * By default, the init/start/stop/destroy callbacks are invoked on the component instance(s).
230 * But you can specify a separate callback instance.
231 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000232 private volatile Object m_callbackInstance;
233
Pierre De Ropc8295c22015-06-04 10:15:35 +0000234 /**
235 * Component Factory instance object, that can be used to instantiate the component instance.
236 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000237 private volatile Object m_instanceFactory;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000238
239 /**
240 * Name of the Factory method to call.
241 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000242 private volatile String m_instanceFactoryCreateMethod;
243
Pierre De Ropc8295c22015-06-04 10:15:35 +0000244 /**
245 * Composition Manager that can be used to create a graph of objects that are used to implement the component.
246 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000247 private volatile Object m_compositionManager;
Pierre De Rop3a00a212015-03-01 09:27:46 +0000248
Pierre De Ropc8295c22015-06-04 10:15:35 +0000249 /**
250 * Name of the method used to invoke in order to get the list of component instance objects.
251 */
252 private volatile String m_compositionManagerGetMethod;
253
254 /**
255 * The composition manager instance object, if specified.
256 */
257 private volatile Object m_compositionManagerInstance;
258
259 /**
260 * The Component bundle.
261 */
262 private final Bundle m_bundle;
263
264 /**
265 * Cache of callback invocation used to avoid calling the same callback twice.
266 * This situation may sometimes happen when the state machine triggers a lifecycle callback ("bind" call), and
267 * when the bind method registers a service which is tracked by another optional component dependency.
268 *
269 * @see org.apache.felix.dm.itest.api.FELIX4913_OptionalCallbackInvokedTwiceTest which reproduces the use case.
270 */
271 private final Map<Event, Event> m_invokeCallbackCache = new IdentityHashMap<>();
Pierre De Rop1eb4a452015-09-18 22:09:45 +0000272
273 /**
274 * Flag used to check if the start callback has been invoked.
275 * We use this flag to ensure that we only inject optional dependencies after the start callback has been called.
276 */
277 private boolean m_startCalled;
Pierre De Ropc8295c22015-06-04 10:15:35 +0000278
279 /**
280 * Default component declaration implementation.
281 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000282 static class SCDImpl implements ComponentDependencyDeclaration {
283 private final String m_name;
284 private final int m_state;
285 private final String m_type;
286
287 public SCDImpl(String name, int state, String type) {
288 m_name = name;
289 m_state = state;
290 m_type = type;
291 }
292
293 public String getName() {
294 return m_name;
295 }
296
297 public String getSimpleName() {
298 return m_name;
299 }
300
301 public String getFilter() {
302 return null;
303 }
304
305 public int getState() {
306 return m_state;
307 }
308
309 public String getType() {
310 return m_type;
311 }
312 }
313
Pierre De Ropc8295c22015-06-04 10:15:35 +0000314 /**
315 * Constructor. Only used for tests.
316 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000317 public ComponentImpl() {
318 this(null, null, new Logger(null));
319 }
320
Pierre De Ropc8295c22015-06-04 10:15:35 +0000321 /**
322 * Constructor
323 * @param context the component bundle context
324 * @param manager the manager used to create the component
325 * @param logger the logger to use
326 */
Pierre De Rop3a00a212015-03-01 09:27:46 +0000327 public ComponentImpl(BundleContext context, DependencyManager manager, Logger logger) {
328 m_context = context;
329 m_bundle = context != null ? context.getBundle() : null;
330 m_manager = manager;
331 m_logger = logger;
332 m_autoConfig.put(BundleContext.class, Boolean.TRUE);
333 m_autoConfig.put(ServiceRegistration.class, Boolean.TRUE);
334 m_autoConfig.put(DependencyManager.class, Boolean.TRUE);
335 m_autoConfig.put(Component.class, Boolean.TRUE);
336 m_callbackInit = "init";
337 m_callbackStart = "start";
338 m_callbackStop = "stop";
339 m_callbackDestroy = "destroy";
340 m_id = m_idGenerator.getAndIncrement();
341 }
342
Pierre De Ropc8295c22015-06-04 10:15:35 +0000343 @Override
Pierre De Rop9e5cdba2016-02-17 20:35:16 +0000344 public <T> T createConfigurationProxy(Class<T> type, Dictionary<?, ?> config) {
345 return Configurable.create(type, config);
346 }
347
348 @Override
Pierre De Ropc723eb32015-11-22 21:49:00 +0000349 public Executor getExecutor() {
350 return m_executor;
351 }
352
353 @Override
Pierre De Ropc8295c22015-06-04 10:15:35 +0000354 public Component setDebug(String debugKey) {
355 // Force debug level in our logger
356 m_logger.setEnabledLevel(LogService.LOG_DEBUG);
357 m_logger.setDebugKey(debugKey);
358 return this;
359 }
360
Pierre De Rop3a00a212015-03-01 09:27:46 +0000361 @Override
362 public Component add(final Dependency ... dependencies) {
363 getExecutor().execute(new Runnable() {
364 @Override
365 public void run() {
366 List<DependencyContext> instanceBoundDeps = new ArrayList<>();
367 for (Dependency d : dependencies) {
368 DependencyContext dc = (DependencyContext) d;
369 if (dc.getComponentContext() != null) {
370 m_logger.err("%s can't be added to %s (dependency already added to another component).", dc,
371 ComponentImpl.this);
372 continue;
373 }
374 m_dependencyEvents.put(dc, new ConcurrentSkipListSet<Event>());
375 m_dependencies.add(dc);
376 dc.setComponentContext(ComponentImpl.this);
377 if (!(m_state == ComponentState.INACTIVE)) {
378 dc.setInstanceBound(true);
379 instanceBoundDeps.add(dc);
380 }
381 }
382 startDependencies(instanceBoundDeps);
383 handleChange();
384 }
385 });
386 return this;
387 }
388
389 @Override
390 public Component remove(final Dependency d) {
391 getExecutor().execute(new Runnable() {
392 @Override
393 public void run() {
394 DependencyContext dc = (DependencyContext) d;
395 // First remove this dependency from the dependency list
396 m_dependencies.remove(d);
397 // Now we can stop the dependency (our component won't be deactivated, it will only be unbound with
398 // the removed dependency).
399 if (!(m_state == ComponentState.INACTIVE)) {
400 dc.stop();
401 }
402 // Finally, cleanup the dependency events.
403 m_dependencyEvents.remove(d);
404 handleChange();
405 }
406 });
407 return this;
408 }
409
Pierre De Ropc8295c22015-06-04 10:15:35 +0000410 @Override
Pierre De Rop3a00a212015-03-01 09:27:46 +0000411 public void start() {
412 if (m_active.compareAndSet(false, true)) {
413 getExecutor().execute(new Runnable() {
414 @Override
415 public void run() {
416 m_isStarted = true;
417 handleChange();
418 }
419 });
420 }
421 }
422
Pierre De Ropc8295c22015-06-04 10:15:35 +0000423 @Override
Pierre De Rop3a00a212015-03-01 09:27:46 +0000424 public void stop() {
425 if (m_active.compareAndSet(true, false)) {
426 Executor executor = getExecutor();
427
428 // First, declare the task that will stop our component in our executor.
429 final Runnable stopTask = new Runnable() {
430 @Override
431 public void run() {
432 m_isStarted = false;
433 handleChange();
434 }
435 };
436
437 // Now, we have to schedule our stopTask in our component executor. But we have to handle a special case:
438 // if the component bundle is stopping *AND* if the executor is a parallel dispatcher, then we want
439 // to invoke our stopTask synchronously, in order to make sure that the bundle context is valid while our
440 // component is being deactivated (if we stop the component asynchronously, the bundle context may be invalidated
441 // before our component is stopped, and we don't want to be in this situation).
442
443 boolean stopping = m_bundle != null /* null only in tests env */ && m_bundle.getState() == Bundle.STOPPING;
444 if (stopping && executor instanceof DispatchExecutor) {
445 ((DispatchExecutor) executor).execute(stopTask, false /* try to execute synchronously, not using threadpool */);
446 } else {
447 executor.execute(stopTask);
448 }
449 }
450 }
451
452 @SuppressWarnings("unchecked")
453 @Override
454 public Component setInterface(String serviceName, Dictionary<?, ?> properties) {
455 ensureNotActive();
456 m_serviceName = serviceName;
457 m_serviceProperties = (Dictionary<Object, Object>) properties;
458 return this;
459 }
460
461 @SuppressWarnings("unchecked")
462 @Override
463 public Component setInterface(String[] serviceName, Dictionary<?, ?> properties) {
464 ensureNotActive();
465 m_serviceName = serviceName;
466 m_serviceProperties = (Dictionary<Object, Object>) properties;
467 return this;
468 }
469
470 @Override
471 public void handleEvent(final DependencyContext dc, final EventType type, final Event... event) {
472 // since this method can be invoked by anyone from any thread, we need to
473 // pass on the event to a runnable that we execute using the component's
474 // executor
475 getExecutor().execute(new Runnable() {
476 @Override
477 public void run() {
Pierre De Ropc8295c22015-06-04 10:15:35 +0000478 try {
479 switch (type) {
480 case ADDED:
481 handleAdded(dc, event[0]);
482 break;
483 case CHANGED:
484 handleChanged(dc, event[0]);
485 break;
486 case REMOVED:
487 handleRemoved(dc, event[0]);
488 break;
489 case SWAPPED:
490 handleSwapped(dc, event[0], event[1]);
491 break;
492 }
493 } finally {
494 // Clear cache of component callbacks invocation, except if we are currently called from handleChange().
495 // (See FELIX-4913).
496 clearInvokeCallbackCache();
Pierre De Rop3a00a212015-03-01 09:27:46 +0000497 }
498 }
499 });
500 }
501
502 @Override
503 public Event getDependencyEvent(DependencyContext dc) {
504 ConcurrentSkipListSet<Event> events = m_dependencyEvents.get(dc);
505 return events.size() > 0 ? events.last() : null;
506 }
507
508 @Override
509 public Set<Event> getDependencyEvents(DependencyContext dc) {
510 return m_dependencyEvents.get(dc);
511 }
512
Pierre De Ropc8295c22015-06-04 10:15:35 +0000513 @Override
Pierre De Rop3a00a212015-03-01 09:27:46 +0000514 public Component setAutoConfig(Class<?> clazz, boolean autoConfig) {
515 m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
516 return this;
517 }
518
Pierre De Ropc8295c22015-06-04 10:15:35 +0000519 @Override
Pierre De Rop3a00a212015-03-01 09:27:46 +0000520 public Component setAutoConfig(Class<?> clazz, String instanceName) {
521 m_autoConfig.put(clazz, Boolean.valueOf(instanceName != null));
522 m_autoConfigInstance.put(clazz, instanceName);
523 return this;
524 }
525
Pierre De Ropc8295c22015-06-04 10:15:35 +0000526 @Override
Pierre De Rop3a00a212015-03-01 09:27:46 +0000527 public boolean getAutoConfig(Class<?> clazz) {
528 Boolean result = (Boolean) m_autoConfig.get(clazz);
529 return (result != null && result.booleanValue());
530 }
531
Pierre De Ropc8295c22015-06-04 10:15:35 +0000532 @Override
Pierre De Rop3a00a212015-03-01 09:27:46 +0000533 public String getAutoConfigInstance(Class<?> clazz) {
534 return (String) m_autoConfigInstance.get(clazz);
535 }
536
Pierre De Ropc8295c22015-06-04 10:15:35 +0000537 @SuppressWarnings("unchecked")
538 public <T> T getInstance() {
539 Object[] instances = getCompositionInstances();
540 return instances.length == 0 ? null : (T) instances[0];
541 }
542
543 public Object[] getInstances() {
544 return getCompositionInstances();
545 }
546
547 public void invokeCallbackMethod(Object[] instances, String methodName, Class<?>[][] signatures, Object[][] parameters) {
548 invokeCallbackMethod(instances, methodName, signatures, parameters, true);
549 }
550
551 public void invokeCallbackMethod(Object[] instances, String methodName, Class<?>[][] signatures,
552 Object[][] parameters, boolean logIfNotFound) {
553 boolean callbackFound = false;
554 for (int i = 0; i < instances.length; i++) {
555 try {
556 InvocationUtil.invokeCallbackMethod(instances[i], methodName, signatures, parameters);
557 callbackFound |= true;
558 }
559 catch (NoSuchMethodException e) {
560 // if the method does not exist, ignore it
561 }
562 catch (InvocationTargetException e) {
563 // the method itself threw an exception, log that
564 m_logger.log(Logger.LOG_ERROR, "Invocation of '" + methodName + "' failed.", e.getCause());
565 }
566 catch (Throwable e) {
567 m_logger.log(Logger.LOG_ERROR, "Could not invoke '" + methodName + "'.", e);
568 }
569 }
570
571 // If the callback is not found, we don't log if the method is on an AbstractDecorator.
572 // (Aspect or Adapter are not interested in user dependency callbacks)
573 if (logIfNotFound && ! callbackFound && ! (getInstance() instanceof AbstractDecorator)) {
574 if (m_logger == null) {
575 System.out.println("Callback \"" + methodName + "\" not found on componnent instances "
576 + Arrays.toString(getInstances()));
577 } else {
578 m_logger.log(LogService.LOG_ERROR, "Callback \"" + methodName + "\" callback not found on componnent instances "
579 + Arrays.toString(getInstances()));
580 }
581
582 }
583 }
584
585 @Override
586 public boolean isAvailable() {
587 return m_state == TRACKING_OPTIONAL;
588 }
589
590 @Override
591 public boolean isActive() {
592 return m_active.get();
593 }
594
595 @Override
596 public Component add(final ComponentStateListener l) {
597 m_listeners.add(l);
598 return this;
599 }
600
601 @Override
602 public Component remove(ComponentStateListener l) {
603 m_listeners.remove(l);
604 return this;
605 }
606
607 @SuppressWarnings("unchecked")
608 @Override
609 public List<DependencyContext> getDependencies() {
610 return (List<DependencyContext>) m_dependencies.clone();
611 }
612
613 @Override
614 public Component setImplementation(Object implementation) {
615 m_componentDefinition = implementation;
616 return this;
617 }
618
619 @Override
620 public ServiceRegistration getServiceRegistration() {
621 return m_registration;
622 }
623
624 @SuppressWarnings("unchecked")
625 @Override
626 public <K,V> Dictionary<K, V> getServiceProperties() {
627 if (m_serviceProperties != null) {
628 // Applied patch from FELIX-4304
629 Hashtable<Object, Object> serviceProperties = new Hashtable<>();
630 addTo(serviceProperties, m_serviceProperties);
631 return (Dictionary<K, V>) serviceProperties;
632 }
633 return null;
634 }
635
636 @Override
637 @SuppressWarnings("unchecked")
638 public Component setServiceProperties(final Dictionary<?, ?> serviceProperties) {
639 getExecutor().execute(new Runnable() {
640 @Override
641 public void run() {
642 Dictionary<Object, Object> properties = null;
643 m_serviceProperties = (Dictionary<Object, Object>) serviceProperties;
644 if ((m_registration != null) && (m_serviceName != null)) {
645 properties = calculateServiceProperties();
646 m_registration.setProperties(properties);
647 }
648 }
649 });
650 return this;
651 }
652
653 public Component setCallbacks(String init, String start, String stop, String destroy) {
654 ensureNotActive();
655 m_callbackInit = init;
656 m_callbackStart = start;
657 m_callbackStop = stop;
658 m_callbackDestroy = destroy;
659 return this;
660 }
661
662 public Component setCallbacks(Object instance, String init, String start, String stop, String destroy) {
663 ensureNotActive();
664 m_callbackInstance = instance;
665 m_callbackInit = init;
666 m_callbackStart = start;
667 m_callbackStop = stop;
668 m_callbackDestroy = destroy;
669 return this;
670 }
671
672 @Override
673 public Component setFactory(Object factory, String createMethod) {
674 ensureNotActive();
675 m_instanceFactory = factory;
676 m_instanceFactoryCreateMethod = createMethod;
677 return this;
678 }
679
680 @Override
681 public Component setFactory(String createMethod) {
682 return setFactory(null, createMethod);
683 }
684
685 @Override
686 public Component setComposition(Object instance, String getMethod) {
687 ensureNotActive();
688 m_compositionManager = instance;
689 m_compositionManagerGetMethod = getMethod;
690 return this;
691 }
692
693 @Override
694 public Component setComposition(String getMethod) {
695 return setComposition(null, getMethod);
696 }
697
698 @Override
699 public DependencyManager getDependencyManager() {
700 return m_manager;
701 }
702
703 public ComponentDependencyDeclaration[] getComponentDependencies() {
704 List<DependencyContext> deps = getDependencies();
705 if (deps != null) {
706 ComponentDependencyDeclaration[] result = new ComponentDependencyDeclaration[deps.size()];
707 for (int i = 0; i < result.length; i++) {
708 DependencyContext dep = (DependencyContext) deps.get(i);
709 if (dep instanceof ComponentDependencyDeclaration) {
710 result[i] = (ComponentDependencyDeclaration) dep;
711 }
712 else {
713 result[i] = new SCDImpl(dep.toString(), (dep.isAvailable() ? 1 : 0) + (dep.isRequired() ? 2 : 0), dep.getClass().getName());
714 }
715 }
716 return result;
717 }
718 return null;
719 }
720
721 public String getName() {
722 StringBuffer sb = new StringBuffer();
723 Object serviceName = m_serviceName;
724 if (serviceName instanceof String[]) {
725 String[] names = (String[]) serviceName;
726 for (int i = 0; i < names.length; i++) {
727 if (i > 0) {
728 sb.append(", ");
729 }
730 sb.append(names[i]);
731 }
732 appendProperties(sb);
733 } else if (serviceName instanceof String) {
734 sb.append(serviceName.toString());
735 appendProperties(sb);
736 } else {
737 Object implementation = m_componentDefinition;
738 if (implementation != null) {
739 if (implementation instanceof Class) {
740 sb.append(((Class<?>) implementation).getName());
741 } else {
742 // If the implementation instance does not override "toString", just display
743 // the class name, else display the component using its toString method
744 try {
745 Method m = implementation.getClass().getMethod("toString", new Class[0]);
746 if (m.getDeclaringClass().equals(Object.class)) {
747 sb.append(implementation.getClass().getName());
748 } else {
749 sb.append(implementation.toString());
750 }
751 } catch (java.lang.NoSuchMethodException e) {
752 // Just display the class name
753 sb.append(implementation.getClass().getName());
754 }
755 }
756 } else {
757 sb.append(super.toString());
758 }
759 }
760 return sb.toString();
761 }
762
763 @Override
764 public BundleContext getBundleContext() {
765 return m_context;
766 }
767
768 @Override
769 public Bundle getBundle() {
770 return m_bundle;
771 }
772
773 public long getId() {
774 return m_id;
775 }
776
777 public String getClassName() {
778 Object serviceInstance = m_componentInstance;
779 if (serviceInstance != null) {
780 return serviceInstance.getClass().getName();
781 }
782
783 Object implementation = m_componentDefinition;
784 if (implementation != null) {
785 if (implementation instanceof Class) {
786 return ((Class<?>) implementation).getName();
787 }
788 return implementation.getClass().getName();
789 }
790
791 Object instanceFactory = m_instanceFactory;
792 if (instanceFactory != null) {
793 return instanceFactory.getClass().getName();
794 } else {
795 // unexpected.
796 return ComponentImpl.class.getName();
797 }
798 }
799
800 public String[] getServices() {
801 if (m_serviceName instanceof String[]) {
802 return (String[]) m_serviceName;
803 } else if (m_serviceName instanceof String) {
804 return new String[] { (String) m_serviceName };
805 } else {
806 return null;
807 }
808 }
809
810 public int getState() {
811 return (isAvailable() ? ComponentDeclaration.STATE_REGISTERED : ComponentDeclaration.STATE_UNREGISTERED);
812 }
813
814 public void ensureNotActive() {
815 if (m_active.get()) {
816 throw new IllegalStateException("Can't modify an already started component.");
817 }
818 }
819
820 public ComponentDeclaration getComponentDeclaration() {
821 return this;
822 }
823
824 @Override
825 public String toString() {
826 if (m_logger.getDebugKey() != null) {
827 return m_logger.getDebugKey();
828 }
829 return getClassName();
830 }
831
832 @Override
833 public void setThreadPool(Executor threadPool) {
834 ensureNotActive();
835 m_executor = new DispatchExecutor(threadPool, m_logger);
836 }
837
838 @Override
839 public Logger getLogger() {
840 return m_logger;
841 }
842
843 @Override
844 public Map<String, Long> getCallbacksTime() {
845 return m_stopwatch;
846 }
847
848 // ---------------------- Package/Private methods ---------------------------
849
850 void instantiateComponent() {
851 m_logger.debug("instantiating component.");
852
853 // TODO add more complex factory instantiations of one or more components in a composition here
854 if (m_componentInstance == null) {
855 if (m_componentDefinition instanceof Class) {
856 try {
857 m_componentInstance = createInstance((Class<?>) m_componentDefinition);
858 }
859 catch (Exception e) {
860 m_logger.log(Logger.LOG_ERROR, "Could not instantiate class " + m_componentDefinition, e);
861 }
862 }
863 else {
864 if (m_instanceFactoryCreateMethod != null) {
865 Object factory = null;
866 if (m_instanceFactory != null) {
867 if (m_instanceFactory instanceof Class) {
868 try {
869 factory = createInstance((Class<?>) m_instanceFactory);
870 }
871 catch (Exception e) {
872 m_logger.log(Logger.LOG_ERROR, "Could not create factory instance of class " + m_instanceFactory + ".", e);
873 }
874 }
875 else {
876 factory = m_instanceFactory;
877 }
878 }
879 else {
880 // TODO review if we want to try to default to something if not specified
881 // for now the JavaDoc of setFactory(method) reflects the fact that we need
882 // to review it
883 }
884 if (factory == null) {
885 m_logger.log(Logger.LOG_ERROR, "Factory cannot be null.");
886 }
887 else {
888 try {
889 m_componentInstance = InvocationUtil.invokeMethod(factory,
890 factory.getClass(), m_instanceFactoryCreateMethod,
891 new Class[][] {{}, {Component.class}}, new Object[][] {{}, {this}}, false);
892 }
893 catch (Exception e) {
894 m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
895 }
896 }
897 }
898 }
899
900 if (m_componentInstance == null) {
901 m_componentInstance = m_componentDefinition;
902 }
903
904 // configure the bundle context
905 autoConfigureImplementation(BundleContext.class, m_context);
906 autoConfigureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
907 autoConfigureImplementation(DependencyManager.class, m_manager);
908 autoConfigureImplementation(Component.class, this);
909 }
910 }
911
912 /**
913 * Runs the state machine, to see if a change event has to trigger some component state transition.
914 */
915 private void handleChange() {
916 m_logger.debug("handleChanged");
917 handlingChange(true);
918 try {
919 ComponentState oldState;
920 ComponentState newState;
921 do {
922 oldState = m_state;
923 newState = calculateNewState(oldState);
924 m_logger.debug("%s -> %s", oldState, newState);
925 m_state = newState;
926 } while (performTransition(oldState, newState));
927 } finally {
928 handlingChange(false);
929 clearInvokeCallbackCache();
930 m_logger.debug("end handling change.");
931 }
932 }
933
934 /**
935 * Based on the current state, calculate the new state.
936 */
937 private ComponentState calculateNewState(ComponentState currentState) {
938 if (currentState == INACTIVE) {
939 if (m_isStarted) {
940 return WAITING_FOR_REQUIRED;
941 }
942 }
943 if (currentState == WAITING_FOR_REQUIRED) {
944 if (!m_isStarted) {
945 return INACTIVE;
946 }
947 if (allRequiredAvailable()) {
948 return INSTANTIATED_AND_WAITING_FOR_REQUIRED;
949 }
950 }
951 if (currentState == INSTANTIATED_AND_WAITING_FOR_REQUIRED) {
952 if (m_isStarted && allRequiredAvailable()) {
953 if (allInstanceBoundAvailable()) {
954 return TRACKING_OPTIONAL;
955 }
956 return currentState;
957 }
958 return WAITING_FOR_REQUIRED;
959 }
960 if (currentState == TRACKING_OPTIONAL) {
961 if (m_isStarted && allRequiredAvailable() && allInstanceBoundAvailable()) {
962 return currentState;
963 }
964 return INSTANTIATED_AND_WAITING_FOR_REQUIRED;
965 }
966 return currentState;
967 }
968
969 /**
970 * Perform all the actions associated with state transitions.
971 * @returns true if a transition was performed.
972 **/
973 private boolean performTransition(ComponentState oldState, ComponentState newState) {
974 if (oldState == ComponentState.INACTIVE && newState == ComponentState.WAITING_FOR_REQUIRED) {
975 startDependencies(m_dependencies);
976 notifyListeners(newState);
977 return true;
978 }
979 if (oldState == ComponentState.WAITING_FOR_REQUIRED && newState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED) {
980 instantiateComponent();
981 invokeAutoConfigDependencies();
982 invokeAddRequiredDependencies();
983 ComponentState stateBeforeCallingInit = m_state;
984 invoke(m_callbackInit);
985 if (stateBeforeCallingInit == m_state) {
986 notifyListeners(newState); // init did not change current state, we can notify about this new state
987 }
988 return true;
989 }
990 if (oldState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED && newState == ComponentState.TRACKING_OPTIONAL) {
991 invokeAutoConfigInstanceBoundDependencies();
992 invokeAddRequiredInstanceBoundDependencies();
Pierre De Rop1eb4a452015-09-18 22:09:45 +0000993 invokeStart();
Pierre De Ropc8295c22015-06-04 10:15:35 +0000994 invokeAddOptionalDependencies();
995 registerService();
996 notifyListeners(newState);
997 return true;
998 }
999 if (oldState == ComponentState.TRACKING_OPTIONAL && newState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED) {
1000 unregisterService();
1001 invokeRemoveOptionalDependencies();
Pierre De Rop1eb4a452015-09-18 22:09:45 +00001002 invokeStop();
Pierre De Ropc8295c22015-06-04 10:15:35 +00001003 invokeRemoveInstanceBoundDependencies();
1004 notifyListeners(newState);
1005 return true;
1006 }
1007 if (oldState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED && newState == ComponentState.WAITING_FOR_REQUIRED) {
1008 invoke(m_callbackDestroy);
Pierre De Rop1088d6d2015-09-24 20:58:58 +00001009 removeInstanceBoundDependencies();
Pierre De Ropc8295c22015-06-04 10:15:35 +00001010 invokeRemoveRequiredDependencies();
1011 notifyListeners(newState);
1012 if (! someDependenciesNeedInstance()) {
1013 destroyComponent();
1014 }
1015 return true;
1016 }
1017 if (oldState == ComponentState.WAITING_FOR_REQUIRED && newState == ComponentState.INACTIVE) {
1018 stopDependencies();
1019 destroyComponent();
1020 notifyListeners(newState);
1021 return true;
1022 }
1023 return false;
1024 }
1025
Pierre De Rop1eb4a452015-09-18 22:09:45 +00001026 private void invokeStart() {
1027 invoke(m_callbackStart);
1028 m_startCalled = true;
1029 }
1030
1031 private void invokeStop() {
1032 invoke(m_callbackStop);
1033 m_startCalled = false;
1034 }
1035
1036 /**
Pierre De Ropc8295c22015-06-04 10:15:35 +00001037 * Sets the m_handlingChange flag that indicates if the state machine is currently running the handleChange method.
1038 */
1039 private void handlingChange(boolean transiting) {
1040 m_handlingChange = transiting;
1041 }
1042
1043 /**
1044 * Are we currently running the handleChange method ?
1045 */
1046 private boolean isHandlingChange() {
1047 return m_handlingChange;
1048 }
1049
1050 /**
1051 * Then handleEvent calls this method when a dependency service is being added.
1052 */
Pierre De Rop3a00a212015-03-01 09:27:46 +00001053 private void handleAdded(DependencyContext dc, Event e) {
1054 if (! m_isStarted) {
1055 return;
1056 }
1057 m_logger.debug("handleAdded %s", e);
1058
1059 Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
1060 dependencyEvents.add(e);
1061 dc.setAvailable(true);
Pierre De Ropc8295c22015-06-04 10:15:35 +00001062
Pierre De Ropc40d93f2015-05-04 20:25:57 +00001063 // In the following switch block, we sometimes only recalculate state changes
Pierre De Ropd2012be2015-04-28 12:17:36 +00001064 // if the dependency is fully started. If the dependency is not started,
1065 // it means it is actually starting (the service tracker is executing the open method).
Pierre De Ropc8295c22015-06-04 10:15:35 +00001066 // And in this case, depending on the state, we don't recalculate state changes now.
Pierre De Ropd2012be2015-04-28 12:17:36 +00001067 //
Pierre De Rop3a00a212015-03-01 09:27:46 +00001068 // All this is done for two reasons:
Pierre De Ropc40d93f2015-05-04 20:25:57 +00001069 // 1- optimization: it is preferable to recalculate state changes once we know about all currently
1070 // available dependency services (after the tracker has returned from its open method).
Pierre De Ropc8295c22015-06-04 10:15:35 +00001071 // 2- This also allows to determine the list of currently available dependency services before calling
1072 // the component start() callback.
Pierre De Rop3a00a212015-03-01 09:27:46 +00001073
Pierre De Ropd2012be2015-04-28 12:17:36 +00001074 switch (m_state) {
1075 case WAITING_FOR_REQUIRED:
1076 if (dc.isStarted() && dc.isRequired()) {
Pierre De Ropd2012be2015-04-28 12:17:36 +00001077 handleChange();
Pierre De Rop3a00a212015-03-01 09:27:46 +00001078 }
Pierre De Ropd2012be2015-04-28 12:17:36 +00001079 break;
1080 case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
1081 if (!dc.isInstanceBound()) {
1082 if (dc.isRequired()) {
Pierre De Ropc8295c22015-06-04 10:15:35 +00001083 invokeCallbackSafe(dc, EventType.ADDED, e);
Pierre De Ropd2012be2015-04-28 12:17:36 +00001084 }
1085 updateInstance(dc, e, false, true);
1086 } else {
1087 if (dc.isStarted() && dc.isRequired()) {
Pierre De Ropd2012be2015-04-28 12:17:36 +00001088 handleChange();
1089 }
1090 }
1091 break;
1092 case TRACKING_OPTIONAL:
Pierre De Ropc8295c22015-06-04 10:15:35 +00001093 invokeCallbackSafe(dc, EventType.ADDED, e);
Pierre De Ropd2012be2015-04-28 12:17:36 +00001094 updateInstance(dc, e, false, true);
1095 break;
1096 default:
Pierre De Rop3a00a212015-03-01 09:27:46 +00001097 }
Pierre De Ropc8295c22015-06-04 10:15:35 +00001098 }
1099
1100 /**
1101 * Then handleEvent calls this method when a dependency service is being changed.
1102 */
Pierre De Rop3a00a212015-03-01 09:27:46 +00001103 private void handleChanged(final DependencyContext dc, final Event e) {
1104 if (! m_isStarted) {
1105 return;
1106 }
1107 Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
1108 dependencyEvents.remove(e);
1109 dependencyEvents.add(e);
Pierre De Ropc8295c22015-06-04 10:15:35 +00001110
Pierre De Ropd2012be2015-04-28 12:17:36 +00001111 switch (m_state) {
1112 case TRACKING_OPTIONAL:
Pierre De Ropc8295c22015-06-04 10:15:35 +00001113 invokeCallbackSafe(dc, EventType.CHANGED, e);
Pierre De Ropd2012be2015-04-28 12:17:36 +00001114 updateInstance(dc, e, true, false);
1115 break;
1116
1117 case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
1118 if (!dc.isInstanceBound()) {
Pierre De Ropc8295c22015-06-04 10:15:35 +00001119 invokeCallbackSafe(dc, EventType.CHANGED, e);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001120 updateInstance(dc, e, true, false);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001121 }
Pierre De Ropd2012be2015-04-28 12:17:36 +00001122 break;
1123 default:
1124 // noop
Pierre De Rop3a00a212015-03-01 09:27:46 +00001125 }
1126 }
1127
Pierre De Ropc8295c22015-06-04 10:15:35 +00001128 /**
1129 * Then handleEvent calls this method when a dependency service is being removed.
1130 */
Pierre De Rop3a00a212015-03-01 09:27:46 +00001131 private void handleRemoved(DependencyContext dc, Event e) {
1132 if (! m_isStarted) {
1133 return;
1134 }
1135 // Check if the dependency is still available.
1136 Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
1137 int size = dependencyEvents.size();
1138 if (dependencyEvents.contains(e)) {
1139 size--; // the dependency is currently registered and is about to be removed.
1140 }
1141 dc.setAvailable(size > 0);
1142
1143 // If the dependency is now unavailable, we have to recalculate state change. This will result in invoking the
1144 // "removed" callback with the removed dependency (which we have not yet removed from our dependency events list.).
1145 // But we don't recalculate the state if the dependency is not started (if not started, it means that it is currently starting,
1146 // and the tracker is detecting a removed service).
1147 if (size == 0 && dc.isStarted()) {
1148 handleChange();
1149 }
1150
1151 // Now, really remove the dependency event.
1152 dependencyEvents.remove(e);
1153
Pierre De Ropd2012be2015-04-28 12:17:36 +00001154 // Depending on the state, we possible have to invoke the callbacks and update the component instance.
1155 switch (m_state) {
1156 case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
1157 if (!dc.isInstanceBound()) {
1158 if (dc.isRequired()) {
Pierre De Ropc8295c22015-06-04 10:15:35 +00001159 invokeCallbackSafe(dc, EventType.REMOVED, e);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001160 }
Pierre De Rop3a00a212015-03-01 09:27:46 +00001161 updateInstance(dc, e, false, false);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001162 }
Pierre De Ropd2012be2015-04-28 12:17:36 +00001163 break;
1164 case TRACKING_OPTIONAL:
Pierre De Ropc8295c22015-06-04 10:15:35 +00001165 invokeCallbackSafe(dc, EventType.REMOVED, e);
Pierre De Ropd2012be2015-04-28 12:17:36 +00001166 updateInstance(dc, e, false, false);
1167 break;
1168 default:
Pierre De Rop3a00a212015-03-01 09:27:46 +00001169 }
1170 }
1171
1172 private void handleSwapped(DependencyContext dc, Event oldEvent, Event newEvent) {
1173 if (! m_isStarted) {
1174 return;
1175 }
1176 Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
1177 dependencyEvents.remove(oldEvent);
1178 dependencyEvents.add(newEvent);
1179
Pierre De Ropd2012be2015-04-28 12:17:36 +00001180 // Depending on the state, we possible have to invoke the callbacks and update the component instance.
1181 switch (m_state) {
1182 case WAITING_FOR_REQUIRED:
1183 // No need to swap, we don't have yet injected anything
1184 break;
1185 case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
1186 // Only swap *non* instance-bound dependencies
1187 if (!dc.isInstanceBound()) {
1188 if (dc.isRequired()) {
1189 dc.invokeCallback(EventType.SWAPPED, oldEvent, newEvent);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001190 }
Pierre De Rop3a00a212015-03-01 09:27:46 +00001191 }
Pierre De Ropd2012be2015-04-28 12:17:36 +00001192 break;
1193 case TRACKING_OPTIONAL:
1194 dc.invokeCallback(EventType.SWAPPED, oldEvent, newEvent);
1195 break;
1196 default:
Pierre De Rop3a00a212015-03-01 09:27:46 +00001197 }
1198 }
Pierre De Ropc8295c22015-06-04 10:15:35 +00001199
Pierre De Rop3a00a212015-03-01 09:27:46 +00001200 private boolean allRequiredAvailable() {
1201 boolean available = true;
1202 for (DependencyContext d : m_dependencies) {
1203 if (d.isRequired() && !d.isInstanceBound()) {
1204 if (!d.isAvailable()) {
1205 available = false;
1206 break;
1207 }
1208 }
1209 }
1210 return available;
1211 }
1212
1213 private boolean allInstanceBoundAvailable() {
1214 boolean available = true;
1215 for (DependencyContext d : m_dependencies) {
1216 if (d.isRequired() && d.isInstanceBound()) {
1217 if (!d.isAvailable()) {
1218 available = false;
1219 break;
1220 }
1221 }
1222 }
1223 return available;
1224 }
1225
1226 private boolean someDependenciesNeedInstance() {
1227 for (DependencyContext d : m_dependencies) {
1228 if (d.needsInstance()) {
1229 return true;
1230 }
1231 }
1232 return false;
1233 }
1234
1235 /**
1236 * Updates the component instance(s).
1237 * @param dc the dependency context for the updating dependency service
1238 * @param event the event holding the updating service (service + properties)
1239 * @param update true if dependency service properties are updating, false if not. If false, it means
1240 * that a dependency service is being added or removed. (see the "add" flag).
1241 * @param add true if the dependency service has been added, false if it has been removed. This flag is
1242 * ignored if the "update" flag is true (because the dependency properties are just being updated).
1243 */
1244 private void updateInstance(DependencyContext dc, Event event, boolean update, boolean add) {
1245 if (dc.isAutoConfig()) {
1246 updateImplementation(dc.getAutoConfigType(), dc, dc.getAutoConfigName(), event, update, add);
1247 }
1248 if (dc.isPropagated() && m_registration != null) {
1249 m_registration.setProperties(calculateServiceProperties());
1250 }
1251 }
1252
1253 private void startDependencies(List<DependencyContext> dependencies) {
1254 // Start first optional dependencies first.
1255 m_logger.debug("startDependencies.");
1256 List<DependencyContext> requiredDeps = new ArrayList<>();
1257 for (DependencyContext d : dependencies) {
1258 if (d.isRequired()) {
1259 requiredDeps.add(d);
1260 continue;
1261 }
1262 if (d.needsInstance()) {
1263 instantiateComponent();
1264 }
1265 d.start();
1266 }
1267 // now, start required dependencies.
1268 for (DependencyContext d : requiredDeps) {
1269 if (d.needsInstance()) {
1270 instantiateComponent();
1271 }
1272 d.start();
1273 }
Pierre De Rop3a00a212015-03-01 09:27:46 +00001274 }
1275
1276 private void stopDependencies() {
1277 for (DependencyContext d : m_dependencies) {
1278 d.stop();
1279 }
1280 }
1281
1282 private void registerService() {
1283 if (m_context != null && m_serviceName != null) {
1284 ServiceRegistrationImpl wrapper = new ServiceRegistrationImpl();
1285 m_registration = wrapper;
1286 autoConfigureImplementation(ServiceRegistration.class, m_registration);
1287
1288 // service name can either be a string or an array of strings
1289 ServiceRegistration registration;
1290
1291 // determine service properties
1292 Dictionary<?,?> properties = calculateServiceProperties();
1293
1294 // register the service
1295 try {
1296 if (m_serviceName instanceof String) {
1297 registration = m_context.registerService((String) m_serviceName, m_componentInstance, properties);
1298 }
1299 else {
1300 registration = m_context.registerService((String[]) m_serviceName, m_componentInstance, properties);
1301 }
1302 wrapper.setServiceRegistration(registration);
1303 }
1304 catch (IllegalArgumentException iae) {
1305 m_logger.log(Logger.LOG_ERROR, "Could not register service " + m_componentInstance, iae);
1306 // set the registration to an illegal state object, which will make all invocations on this
1307 // wrapper fail with an ISE (which also occurs when the SR becomes invalid)
1308 wrapper.setIllegalState();
1309 }
1310 }
1311 }
1312
1313 private void unregisterService() {
1314 if (m_serviceName != null && m_registration != null) {
1315 try {
Pierre De Ropfd90eda2015-12-31 09:06:08 +00001316 if (m_bundle != null && (m_bundle.getState() == Bundle.ACTIVE || m_bundle.getState() == Bundle.STOPPING)) {
Pierre De Rop3a00a212015-03-01 09:27:46 +00001317 m_registration.unregister();
1318 }
1319 } catch (IllegalStateException e) { /* Should we really log this ? */}
1320 autoConfigureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
1321 m_registration = null;
1322 }
1323 }
1324
1325 private Dictionary<Object, Object> calculateServiceProperties() {
1326 Dictionary<Object, Object> properties = new Hashtable<>();
1327 for (int i = 0; i < m_dependencies.size(); i++) {
1328 DependencyContext d = (DependencyContext) m_dependencies.get(i);
1329 if (d.isPropagated() && d.isAvailable()) {
1330 Dictionary<Object, Object> dict = d.getProperties();
1331 addTo(properties, dict);
1332 }
1333 }
1334 // our service properties must not be overriden by propagated dependency properties, so we add our service
1335 // properties after having added propagated dependency properties.
1336 addTo(properties, m_serviceProperties);
1337 if (properties.size() == 0) {
1338 properties = null;
1339 }
1340 return properties;
1341 }
1342
1343 private void addTo(Dictionary<Object, Object> properties, Dictionary<Object, Object> additional) {
1344 if (properties == null) {
1345 throw new IllegalArgumentException("Dictionary to add to cannot be null.");
1346 }
1347 if (additional != null) {
1348 Enumeration<Object> e = additional.keys();
1349 while (e.hasMoreElements()) {
1350 Object key = e.nextElement();
1351 properties.put(key, additional.get(key));
1352 }
1353 }
1354 }
Pierre De Rop3a00a212015-03-01 09:27:46 +00001355
1356 private void destroyComponent() {
1357 m_componentInstance = null;
1358 }
1359
1360 private void invokeAddRequiredDependencies() {
1361 for (DependencyContext d : m_dependencies) {
1362 if (d.isRequired() && !d.isInstanceBound()) {
1363 for (Event e : m_dependencyEvents.get(d)) {
Pierre De Ropc8295c22015-06-04 10:15:35 +00001364 invokeCallbackSafe(d, EventType.ADDED, e);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001365 }
1366 }
1367 }
1368 }
1369
1370 private void invokeAutoConfigDependencies() {
1371 for (DependencyContext d : m_dependencies) {
1372 if (d.isAutoConfig() && !d.isInstanceBound()) {
1373 configureImplementation(d.getAutoConfigType(), d, d.getAutoConfigName());
1374 }
1375 }
1376 }
1377
1378 private void invokeAutoConfigInstanceBoundDependencies() {
1379 for (DependencyContext d : m_dependencies) {
1380 if (d.isAutoConfig() && d.isInstanceBound()) {
1381 configureImplementation(d.getAutoConfigType(), d, d.getAutoConfigName());
1382 }
1383 }
1384 }
1385
1386 private void invokeAddRequiredInstanceBoundDependencies() {
1387 for (DependencyContext d : m_dependencies) {
1388 if (d.isRequired() && d.isInstanceBound()) {
1389 for (Event e : m_dependencyEvents.get(d)) {
Pierre De Ropc8295c22015-06-04 10:15:35 +00001390 invokeCallbackSafe(d, EventType.ADDED, e);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001391 }
1392 }
1393 }
1394 }
1395
1396 private void invokeAddOptionalDependencies() {
1397 for (DependencyContext d : m_dependencies) {
1398 if (! d.isRequired()) {
1399 for (Event e : m_dependencyEvents.get(d)) {
Pierre De Ropc8295c22015-06-04 10:15:35 +00001400 invokeCallbackSafe(d, EventType.ADDED, e);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001401 }
1402 }
1403 }
1404 }
1405
1406 private void invokeRemoveRequiredDependencies() {
1407 for (DependencyContext d : m_dependencies) {
1408 if (!d.isInstanceBound() && d.isRequired()) {
1409 for (Event e : m_dependencyEvents.get(d)) {
Pierre De Ropc8295c22015-06-04 10:15:35 +00001410 invokeCallbackSafe(d, EventType.REMOVED, e);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001411 }
1412 }
1413 }
1414 }
1415
1416 private void invokeRemoveOptionalDependencies() {
1417 for (DependencyContext d : m_dependencies) {
1418 if (! d.isRequired()) {
1419 for (Event e : m_dependencyEvents.get(d)) {
Pierre De Ropc8295c22015-06-04 10:15:35 +00001420 invokeCallbackSafe(d, EventType.REMOVED, e);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001421 }
1422 }
1423 }
1424 }
1425
1426 private void invokeRemoveInstanceBoundDependencies() {
1427 for (DependencyContext d : m_dependencies) {
1428 if (d.isInstanceBound()) {
1429 for (Event e : m_dependencyEvents.get(d)) {
Pierre De Ropc8295c22015-06-04 10:15:35 +00001430 invokeCallbackSafe(d, EventType.REMOVED, e);
Pierre De Rop3a00a212015-03-01 09:27:46 +00001431 }
1432 }
1433 }
1434 }
Pierre De Ropc8295c22015-06-04 10:15:35 +00001435
1436 /**
1437 * This method ensures that a dependency callback is invoked only one time;
Pierre De Rop1eb4a452015-09-18 22:09:45 +00001438 * It also ensures that if the dependency callback is optional, then we only
1439 * invoke the bind method if the component start callback has already been called.
Pierre De Ropc8295c22015-06-04 10:15:35 +00001440 */
1441 private void invokeCallbackSafe(DependencyContext dc, EventType type, Event event) {
Pierre De Rop1eb4a452015-09-18 22:09:45 +00001442 if (! dc.isRequired() && ! m_startCalled) {
1443 return;
1444 }
1445 if (m_invokeCallbackCache.put(event, event) == null) {
Pierre De Ropbecfed42016-01-31 22:00:44 +00001446 // FELIX-5155: we must not invoke callbacks on our special internal components (adapters/aspects) if the dependency is not the first one, or
1447 // if the internal component is a Factory Pid Adapter.
1448 // For aspects/adapters, the first dependency only need to be injected, not the other extra dependencies added by user.
1449 // (in fact, we do this because extra dependencies (added by user) may contain a callback instance, and we really don't want to invoke the callbacks twice !
1450 Object mainComponentImpl = getInstance();
1451 if (mainComponentImpl instanceof AbstractDecorator) {
1452 if (mainComponentImpl instanceof FactoryConfigurationAdapterImpl || dc != m_dependencies.get(0)) {
1453 return;
1454 }
1455 }
Pierre De Rop1eb4a452015-09-18 22:09:45 +00001456 dc.invokeCallback(type, event);
1457 }
Pierre De Ropc8295c22015-06-04 10:15:35 +00001458 }
1459
1460 /**
Pierre De Rop1088d6d2015-09-24 20:58:58 +00001461 * Removes and closes all instance bound dependencies.
1462 * This method is called when a component is destroyed.
1463 */
1464 private void removeInstanceBoundDependencies() {
1465 for (DependencyContext dep : m_dependencies) {
1466 if (dep.isInstanceBound()) {
1467 m_dependencies.remove(dep);
1468 dep.stop();
1469 }
1470 }
1471 }
1472
1473 /**
Pierre De Ropc8295c22015-06-04 10:15:35 +00001474 * Clears the cache of invoked components callbacks.
1475 * We only clear the cache when the state machine is not running.
1476 * The cache is used to avoid calling the same bind callback twice.
1477 * See FELIX-4913.
1478 */
1479 private void clearInvokeCallbackCache() {
1480 if (! isHandlingChange()) {
1481 m_invokeCallbackCache.clear();
1482 }
1483 }
Pierre De Rop3a00a212015-03-01 09:27:46 +00001484
1485 private void invoke(String name) {
1486 if (name != null) {
1487 // if a callback instance was specified, look for the method there, if not,
1488 // ask the service for its composition instances
1489 Object[] instances = m_callbackInstance != null ? new Object[] { m_callbackInstance } : getCompositionInstances();
1490
1491 long t1 = System.nanoTime();
1492 try {
1493 invokeCallbackMethod(instances, name,
1494 new Class[][] {{ Component.class }, {}},
1495 new Object[][] {{ this }, {}},
1496 false);
1497 } finally {
1498 long t2 = System.nanoTime();
1499 m_stopwatch.put(name, t2 - t1);
1500 }
1501 }
1502 }
1503
Pierre De Ropc8295c22015-06-04 10:15:35 +00001504 private Object createInstance(Class<?> clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Pierre De Rop3a00a212015-03-01 09:27:46 +00001505 Constructor<?> constructor = clazz.getConstructor(VOID);
1506 constructor.setAccessible(true);
1507 return constructor.newInstance();
1508 }
1509
1510 private void notifyListeners(ComponentState state) {
1511 for (ComponentStateListener l : m_listeners) {
1512 l.changed(this, state);
1513 }
1514 }
1515
Pierre De Rop3a00a212015-03-01 09:27:46 +00001516 private void autoConfigureImplementation(Class<?> clazz, Object instance) {
1517 if (((Boolean) m_autoConfig.get(clazz)).booleanValue()) {
1518 configureImplementation(clazz, instance, (String) m_autoConfigInstance.get(clazz));
1519 }
1520 }
1521
1522 /**
1523 * Configure a field in the service implementation. The service implementation
1524 * is searched for fields that have the same type as the class that was specified
1525 * and for each of these fields, the specified instance is filled in.
1526 *
1527 * @param clazz the class to search for
1528 * @param instance the object to fill in the implementation class(es) field
1529 * @param instanceName the name of the instance to fill in, or <code>null</code> if not used
1530 */
1531 private void configureImplementation(Class<?> clazz, Object instance, String fieldName) {
1532 Object[] targets = getInstances();
1533 if (! FieldUtil.injectField(targets, fieldName, clazz, instance, m_logger) && fieldName != null) {
1534 // If the target is an abstract decorator (i.e: an adapter, or an aspect), we must not log warnings
1535 // if field has not been injected.
1536 if (! (getInstance() instanceof AbstractDecorator)) {
1537 m_logger.log(Logger.LOG_ERROR, "Could not inject " + instance + " to field \"" + fieldName
1538 + "\" at any of the following component instances: " + Arrays.toString(targets));
1539 }
1540 }
1541 }
1542
1543 private void configureImplementation(Class<?> clazz, DependencyContext dc, String fieldName) {
1544 Object[] targets = getInstances();
1545 if (! FieldUtil.injectDependencyField(targets, fieldName, clazz, dc, m_logger) && fieldName != null) {
1546 // If the target is an abstract decorator (i.e: an adapter, or an aspect), we must not log warnings
1547 // if field has not been injected.
1548 if (! (getInstance() instanceof AbstractDecorator)) {
1549 m_logger.log(Logger.LOG_ERROR, "Could not inject dependency " + clazz.getName() + " to field \""
1550 + fieldName + "\" at any of the following component instances: " + Arrays.toString(targets));
1551 }
1552 }
1553 }
1554
1555 /**
1556 * Update the component instances.
1557 *
1558 * @param clazz the class of the dependency service to inject in the component instances
1559 * @param dc the dependency context for the updating dependency service
1560 * @param fieldName the component instances fieldname to fill in with the updated dependency service
1561 * @param event the event holding the updating service (service + properties)
1562 * @param update true if dependency service properties are updating, false if not. If false, it means
1563 * that a dependency service is being added or removed. (see the "add" flag).
1564 * @param add true if the dependency service has been added, false if it has been removed. This flag is
1565 * ignored if the "update" flag is true (because the dependency properties are just being updated).
1566 */
1567 private void updateImplementation(Class<?> clazz, DependencyContext dc, String fieldName, Event event, boolean update,
1568 boolean add)
1569 {
1570 Object[] targets = getInstances();
1571 FieldUtil.updateDependencyField(targets, fieldName, update, add, clazz, event, dc, m_logger);
1572 }
1573
Pierre De Rop3a00a212015-03-01 09:27:46 +00001574 private Object[] getCompositionInstances() {
1575 Object[] instances = null;
1576 if (m_compositionManagerGetMethod != null) {
1577 if (m_compositionManager != null) {
1578 m_compositionManagerInstance = m_compositionManager;
1579 }
1580 else {
1581 m_compositionManagerInstance = m_componentInstance;
1582 }
1583 if (m_compositionManagerInstance != null) {
1584 try {
1585 instances = (Object[]) InvocationUtil.invokeMethod(m_compositionManagerInstance, m_compositionManagerInstance.getClass(), m_compositionManagerGetMethod, new Class[][] {{}}, new Object[][] {{}}, false);
1586 }
1587 catch (Exception e) {
1588 m_logger.log(Logger.LOG_ERROR, "Could not obtain instances from the composition manager.", e);
1589 instances = m_componentInstance == null ? new Object[] {} : new Object[] { m_componentInstance };
1590 }
1591 }
1592 }
1593 else {
1594 instances = m_componentInstance == null ? new Object[] {} : new Object[] { m_componentInstance };
1595 }
1596 return instances;
1597 }
1598
Pierre De Rop3a00a212015-03-01 09:27:46 +00001599 private void appendProperties(StringBuffer result) {
1600 Dictionary<Object, Object> properties = calculateServiceProperties();
1601 if (properties != null) {
1602 result.append("(");
1603 Enumeration<?> enumeration = properties.keys();
1604 while (enumeration.hasMoreElements()) {
1605 Object key = enumeration.nextElement();
1606 result.append(key.toString());
1607 result.append('=');
1608 Object value = properties.get(key);
1609 if (value instanceof String[]) {
1610 String[] values = (String[]) value;
1611 result.append('{');
1612 for (int i = 0; i < values.length; i++) {
1613 if (i > 0) {
1614 result.append(',');
1615 }
1616 result.append(values[i].toString());
1617 }
1618 result.append('}');
1619 }
1620 else {
1621 result.append(value.toString());
1622 }
1623 if (enumeration.hasMoreElements()) {
1624 result.append(',');
1625 }
1626 }
1627 result.append(")");
1628 }
1629 }
Pierre De Rop3a00a212015-03-01 09:27:46 +00001630}