blob: 50d2a91138c6ae03dcc84882f7c269040d325f70 [file] [log] [blame]
Marcel Offermansa962bc92009-11-21 17:59:33 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Pierre De Ropd2ec3952009-12-04 22:40:05 +000019package org.apache.felix.dm.impl;
Marcel Offermansa962bc92009-11-21 17:59:33 +000020
21import java.lang.reflect.Constructor;
22import java.lang.reflect.Field;
Marcel Offermansa962bc92009-11-21 17:59:33 +000023import java.lang.reflect.Proxy;
24import java.util.ArrayList;
25import java.util.Dictionary;
26import java.util.Enumeration;
27import java.util.HashMap;
28import java.util.Hashtable;
29import java.util.Iterator;
30import java.util.List;
31import java.util.Map;
32import java.util.Properties;
33
Pierre De Ropd2ec3952009-12-04 22:40:05 +000034import org.apache.felix.dm.DependencyManager;
35import org.apache.felix.dm.dependencies.Dependency;
Pierre De Ropd2ec3952009-12-04 22:40:05 +000036import org.apache.felix.dm.impl.dependencies.DependencyActivation;
37import org.apache.felix.dm.impl.dependencies.DependencyService;
Pierre De Ropd2ec3952009-12-04 22:40:05 +000038import org.apache.felix.dm.management.ServiceComponent;
39import org.apache.felix.dm.management.ServiceComponentDependency;
Pierre De Ropd2ec3952009-12-04 22:40:05 +000040import org.apache.felix.dm.service.Service;
41import org.apache.felix.dm.service.ServiceStateListener;
Marcel Offermansa962bc92009-11-21 17:59:33 +000042import org.osgi.framework.BundleContext;
43import org.osgi.framework.ServiceRegistration;
44
45/**
46 * Service implementation.
47 *
48 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
49 */
Marcel Offermanse14b3422009-11-25 23:04:32 +000050public class ServiceImpl implements Service, DependencyService, ServiceComponent {
Marcel Offermansa962bc92009-11-21 17:59:33 +000051 private static final Class[] VOID = new Class[] {};
52 private static final ServiceRegistration NULL_REGISTRATION;
53 private static final ServiceStateListener[] SERVICE_STATE_LISTENER_TYPE = new ServiceStateListener[] {};
54
Marcel Offermanse14b3422009-11-25 23:04:32 +000055 private final Object SYNC = new Object();
Marcel Offermansa962bc92009-11-21 17:59:33 +000056 private final BundleContext m_context;
57 private final DependencyManager m_manager;
58
59 // configuration (static)
60 private String m_callbackInit;
61 private String m_callbackStart;
62 private String m_callbackStop;
63 private String m_callbackDestroy;
64 private Object m_serviceName;
65 private Object m_implementation;
Marcel Offermans61a81142010-04-02 15:16:50 +000066 private Object m_callbackInstance;
Marcel Offermansa962bc92009-11-21 17:59:33 +000067
68 // configuration (dynamic, but does not affect state)
69 private Dictionary m_serviceProperties;
70
71 // configuration (dynamic, and affects state)
72 private ArrayList m_dependencies = new ArrayList();
73
74 // runtime state (calculated from dependencies)
75 private State m_state;
76
77 // runtime state (changes because of state changes)
78 private Object m_serviceInstance;
79 private ServiceRegistration m_registration;
Marcel Offermanse14b3422009-11-25 23:04:32 +000080 private boolean m_isBound;
81 private boolean m_isInstantiated;
Marcel Offermansa962bc92009-11-21 17:59:33 +000082
83 // service state listeners
84 private final List m_stateListeners = new ArrayList();
85
86 // work queue
87 private final SerialExecutor m_executor = new SerialExecutor();
88
89 // instance factory
90 private Object m_instanceFactory;
91 private String m_instanceFactoryCreateMethod;
92
93 // composition manager
94 private Object m_compositionManager;
95 private String m_compositionManagerGetMethod;
96 private Object m_compositionManagerInstance;
97
98 // internal logging
99 private final Logger m_logger;
100 private ServiceRegistration m_serviceRegistration;
101 private Map m_autoConfig = new HashMap();
102 private Map m_autoConfigInstance = new HashMap();
103
104 public ServiceImpl(BundleContext context, DependencyManager manager, Logger logger) {
105 m_logger = logger;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000106 m_state = new State((List) m_dependencies.clone(), false, false, false);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000107 m_context = context;
108 m_manager = manager;
109 m_callbackInit = "init";
110 m_callbackStart = "start";
111 m_callbackStop = "stop";
112 m_callbackDestroy = "destroy";
113 m_implementation = null;
114 m_autoConfig.put(BundleContext.class, Boolean.TRUE);
115 m_autoConfig.put(ServiceRegistration.class, Boolean.TRUE);
116 m_autoConfig.put(DependencyManager.class, Boolean.TRUE);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000117 m_autoConfig.put(Service.class, Boolean.TRUE);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000118 }
119
Marcel Offermanse14b3422009-11-25 23:04:32 +0000120 private void calculateStateChanges() {
121 // see if any of the things we did caused a further change of state
122 State oldState, newState;
123 synchronized (m_dependencies) {
124 oldState = m_state;
125 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
126 m_state = newState;
127 }
128 calculateStateChanges(oldState, newState);
129 }
130
Marcel Offermansa962bc92009-11-21 17:59:33 +0000131 private void calculateStateChanges(final State oldState, final State newState) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000132 if (oldState.isInactive() && (newState.isTrackingOptional())) {
133 m_executor.enqueue(new Runnable() {
134 public void run() {
135 activateService(newState);
136 }});
137 }
138 if (oldState.isInactive() && (newState.isWaitingForRequired())) {
139 m_executor.enqueue(new Runnable() {
140 public void run() {
141 startTrackingRequired(newState);
142 }});
143 }
144 if (oldState.isWaitingForRequired() && newState.isTrackingOptional()) {
145 m_executor.enqueue(new Runnable() {
146 public void run() {
147 activateService(newState);
148 }});
149 }
150 if ((oldState.isWaitingForRequired()) && newState.isInactive()) {
151 m_executor.enqueue(new Runnable() {
152 public void run() {
153 stopTrackingRequired(oldState);
154 }});
155 }
156 if (oldState.isTrackingOptional() && newState.isWaitingForRequiredInstantiated()) {
157 m_executor.enqueue(new Runnable() {
158 public void run() {
159 // TODO as far as I can see there is nothing left to do here
160 }});
161 }
162 if (oldState.isTrackingOptional() && newState.isWaitingForRequired()) {
163 m_executor.enqueue(new Runnable() {
164 public void run() {
165 deactivateService(oldState);
166 }});
167 }
168 if (oldState.isTrackingOptional() && newState.isBound()) {
169 m_executor.enqueue(new Runnable() {
170 public void run() {
Marcel Offermansbedf3692010-06-06 20:07:12 +0000171 bindService(newState);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000172 }});
173 }
174 if (oldState.isTrackingOptional() && newState.isInactive()) {
175 m_executor.enqueue(new Runnable() {
176 public void run() {
177 deactivateService(oldState);
178 stopTrackingRequired(oldState);
179 }});
180 }
181 if (oldState.isWaitingForRequiredInstantiated() && newState.isWaitingForRequired()) {
182 m_executor.enqueue(new Runnable() {
183 public void run() {
184 deactivateService(oldState);
185 }});
186 }
187 if (oldState.isWaitingForRequiredInstantiated() && newState.isInactive()) {
188 m_executor.enqueue(new Runnable() {
189 public void run() {
190 deactivateService(oldState);
191 stopTrackingRequired(oldState);
192 }});
193 }
194 if (oldState.isWaitingForRequiredInstantiated() && newState.isBound()) {
195 m_executor.enqueue(new Runnable() {
196 public void run() {
Marcel Offermansbedf3692010-06-06 20:07:12 +0000197 bindService(newState);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000198 }});
199 }
200 if (oldState.isBound() && newState.isWaitingForRequiredInstantiated()) {
201 m_executor.enqueue(new Runnable() {
202 public void run() {
203 unbindService(oldState);
204 }});
205 }
206 if (oldState.isBound() && newState.isWaitingForRequired()) {
207 m_executor.enqueue(new Runnable() {
208 public void run() {
209 unbindService(oldState);
210 deactivateService(oldState);
211 }});
212 }
213 if (oldState.isBound() && newState.isInactive()) {
214 m_executor.enqueue(new Runnable() {
215 public void run() {
216 unbindService(oldState);
217 deactivateService(oldState);
218 stopTrackingRequired(oldState);
219 }});
220 }
221 m_executor.execute();
Marcel Offermansa962bc92009-11-21 17:59:33 +0000222 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000223
Marcel Offermansa962bc92009-11-21 17:59:33 +0000224 public Service add(final Dependency dependency) {
225 State oldState, newState;
226 synchronized (m_dependencies) {
227 oldState = m_state;
228 m_dependencies.add(dependency);
229 }
Pierre De Rop79ac9712010-06-11 06:02:07 +0000230
231 if (dependency.isInstanceBound()) {
232 // At this point: this dependency is added from init(): but we don't want to start it now,
233 // because if we start it, and if the required dependency is available, then the service.start()
234 // method will be called, and this is a problem if a further
235 // required (but unavailable) dependency is then added again from the init() method ...
236 // Once the init() method will return, the activateService method will then calculate the state changes,
237 // but at this point, all added extra-dependencies will be known.
238 return this;
239 }
240
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000241 if (oldState.isAllRequiredAvailable() || (oldState.isWaitingForRequiredInstantiated() && dependency.isRequired()) || (oldState.isWaitingForRequired() && dependency.isRequired())) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000242 ((DependencyActivation) dependency).start(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000243 }
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000244
Marcel Offermansa962bc92009-11-21 17:59:33 +0000245 synchronized (m_dependencies) {
Marcel Offermans306c2522009-12-17 13:57:58 +0000246 // starting the dependency above might have triggered another state change, so
247 // we have to fetch the current state again
248 oldState = m_state;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000249 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000250 m_state = newState;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000251 }
252 calculateStateChanges(oldState, newState);
253 return this;
254 }
255
256 public Service add(List dependencies) {
257 // TODO review if this can be done more smartly
258 for (int i = 0; i < dependencies.size(); i++) {
259 add((Dependency) dependencies.get(i));
Marcel Offermansa962bc92009-11-21 17:59:33 +0000260 }
261 return this;
262 }
263
264 public Service remove(Dependency dependency) {
265 State oldState, newState;
266 synchronized (m_dependencies) {
267 oldState = m_state;
268 m_dependencies.remove(dependency);
269 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000270 if (oldState.isAllRequiredAvailable() || (oldState.isWaitingForRequired() && dependency.isRequired())) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000271 ((DependencyActivation) dependency).stop(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000272 }
273 synchronized (m_dependencies) {
Marcel Offermans306c2522009-12-17 13:57:58 +0000274 // starting the dependency above might have triggered another state change, so
275 // we have to fetch the current state again
276 oldState = m_state;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000277 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000278 m_state = newState;
279 }
280 calculateStateChanges(oldState, newState);
281 return this;
282 }
283
284 public List getDependencies() {
285 synchronized (m_dependencies) {
286 return (List) m_dependencies.clone();
287 }
288 }
289
290 public ServiceRegistration getServiceRegistration() {
291 return m_registration;
292 }
293
294 public Object getService() {
295 return m_serviceInstance;
296 }
297
298 public void dependencyAvailable(final Dependency dependency) {
299 State oldState, newState;
300 synchronized (m_dependencies) {
301 oldState = m_state;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000302 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000303 m_state = newState;
304 }
Marcel Offermans6cb7ac22010-01-04 09:32:37 +0000305 if (newState.isAllRequiredAvailable() || newState.isWaitingForRequiredInstantiated()) {
Marcel Offermans84a43ad2009-12-29 14:54:48 +0000306 updateInstance(dependency);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000307 }
Marcel Offermans306c2522009-12-17 13:57:58 +0000308 calculateStateChanges(oldState, newState);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000309 }
310
311 public void dependencyChanged(final Dependency dependency) {
312 State state;
313 synchronized (m_dependencies) {
314 state = m_state;
315 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000316 if (state.isAllRequiredAvailable()) {
Marcel Offermans84a43ad2009-12-29 14:54:48 +0000317 updateInstance(dependency);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000318 }
319 }
320
321 public void dependencyUnavailable(final Dependency dependency) {
322 State oldState, newState;
323 synchronized (m_dependencies) {
324 oldState = m_state;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000325 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000326 m_state = newState;
327 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000328 if (newState.isAllRequiredAvailable()) {
Marcel Offermans84a43ad2009-12-29 14:54:48 +0000329 updateInstance(dependency);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000330 }
Marcel Offermans306c2522009-12-17 13:57:58 +0000331 calculateStateChanges(oldState, newState);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000332 }
333
334 public synchronized void start() {
Marcel Offermans6358e052010-01-04 14:36:08 +0000335 if (m_serviceRegistration == null) {
336 m_serviceRegistration = m_context.registerService(ServiceComponent.class.getName(), this, null);
337 State oldState, newState;
338 synchronized (m_dependencies) {
339 oldState = m_state;
340 newState = new State((List) m_dependencies.clone(), true, m_isInstantiated, m_isBound);
341 m_state = newState;
342 }
343 calculateStateChanges(oldState, newState);
344 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000345 }
346
347 public synchronized void stop() {
Marcel Offermans6358e052010-01-04 14:36:08 +0000348 if (m_serviceRegistration != null) {
349 State oldState, newState;
350 synchronized (m_dependencies) {
351 oldState = m_state;
352 newState = new State((List) m_dependencies.clone(), false, m_isInstantiated, m_isBound);
353 m_state = newState;
354 }
355 calculateStateChanges(oldState, newState);
356 m_serviceRegistration.unregister();
357 m_serviceRegistration = null;
358 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000359 }
360
361 public synchronized Service setInterface(String serviceName, Dictionary properties) {
362 ensureNotActive();
363 m_serviceName = serviceName;
364 m_serviceProperties = properties;
365 return this;
366 }
367
368 public synchronized Service setInterface(String[] serviceName, Dictionary properties) {
369 ensureNotActive();
370 m_serviceName = serviceName;
371 m_serviceProperties = properties;
372 return this;
373 }
374
375 public synchronized Service setCallbacks(String init, String start, String stop, String destroy) {
376 ensureNotActive();
377 m_callbackInit = init;
378 m_callbackStart = start;
379 m_callbackStop = stop;
380 m_callbackDestroy = destroy;
381 return this;
382 }
Marcel Offermans61a81142010-04-02 15:16:50 +0000383
384 public synchronized Service setCallbacks(Object instance, String init, String start, String stop, String destroy) {
385 ensureNotActive();
386 m_callbackInstance = instance;
387 m_callbackInit = init;
388 m_callbackStart = start;
389 m_callbackStop = stop;
390 m_callbackDestroy = destroy;
391 return this;
392 }
393
394
Marcel Offermansa962bc92009-11-21 17:59:33 +0000395
396 public synchronized Service setImplementation(Object implementation) {
397 ensureNotActive();
398 m_implementation = implementation;
399 return this;
400 }
401
402 public synchronized Service setFactory(Object factory, String createMethod) {
403 ensureNotActive();
404 m_instanceFactory = factory;
405 m_instanceFactoryCreateMethod = createMethod;
406 return this;
407 }
408
409 public synchronized Service setFactory(String createMethod) {
410 return setFactory(null, createMethod);
411 }
412
413 public synchronized Service setComposition(Object instance, String getMethod) {
414 ensureNotActive();
415 m_compositionManager = instance;
416 m_compositionManagerGetMethod = getMethod;
417 return this;
418 }
419
420 public synchronized Service setComposition(String getMethod) {
421 return setComposition(null, getMethod);
422 }
423
424 public String toString() {
425 return "ServiceImpl[" + m_serviceName + " " + m_implementation + "]";
426 }
427
428 public synchronized Dictionary getServiceProperties() {
429 if (m_serviceProperties != null) {
430 return (Dictionary) ((Hashtable) m_serviceProperties).clone();
431 }
432 return null;
433 }
434
Pierre De Rop19476fe2010-05-23 08:13:58 +0000435 public synchronized Service setServiceProperties(Dictionary serviceProperties) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000436 m_serviceProperties = serviceProperties;
Marcel Offermans937ab4f2009-12-10 10:53:01 +0000437 if ((m_registration != null) && (m_serviceName != null)) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000438 m_registration.setProperties(calculateServiceProperties());
439 }
Pierre De Rop19476fe2010-05-23 08:13:58 +0000440 return this;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000441 }
442
443 // service state listener methods
444 public void addStateListener(ServiceStateListener listener) {
445 synchronized (m_stateListeners) {
446 m_stateListeners.add(listener);
447 }
448 // when we register as a listener and the service is already started
449 // make sure we invoke the right callbacks so the listener knows
450 State state;
451 synchronized (m_dependencies) {
452 state = m_state;
453 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000454 if (state.isAllRequiredAvailable()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000455 listener.starting(this);
456 listener.started(this);
457 }
458 }
459
460 public void removeStateListener(ServiceStateListener listener) {
461 synchronized (m_stateListeners) {
462 m_stateListeners.remove(listener);
463 }
464 }
465
Marcel Offermanse14b3422009-11-25 23:04:32 +0000466 public void removeStateListeners() {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000467 synchronized (m_stateListeners) {
468 m_stateListeners.clear();
469 }
470 }
471
472 private void stateListenersStarting() {
473 ServiceStateListener[] list = getListeners();
474 for (int i = 0; i < list.length; i++) {
475 try {
476 list[i].starting(this);
477 }
478 catch (Throwable t) {
479 m_logger.log(Logger.LOG_ERROR, "Error invoking listener starting method.", t);
480 }
481 }
482 }
483
484 private void stateListenersStarted() {
485 ServiceStateListener[] list = getListeners();
486 for (int i = 0; i < list.length; i++) {
487 try {
488 list[i].started(this);
489 }
490 catch (Throwable t) {
491 m_logger.log(Logger.LOG_ERROR, "Error invoking listener started method.", t);
492 }
493 }
494 }
495
496 private void stateListenersStopping() {
497 ServiceStateListener[] list = getListeners();
498 for (int i = 0; i < list.length; i++) {
499 try {
500 list[i].stopping(this);
501 }
502 catch (Throwable t) {
503 m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopping method.", t);
504 }
505 }
506 }
507
508 private void stateListenersStopped() {
509 ServiceStateListener[] list = getListeners();
510 for (int i = 0; i < list.length; i++) {
511 try {
512 list[i].stopped(this);
513 }
514 catch (Throwable t) {
515 m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopped method.", t);
516 }
517 }
518 }
519
520 private ServiceStateListener[] getListeners() {
521 synchronized (m_stateListeners) {
522 return (ServiceStateListener[]) m_stateListeners.toArray(SERVICE_STATE_LISTENER_TYPE);
523 }
524 }
525
Marcel Offermanse14b3422009-11-25 23:04:32 +0000526 private void activateService(State state) {
527 String init;
528 synchronized (this) {
529 init = m_callbackInit;
530 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000531 // service activation logic, first we initialize the service instance itself
532 // meaning it is created if necessary and the bundle context is set
533 initService();
Marcel Offermansa962bc92009-11-21 17:59:33 +0000534 // now is the time to configure the service, meaning all required
535 // dependencies will be set and any callbacks called
536 configureService(state);
Marcel Offermans78e5dfc2009-12-10 13:52:49 +0000537 // flag that our instance has been created
538 m_isInstantiated = true;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000539 // then we invoke the init callback so the service can further initialize
540 // itself
541 invoke(init);
Pierre De Rop79ac9712010-06-11 06:02:07 +0000542 // start extra/required dependencies which might have been added from the init() method.
543 startExtraRequiredDependencies();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000544 // see if any of this caused further state changes
545 calculateStateChanges();
546 }
547
Pierre De Rop79ac9712010-06-11 06:02:07 +0000548 private void startExtraRequiredDependencies() {
549 Iterator i = m_dependencies.iterator();
550 while (i.hasNext()) {
551 Dependency dependency = (Dependency) i.next();
552 if (dependency.isInstanceBound() && dependency.isRequired()) {
553 // Optional extra dependencies will be started later, once our service is started.
554 ((DependencyActivation) dependency).start(this);
555 }
556 }
557 }
558
Marcel Offermanse14b3422009-11-25 23:04:32 +0000559 private void bindService(State state) {
560 String start;
561 synchronized (this) {
562 start = m_callbackStart;
563 }
Pierre De Rop79ac9712010-06-11 06:02:07 +0000564
565 // configure service with extra-dependencies which might have been added from init() method.
566 configureServiceWithExtraDependencies(state);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000567 // inform the state listeners we're starting
568 stateListenersStarting();
569 // invoke the start callback, since we're now ready to be used
570 invoke(start);
571 // start tracking optional services
572 startTrackingOptional(state);
573 // register the service in the framework's service registry
574 registerService();
575 // inform the state listeners we've started
576 stateListenersStarted();
577 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000578
Pierre De Rop79ac9712010-06-11 06:02:07 +0000579 private void configureServiceWithExtraDependencies(State state)
580 {
581 Iterator i = state.getDependencies().iterator();
582 while (i.hasNext()) {
583 Dependency dependency = (Dependency) i.next();
584 if (dependency.isAutoConfig() && dependency.isInstanceBound()) {
585 configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
586 }
587 if (dependency.isRequired() && dependency.isInstanceBound()) {
588 dependency.invokeAdded(this);
589 }
590 }
591 }
592
Marcel Offermanse14b3422009-11-25 23:04:32 +0000593 private void unbindService(State state) {
594 String stop;
595 synchronized (this) {
596 stop = m_callbackStop;
597 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000598 // service deactivation logic, first inform the state listeners
599 // we're stopping
600 stateListenersStopping();
601 // then, unregister the service from the framework
602 unregisterService();
603 // stop tracking optional services
604 stopTrackingOptional(state);
605 // invoke the stop callback
606 invoke(stop);
607 // inform the state listeners we've stopped
608 stateListenersStopped();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000609 }
610
611 private void deactivateService(State state) {
612 String destroy;
613 synchronized (this) {
614 destroy = m_callbackDestroy;
615 }
Marcel Offermans78e5dfc2009-12-10 13:52:49 +0000616 // flag that our instance was destroyed
617 m_isInstantiated = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000618 // invoke the destroy callback
619 invoke(destroy);
620 // destroy the service instance
621 destroyService(state);
622 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000623
Marcel Offermansa962bc92009-11-21 17:59:33 +0000624 private void invoke(String name) {
625 if (name != null) {
626 // invoke method if it exists
627 try {
Marcel Offermans61a81142010-04-02 15:16:50 +0000628 // if a callback instance was specified, look for the method there, if not, look for the method in the
629 // instance itself
630 Object instance = m_callbackInstance != null ? m_callbackInstance : m_serviceInstance;
631 InvocationUtil.invokeCallbackMethod(instance, name,
632 new Class[][] {{ Object.class, DependencyManager.class, Service.class }, { DependencyManager.class, Service.class }, { Object.class }, {}},
633 new Object[][] {{ m_serviceInstance, m_manager, this }, { m_manager, this }, { m_serviceInstance }, {}});
Marcel Offermansa962bc92009-11-21 17:59:33 +0000634 }
Marcel Offermanse43114b2010-04-04 18:37:44 +0000635 catch (NoSuchMethodException e) {
636 // we ignore the fact that the method was not found
637 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000638 catch (Exception e) {
Marcel Offermanse43114b2010-04-04 18:37:44 +0000639 // but any other exception means that the method was invoked but somehow failed
640 m_logger.log(Logger.LOG_WARNING, "Error trying to invoke method named " + name + ".", e);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000641 }
642 }
643 }
644
645 private void startTrackingOptional(State state) {
646 Iterator i = state.getDependencies().iterator();
647 while (i.hasNext()) {
648 Dependency dependency = (Dependency) i.next();
649 if (!dependency.isRequired()) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000650 ((DependencyActivation) dependency).start(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000651 }
652 }
653 }
654
655 private void stopTrackingOptional(State state) {
656 Iterator i = state.getDependencies().iterator();
657 while (i.hasNext()) {
658 Dependency dependency = (Dependency) i.next();
659 if (!dependency.isRequired()) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000660 ((DependencyActivation) dependency).stop(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000661 }
662 }
663 }
664
665 private void startTrackingRequired(State state) {
666 Iterator i = state.getDependencies().iterator();
667 while (i.hasNext()) {
668 Dependency dependency = (Dependency) i.next();
669 if (dependency.isRequired()) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000670 ((DependencyActivation) dependency).start(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000671 }
672 }
673 }
674
675 private void stopTrackingRequired(State state) {
676 Iterator i = state.getDependencies().iterator();
677 while (i.hasNext()) {
678 Dependency dependency = (Dependency) i.next();
679 if (dependency.isRequired()) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000680 ((DependencyActivation) dependency).stop(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000681 }
682 }
683 }
684
685 private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
686 Constructor constructor = clazz.getConstructor(VOID);
687 constructor.setAccessible(true);
688 return clazz.newInstance();
689 }
690
Marcel Offermanse14b3422009-11-25 23:04:32 +0000691 public void initService() {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000692 if (m_serviceInstance == null) {
693 if (m_implementation instanceof Class) {
694 // instantiate
695 try {
696 m_serviceInstance = createInstance((Class) m_implementation);
697 }
698 catch (Exception e) {
699 m_logger.log(Logger.LOG_ERROR, "Could not create service instance of class " + m_implementation + ".", e);
700 }
701 }
702 else {
703 if (m_instanceFactoryCreateMethod != null) {
704 Object factory = null;
705 if (m_instanceFactory != null) {
706 if (m_instanceFactory instanceof Class) {
707 try {
708 factory = createInstance((Class) m_instanceFactory);
709 }
710 catch (Exception e) {
711 m_logger.log(Logger.LOG_ERROR, "Could not create factory instance of class " + m_instanceFactory + ".", e);
712 }
713 }
714 else {
715 factory = m_instanceFactory;
716 }
717 }
718 else {
719 // TODO review if we want to try to default to something if not specified
720 // for now the JavaDoc of setFactory(method) reflects the fact that we need
721 // to review it
722 }
723 if (factory == null) {
724 m_logger.log(Logger.LOG_ERROR, "Factory cannot be null.");
725 }
726 else {
727 try {
Marcel Offermansa6ffb992010-05-19 11:56:44 +0000728// Method m = factory.getClass().getDeclaredMethod(m_instanceFactoryCreateMethod, null);
729// m_serviceInstance = m.invoke(factory, null);
730//
731 m_serviceInstance = InvocationUtil.invokeMethod(factory, factory.getClass(), m_instanceFactoryCreateMethod, new Class[][] {{}}, new Object[][] {{}}, false);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000732 }
733 catch (Exception e) {
734 m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
735 }
736 }
737 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000738 if (m_serviceInstance == null) {
Marcel Offermanscc8adbb2010-02-17 10:20:11 +0000739 if (m_implementation == null) {
740 m_logger.log(Logger.LOG_ERROR, "Implementation cannot be null.");
741 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000742 m_serviceInstance = m_implementation;
743 }
744 }
745 // configure the bundle context
746 if (((Boolean) m_autoConfig.get(BundleContext.class)).booleanValue()) {
747 configureImplementation(BundleContext.class, m_context, (String) m_autoConfigInstance.get(BundleContext.class));
748 }
749 if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
750 configureImplementation(ServiceRegistration.class, NULL_REGISTRATION, (String) m_autoConfigInstance.get(ServiceRegistration.class));
751 }
752 if (((Boolean) m_autoConfig.get(DependencyManager.class)).booleanValue()) {
753 configureImplementation(DependencyManager.class, m_manager, (String) m_autoConfigInstance.get(DependencyManager.class));
754 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000755 if (((Boolean) m_autoConfig.get(Service.class)).booleanValue()) {
756 configureImplementation(Service.class, this, (String) m_autoConfigInstance.get(Service.class));
757 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000758 }
759 }
760
761 public void setAutoConfig(Class clazz, boolean autoConfig) {
762 m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
763 }
764
765 public void setAutoConfig(Class clazz, String instanceName) {
766 m_autoConfig.put(clazz, Boolean.valueOf(instanceName != null));
767 m_autoConfigInstance.put(clazz, instanceName);
768 }
769
770 private void configureService(State state) {
771 // configure all services (the optional dependencies might be configured
772 // as null objects but that's what we want at this point)
773 configureServices(state);
774 }
775
776 private void destroyService(State state) {
777 unconfigureServices(state);
778 m_serviceInstance = null;
779 }
780
781 private void registerService() {
782 if (m_serviceName != null) {
783 ServiceRegistrationImpl wrapper = new ServiceRegistrationImpl();
784 m_registration = wrapper;
785 if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
786 configureImplementation(ServiceRegistration.class, m_registration, (String) m_autoConfigInstance.get(ServiceRegistration.class));
787 }
788
789 // service name can either be a string or an array of strings
790 ServiceRegistration registration;
791
792 // determine service properties
793 Dictionary properties = calculateServiceProperties();
794
795 // register the service
796 try {
797 if (m_serviceName instanceof String) {
798 registration = m_context.registerService((String) m_serviceName, m_serviceInstance, properties);
799 }
800 else {
801 registration = m_context.registerService((String[]) m_serviceName, m_serviceInstance, properties);
802 }
803 wrapper.setServiceRegistration(registration);
804 }
805 catch (IllegalArgumentException iae) {
806 m_logger.log(Logger.LOG_ERROR, "Could not register service " + m_serviceInstance, iae);
807 // set the registration to an illegal state object, which will make all invocations on this
808 // wrapper fail with an ISE (which also occurs when the SR becomes invalid)
809 wrapper.setIllegalState();
810 }
811 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000812 m_isBound = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000813 }
814
815 private Dictionary calculateServiceProperties() {
816 Dictionary properties = new Properties();
817 addTo(properties, m_serviceProperties);
818 for (int i = 0; i < m_dependencies.size(); i++) {
819 Dependency d = (Dependency) m_dependencies.get(i);
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000820 if (d.isPropagated()) {
821 Dictionary dict = d.getProperties();
822 addTo(properties, dict);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000823 }
824 }
825 if (properties.size() == 0) {
826 properties = null;
827 }
828 return properties;
829 }
830
831 private void addTo(Dictionary properties, Dictionary additional) {
832 if (properties == null) {
833 throw new IllegalArgumentException("Dictionary to add to cannot be null.");
834 }
835 if (additional != null) {
836 Enumeration e = additional.keys();
837 while (e.hasMoreElements()) {
838 Object key = e.nextElement();
839 properties.put(key, additional.get(key));
840 }
841 }
842 }
843
844 private void unregisterService() {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000845 m_isBound = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000846 if (m_serviceName != null) {
847 m_registration.unregister();
848 configureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
849 }
850 }
851
852 private void updateInstance(Dependency dependency) {
Marcel Offermans937ab4f2009-12-10 10:53:01 +0000853 if (dependency.isAutoConfig()) {
854 configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
855 if (dependency.isPropagated() && m_registration != null) {
856 m_registration.setProperties(calculateServiceProperties());
Marcel Offermansa962bc92009-11-21 17:59:33 +0000857 }
858 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000859 }
860
861 /**
862 * Configure a field in the service implementation. The service implementation
863 * is searched for fields that have the same type as the class that was specified
864 * and for each of these fields, the specified instance is filled in.
865 *
866 * @param clazz the class to search for
867 * @param instance the instance to fill in
868 * @param instanceName the name of the instance to fill in, or <code>null</code> if not used
869 */
870 private void configureImplementation(Class clazz, Object instance, String instanceName) {
871 Object[] instances = getCompositionInstances();
872 if (instances != null) {
873 for (int i = 0; i < instances.length; i++) {
874 Object serviceInstance = instances[i];
875 Class serviceClazz = serviceInstance.getClass();
Marcel Offermansad760672010-03-03 15:30:01 +0000876 if (Proxy.isProxyClass(serviceClazz)) {
877 serviceInstance = Proxy.getInvocationHandler(serviceInstance);
878 serviceClazz = serviceInstance.getClass();
879 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000880 while (serviceClazz != null) {
881 Field[] fields = serviceClazz.getDeclaredFields();
882 for (int j = 0; j < fields.length; j++) {
Marcel Offermans9afe2f52010-05-11 11:33:39 +0000883 Field field = fields[j];
884 Class type = field.getType();
885 if ((instanceName == null && type.equals(clazz))
886 || (instanceName != null && field.getName().equals(instanceName) && type.isAssignableFrom(clazz))) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000887 try {
Marcel Offermans9afe2f52010-05-11 11:33:39 +0000888 field.setAccessible(true);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000889 // synchronized makes sure the field is actually written to immediately
Marcel Offermanse14b3422009-11-25 23:04:32 +0000890 synchronized (SYNC) {
Marcel Offermans9afe2f52010-05-11 11:33:39 +0000891 field.set(serviceInstance, instance);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000892 }
893 }
894 catch (Exception e) {
Marcel Offermans9afe2f52010-05-11 11:33:39 +0000895 m_logger.log(Logger.LOG_ERROR, "Could not set field " + field, e);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000896 return;
897 }
898 }
899 }
900 serviceClazz = serviceClazz.getSuperclass();
901 }
902 }
903 }
904 }
905
906 public Object[] getCompositionInstances() {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000907 Object[] instances = null;
908 if (m_compositionManagerGetMethod != null) {
909 if (m_compositionManager != null) {
910 m_compositionManagerInstance = m_compositionManager;
911 }
912 else {
913 m_compositionManagerInstance = m_serviceInstance;
914 }
915 if (m_compositionManagerInstance != null) {
916 try {
Marcel Offermans1391d682010-06-17 10:17:47 +0000917 instances = (Object[]) InvocationUtil.invokeMethod(m_compositionManagerInstance, m_compositionManagerInstance.getClass(), m_compositionManagerGetMethod, new Class[][] {{}}, new Object[][] {{}}, false);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000918 }
919 catch (Exception e) {
920 m_logger.log(Logger.LOG_ERROR, "Could not obtain instances from the composition manager.", e);
Marcel Offermans80eeafe2009-12-01 22:12:26 +0000921 instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
Marcel Offermanse14b3422009-11-25 23:04:32 +0000922 }
923 }
924 }
925 else {
Marcel Offermans80eeafe2009-12-01 22:12:26 +0000926 instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
Marcel Offermanse14b3422009-11-25 23:04:32 +0000927 }
928 return instances;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000929 }
930
931 private void configureImplementation(Class clazz, Object instance) {
932 configureImplementation(clazz, instance, null);
933 }
934
935 private void configureServices(State state) {
936 Iterator i = state.getDependencies().iterator();
937 while (i.hasNext()) {
938 Dependency dependency = (Dependency) i.next();
Marcel Offermans001db052009-12-08 08:58:40 +0000939 if (dependency.isAutoConfig()) {
940 configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
Marcel Offermanse14b3422009-11-25 23:04:32 +0000941 }
Marcel Offermans001db052009-12-08 08:58:40 +0000942 if (dependency.isRequired()) {
943 dependency.invokeAdded(this);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000944 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000945 }
946 }
947
948 private void unconfigureServices(State state) {
949 Iterator i = state.getDependencies().iterator();
950 while (i.hasNext()) {
951 Dependency dependency = (Dependency) i.next();
Marcel Offermans001db052009-12-08 08:58:40 +0000952 if (dependency.isRequired()) {
953 dependency.invokeRemoved(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000954 }
Marcel Offermans001db052009-12-08 08:58:40 +0000955// if (dependency instanceof ServiceDependencyImpl) {
956// ServiceDependencyImpl sd = (ServiceDependencyImpl) dependency;
957// // for required dependencies, we invoke any callbacks here
958// if (sd.isRequired()) {
959// sd.invokeRemoved(this, sd.lookupServiceReference(), sd.lookupService());
960// }
961// }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000962 }
963 }
964
Pierre De Rop19476fe2010-05-23 08:13:58 +0000965 protected void ensureNotActive() {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000966 State state;
967 synchronized (m_dependencies) {
968 state = m_state;
969 }
970 if (!state.isInactive()) {
971 throw new IllegalStateException("Cannot modify state while active.");
972 }
973 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000974
975 public boolean isRegistered() {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000976 State state;
977 synchronized (m_dependencies) {
978 state = m_state;
979 }
Marcel Offermans0f6605e2009-12-10 10:31:35 +0000980 return (state.isAllRequiredAvailable());
981 }
982
Marcel Offermansa962bc92009-11-21 17:59:33 +0000983 // ServiceComponent interface
984
985 static class SCDImpl implements ServiceComponentDependency {
986 private final String m_name;
987 private final int m_state;
988 private final String m_type;
989
990 public SCDImpl(String name, int state, String type) {
991 m_name = name;
992 m_state = state;
993 m_type = type;
994 }
995
996 public String getName() {
997 return m_name;
998 }
999
1000 public int getState() {
1001 return m_state;
1002 }
1003
1004 public String getType() {
1005 return m_type;
1006 }
1007 }
1008
1009 public ServiceComponentDependency[] getComponentDependencies() {
1010 List deps = getDependencies();
1011 if (deps != null) {
1012 ServiceComponentDependency[] result = new ServiceComponentDependency[deps.size()];
1013 for (int i = 0; i < result.length; i++) {
1014 Dependency dep = (Dependency) deps.get(i);
1015 if (dep instanceof ServiceComponentDependency) {
1016 result[i] = (ServiceComponentDependency) dep;
1017 }
1018 else {
1019 result[i] = new SCDImpl(dep.toString(), (dep.isAvailable() ? 1 : 0) + (dep.isRequired() ? 2 : 0), dep.getClass().getName());
1020 }
1021 }
1022 return result;
1023 }
1024 return null;
1025 }
1026
1027 public String getName() {
1028 if (m_serviceName instanceof String[]) {
1029 StringBuffer sb = new StringBuffer();
1030 String[] names = (String[]) m_serviceName;
1031 for (int i = 0; i < names.length; i++) {
1032 if (i > 0) {
1033 sb.append(", ");
1034 }
1035 sb.append(names[i]);
1036 }
1037 return sb.toString();
1038 }
1039 else if (m_serviceName instanceof String) {
1040 return m_serviceName.toString();
1041 }
1042 else {
1043 return m_implementation.toString();
1044 }
1045 }
1046
1047 public int getState() {
1048 return (isRegistered() ? 1 : 0);
1049 }
1050
1051 static {
1052 NULL_REGISTRATION = (ServiceRegistration) Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(), new Class[] {ServiceRegistration.class}, new DefaultNullObject());
1053 }
1054}