blob: 9e1966bce51622da5406e1ca958e408bb7ac15cf [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 Offermansea89b862010-06-24 13:14:43 +000023import java.lang.reflect.InvocationTargetException;
Marcel Offermansa962bc92009-11-21 17:59:33 +000024import java.lang.reflect.Proxy;
25import java.util.ArrayList;
26import java.util.Dictionary;
27import java.util.Enumeration;
28import java.util.HashMap;
29import java.util.Hashtable;
30import java.util.Iterator;
31import java.util.List;
32import java.util.Map;
33import java.util.Properties;
34
Marcel Offermans8b93efa2010-07-02 18:27:21 +000035import org.apache.felix.dm.Dependency;
Marcel Offermans3d921212010-08-09 13:37:02 +000036import org.apache.felix.dm.DependencyActivation;
Pierre De Ropd2ec3952009-12-04 22:40:05 +000037import org.apache.felix.dm.DependencyManager;
Marcel Offermans3d921212010-08-09 13:37:02 +000038import org.apache.felix.dm.DependencyService;
Marcel Offermans8b93efa2010-07-02 18:27:21 +000039import org.apache.felix.dm.Service;
40import org.apache.felix.dm.ServiceComponent;
41import org.apache.felix.dm.ServiceComponentDependency;
42import org.apache.felix.dm.ServiceStateListener;
Marcel Offermansa962bc92009-11-21 17:59:33 +000043import org.osgi.framework.BundleContext;
44import org.osgi.framework.ServiceRegistration;
45
46/**
47 * Service implementation.
48 *
49 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
50 */
Marcel Offermanse14b3422009-11-25 23:04:32 +000051public class ServiceImpl implements Service, DependencyService, ServiceComponent {
Marcel Offermansa962bc92009-11-21 17:59:33 +000052 private static final Class[] VOID = new Class[] {};
53 private static final ServiceRegistration NULL_REGISTRATION;
54 private static final ServiceStateListener[] SERVICE_STATE_LISTENER_TYPE = new ServiceStateListener[] {};
55
Marcel Offermanse14b3422009-11-25 23:04:32 +000056 private final Object SYNC = new Object();
Marcel Offermansa962bc92009-11-21 17:59:33 +000057 private final BundleContext m_context;
58 private final DependencyManager m_manager;
59
60 // configuration (static)
61 private String m_callbackInit;
62 private String m_callbackStart;
63 private String m_callbackStop;
64 private String m_callbackDestroy;
65 private Object m_serviceName;
66 private Object m_implementation;
Marcel Offermans61a81142010-04-02 15:16:50 +000067 private Object m_callbackInstance;
Marcel Offermansa962bc92009-11-21 17:59:33 +000068
69 // configuration (dynamic, but does not affect state)
70 private Dictionary m_serviceProperties;
71
72 // configuration (dynamic, and affects state)
73 private ArrayList m_dependencies = new ArrayList();
74
75 // runtime state (calculated from dependencies)
76 private State m_state;
77
78 // runtime state (changes because of state changes)
79 private Object m_serviceInstance;
80 private ServiceRegistration m_registration;
Marcel Offermanse14b3422009-11-25 23:04:32 +000081 private boolean m_isBound;
82 private boolean m_isInstantiated;
Marcel Offermansa962bc92009-11-21 17:59:33 +000083
84 // service state listeners
85 private final List m_stateListeners = new ArrayList();
86
87 // work queue
88 private final SerialExecutor m_executor = new SerialExecutor();
89
90 // instance factory
91 private Object m_instanceFactory;
92 private String m_instanceFactoryCreateMethod;
93
94 // composition manager
95 private Object m_compositionManager;
96 private String m_compositionManagerGetMethod;
97 private Object m_compositionManagerInstance;
98
99 // internal logging
100 private final Logger m_logger;
101 private ServiceRegistration m_serviceRegistration;
102 private Map m_autoConfig = new HashMap();
103 private Map m_autoConfigInstance = new HashMap();
104
105 public ServiceImpl(BundleContext context, DependencyManager manager, Logger logger) {
106 m_logger = logger;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000107 m_state = new State((List) m_dependencies.clone(), false, false, false);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000108 m_context = context;
109 m_manager = manager;
110 m_callbackInit = "init";
111 m_callbackStart = "start";
112 m_callbackStop = "stop";
113 m_callbackDestroy = "destroy";
114 m_implementation = null;
115 m_autoConfig.put(BundleContext.class, Boolean.TRUE);
116 m_autoConfig.put(ServiceRegistration.class, Boolean.TRUE);
117 m_autoConfig.put(DependencyManager.class, Boolean.TRUE);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000118 m_autoConfig.put(Service.class, Boolean.TRUE);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000119 }
120
Marcel Offermanse14b3422009-11-25 23:04:32 +0000121 private void calculateStateChanges() {
122 // see if any of the things we did caused a further change of state
123 State oldState, newState;
124 synchronized (m_dependencies) {
125 oldState = m_state;
126 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
127 m_state = newState;
128 }
129 calculateStateChanges(oldState, newState);
130 }
131
Marcel Offermansa962bc92009-11-21 17:59:33 +0000132 private void calculateStateChanges(final State oldState, final State newState) {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000133 if (oldState.isInactive() && (newState.isTrackingOptional())) {
134 m_executor.enqueue(new Runnable() {
135 public void run() {
136 activateService(newState);
137 }});
138 }
139 if (oldState.isInactive() && (newState.isWaitingForRequired())) {
140 m_executor.enqueue(new Runnable() {
141 public void run() {
142 startTrackingRequired(newState);
143 }});
144 }
145 if (oldState.isWaitingForRequired() && newState.isTrackingOptional()) {
146 m_executor.enqueue(new Runnable() {
147 public void run() {
148 activateService(newState);
149 }});
150 }
151 if ((oldState.isWaitingForRequired()) && newState.isInactive()) {
152 m_executor.enqueue(new Runnable() {
153 public void run() {
154 stopTrackingRequired(oldState);
155 }});
156 }
157 if (oldState.isTrackingOptional() && newState.isWaitingForRequiredInstantiated()) {
158 m_executor.enqueue(new Runnable() {
159 public void run() {
160 // TODO as far as I can see there is nothing left to do here
161 }});
162 }
163 if (oldState.isTrackingOptional() && newState.isWaitingForRequired()) {
164 m_executor.enqueue(new Runnable() {
165 public void run() {
166 deactivateService(oldState);
167 }});
168 }
169 if (oldState.isTrackingOptional() && newState.isBound()) {
170 m_executor.enqueue(new Runnable() {
171 public void run() {
Marcel Offermansbedf3692010-06-06 20:07:12 +0000172 bindService(newState);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000173 }});
174 }
175 if (oldState.isTrackingOptional() && newState.isInactive()) {
176 m_executor.enqueue(new Runnable() {
177 public void run() {
178 deactivateService(oldState);
179 stopTrackingRequired(oldState);
180 }});
181 }
182 if (oldState.isWaitingForRequiredInstantiated() && newState.isWaitingForRequired()) {
183 m_executor.enqueue(new Runnable() {
184 public void run() {
185 deactivateService(oldState);
186 }});
187 }
188 if (oldState.isWaitingForRequiredInstantiated() && newState.isInactive()) {
189 m_executor.enqueue(new Runnable() {
190 public void run() {
191 deactivateService(oldState);
192 stopTrackingRequired(oldState);
193 }});
194 }
195 if (oldState.isWaitingForRequiredInstantiated() && newState.isBound()) {
196 m_executor.enqueue(new Runnable() {
197 public void run() {
Marcel Offermansbedf3692010-06-06 20:07:12 +0000198 bindService(newState);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000199 }});
200 }
201 if (oldState.isBound() && newState.isWaitingForRequiredInstantiated()) {
202 m_executor.enqueue(new Runnable() {
203 public void run() {
204 unbindService(oldState);
205 }});
206 }
207 if (oldState.isBound() && newState.isWaitingForRequired()) {
208 m_executor.enqueue(new Runnable() {
209 public void run() {
210 unbindService(oldState);
211 deactivateService(oldState);
212 }});
213 }
214 if (oldState.isBound() && newState.isInactive()) {
215 m_executor.enqueue(new Runnable() {
216 public void run() {
217 unbindService(oldState);
218 deactivateService(oldState);
219 stopTrackingRequired(oldState);
220 }});
221 }
222 m_executor.execute();
Marcel Offermansa962bc92009-11-21 17:59:33 +0000223 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000224
Marcel Offermansa962bc92009-11-21 17:59:33 +0000225 public Service add(final Dependency dependency) {
226 State oldState, newState;
227 synchronized (m_dependencies) {
228 oldState = m_state;
229 m_dependencies.add(dependency);
230 }
Pierre De Rop79ac9712010-06-11 06:02:07 +0000231
232 if (dependency.isInstanceBound()) {
233 // At this point: this dependency is added from init(): but we don't want to start it now,
234 // because if we start it, and if the required dependency is available, then the service.start()
235 // method will be called, and this is a problem if a further
236 // required (but unavailable) dependency is then added again from the init() method ...
237 // Once the init() method will return, the activateService method will then calculate the state changes,
238 // but at this point, all added extra-dependencies will be known.
239 return this;
240 }
241
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000242 if (oldState.isAllRequiredAvailable() || (oldState.isWaitingForRequiredInstantiated() && dependency.isRequired()) || (oldState.isWaitingForRequired() && dependency.isRequired())) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000243 ((DependencyActivation) dependency).start(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000244 }
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000245
Marcel Offermansa962bc92009-11-21 17:59:33 +0000246 synchronized (m_dependencies) {
Marcel Offermans306c2522009-12-17 13:57:58 +0000247 // starting the dependency above might have triggered another state change, so
248 // we have to fetch the current state again
249 oldState = m_state;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000250 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000251 m_state = newState;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000252 }
253 calculateStateChanges(oldState, newState);
254 return this;
255 }
256
257 public Service add(List dependencies) {
258 // TODO review if this can be done more smartly
259 for (int i = 0; i < dependencies.size(); i++) {
260 add((Dependency) dependencies.get(i));
Marcel Offermansa962bc92009-11-21 17:59:33 +0000261 }
262 return this;
263 }
264
265 public Service remove(Dependency dependency) {
266 State oldState, newState;
267 synchronized (m_dependencies) {
268 oldState = m_state;
269 m_dependencies.remove(dependency);
270 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000271 if (oldState.isAllRequiredAvailable() || (oldState.isWaitingForRequired() && dependency.isRequired())) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000272 ((DependencyActivation) dependency).stop(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000273 }
274 synchronized (m_dependencies) {
Marcel Offermans306c2522009-12-17 13:57:58 +0000275 // starting the dependency above might have triggered another state change, so
276 // we have to fetch the current state again
277 oldState = m_state;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000278 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000279 m_state = newState;
280 }
281 calculateStateChanges(oldState, newState);
282 return this;
283 }
284
285 public List getDependencies() {
286 synchronized (m_dependencies) {
287 return (List) m_dependencies.clone();
288 }
289 }
290
291 public ServiceRegistration getServiceRegistration() {
292 return m_registration;
293 }
294
295 public Object getService() {
296 return m_serviceInstance;
297 }
Marcel Offermansea89b862010-06-24 13:14:43 +0000298
299 public Service getServiceInterface() {
300 return this;
301 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000302
303 public void dependencyAvailable(final Dependency dependency) {
304 State oldState, newState;
305 synchronized (m_dependencies) {
306 oldState = m_state;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000307 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000308 m_state = newState;
309 }
Marcel Offermans6cb7ac22010-01-04 09:32:37 +0000310 if (newState.isAllRequiredAvailable() || newState.isWaitingForRequiredInstantiated()) {
Marcel Offermans84a43ad2009-12-29 14:54:48 +0000311 updateInstance(dependency);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000312 }
Marcel Offermans306c2522009-12-17 13:57:58 +0000313 calculateStateChanges(oldState, newState);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000314 }
315
316 public void dependencyChanged(final Dependency dependency) {
317 State state;
318 synchronized (m_dependencies) {
319 state = m_state;
320 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000321 if (state.isAllRequiredAvailable()) {
Marcel Offermans84a43ad2009-12-29 14:54:48 +0000322 updateInstance(dependency);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000323 }
324 }
325
326 public void dependencyUnavailable(final Dependency dependency) {
327 State oldState, newState;
328 synchronized (m_dependencies) {
329 oldState = m_state;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000330 newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000331 m_state = newState;
332 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000333 if (newState.isAllRequiredAvailable()) {
Marcel Offermans84a43ad2009-12-29 14:54:48 +0000334 updateInstance(dependency);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000335 }
Marcel Offermans306c2522009-12-17 13:57:58 +0000336 calculateStateChanges(oldState, newState);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000337 }
338
339 public synchronized void start() {
Marcel Offermans6358e052010-01-04 14:36:08 +0000340 if (m_serviceRegistration == null) {
341 m_serviceRegistration = m_context.registerService(ServiceComponent.class.getName(), this, null);
342 State oldState, newState;
343 synchronized (m_dependencies) {
344 oldState = m_state;
345 newState = new State((List) m_dependencies.clone(), true, m_isInstantiated, m_isBound);
346 m_state = newState;
347 }
348 calculateStateChanges(oldState, newState);
349 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000350 }
351
352 public synchronized void stop() {
Marcel Offermans6358e052010-01-04 14:36:08 +0000353 if (m_serviceRegistration != null) {
354 State oldState, newState;
355 synchronized (m_dependencies) {
356 oldState = m_state;
357 newState = new State((List) m_dependencies.clone(), false, m_isInstantiated, m_isBound);
358 m_state = newState;
359 }
360 calculateStateChanges(oldState, newState);
361 m_serviceRegistration.unregister();
362 m_serviceRegistration = null;
363 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000364 }
365
366 public synchronized Service setInterface(String serviceName, Dictionary properties) {
367 ensureNotActive();
368 m_serviceName = serviceName;
369 m_serviceProperties = properties;
370 return this;
371 }
372
373 public synchronized Service setInterface(String[] serviceName, Dictionary properties) {
374 ensureNotActive();
375 m_serviceName = serviceName;
376 m_serviceProperties = properties;
377 return this;
378 }
379
380 public synchronized Service setCallbacks(String init, String start, String stop, String destroy) {
381 ensureNotActive();
382 m_callbackInit = init;
383 m_callbackStart = start;
384 m_callbackStop = stop;
385 m_callbackDestroy = destroy;
386 return this;
387 }
Marcel Offermans61a81142010-04-02 15:16:50 +0000388
389 public synchronized Service setCallbacks(Object instance, String init, String start, String stop, String destroy) {
390 ensureNotActive();
391 m_callbackInstance = instance;
392 m_callbackInit = init;
393 m_callbackStart = start;
394 m_callbackStop = stop;
395 m_callbackDestroy = destroy;
396 return this;
397 }
398
399
Marcel Offermansa962bc92009-11-21 17:59:33 +0000400
401 public synchronized Service setImplementation(Object implementation) {
402 ensureNotActive();
403 m_implementation = implementation;
404 return this;
405 }
406
407 public synchronized Service setFactory(Object factory, String createMethod) {
408 ensureNotActive();
409 m_instanceFactory = factory;
410 m_instanceFactoryCreateMethod = createMethod;
411 return this;
412 }
413
414 public synchronized Service setFactory(String createMethod) {
415 return setFactory(null, createMethod);
416 }
417
418 public synchronized Service setComposition(Object instance, String getMethod) {
419 ensureNotActive();
420 m_compositionManager = instance;
421 m_compositionManagerGetMethod = getMethod;
422 return this;
423 }
424
425 public synchronized Service setComposition(String getMethod) {
426 return setComposition(null, getMethod);
427 }
428
429 public String toString() {
430 return "ServiceImpl[" + m_serviceName + " " + m_implementation + "]";
431 }
432
433 public synchronized Dictionary getServiceProperties() {
434 if (m_serviceProperties != null) {
435 return (Dictionary) ((Hashtable) m_serviceProperties).clone();
436 }
437 return null;
438 }
439
Pierre De Rop19476fe2010-05-23 08:13:58 +0000440 public synchronized Service setServiceProperties(Dictionary serviceProperties) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000441 m_serviceProperties = serviceProperties;
Marcel Offermans937ab4f2009-12-10 10:53:01 +0000442 if ((m_registration != null) && (m_serviceName != null)) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000443 m_registration.setProperties(calculateServiceProperties());
444 }
Pierre De Rop19476fe2010-05-23 08:13:58 +0000445 return this;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000446 }
447
448 // service state listener methods
449 public void addStateListener(ServiceStateListener listener) {
450 synchronized (m_stateListeners) {
451 m_stateListeners.add(listener);
452 }
453 // when we register as a listener and the service is already started
454 // make sure we invoke the right callbacks so the listener knows
455 State state;
456 synchronized (m_dependencies) {
457 state = m_state;
458 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000459 if (state.isAllRequiredAvailable()) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000460 listener.starting(this);
461 listener.started(this);
462 }
463 }
464
465 public void removeStateListener(ServiceStateListener listener) {
466 synchronized (m_stateListeners) {
467 m_stateListeners.remove(listener);
468 }
469 }
470
Marcel Offermanse14b3422009-11-25 23:04:32 +0000471 public void removeStateListeners() {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000472 synchronized (m_stateListeners) {
473 m_stateListeners.clear();
474 }
475 }
476
477 private void stateListenersStarting() {
478 ServiceStateListener[] list = getListeners();
479 for (int i = 0; i < list.length; i++) {
480 try {
481 list[i].starting(this);
482 }
483 catch (Throwable t) {
484 m_logger.log(Logger.LOG_ERROR, "Error invoking listener starting method.", t);
485 }
486 }
487 }
488
489 private void stateListenersStarted() {
490 ServiceStateListener[] list = getListeners();
491 for (int i = 0; i < list.length; i++) {
492 try {
493 list[i].started(this);
494 }
495 catch (Throwable t) {
496 m_logger.log(Logger.LOG_ERROR, "Error invoking listener started method.", t);
497 }
498 }
499 }
500
501 private void stateListenersStopping() {
502 ServiceStateListener[] list = getListeners();
503 for (int i = 0; i < list.length; i++) {
504 try {
505 list[i].stopping(this);
506 }
507 catch (Throwable t) {
508 m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopping method.", t);
509 }
510 }
511 }
512
513 private void stateListenersStopped() {
514 ServiceStateListener[] list = getListeners();
515 for (int i = 0; i < list.length; i++) {
516 try {
517 list[i].stopped(this);
518 }
519 catch (Throwable t) {
520 m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopped method.", t);
521 }
522 }
523 }
524
525 private ServiceStateListener[] getListeners() {
526 synchronized (m_stateListeners) {
527 return (ServiceStateListener[]) m_stateListeners.toArray(SERVICE_STATE_LISTENER_TYPE);
528 }
529 }
530
Marcel Offermanse14b3422009-11-25 23:04:32 +0000531 private void activateService(State state) {
532 String init;
533 synchronized (this) {
534 init = m_callbackInit;
535 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000536 // service activation logic, first we initialize the service instance itself
537 // meaning it is created if necessary and the bundle context is set
538 initService();
Marcel Offermansa962bc92009-11-21 17:59:33 +0000539 // now is the time to configure the service, meaning all required
540 // dependencies will be set and any callbacks called
541 configureService(state);
Marcel Offermans78e5dfc2009-12-10 13:52:49 +0000542 // flag that our instance has been created
543 m_isInstantiated = true;
Marcel Offermanse14b3422009-11-25 23:04:32 +0000544 // then we invoke the init callback so the service can further initialize
545 // itself
546 invoke(init);
Pierre De Rop79ac9712010-06-11 06:02:07 +0000547 // start extra/required dependencies which might have been added from the init() method.
548 startExtraRequiredDependencies();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000549 // see if any of this caused further state changes
550 calculateStateChanges();
551 }
552
Pierre De Rop79ac9712010-06-11 06:02:07 +0000553 private void startExtraRequiredDependencies() {
554 Iterator i = m_dependencies.iterator();
555 while (i.hasNext()) {
556 Dependency dependency = (Dependency) i.next();
557 if (dependency.isInstanceBound() && dependency.isRequired()) {
558 // Optional extra dependencies will be started later, once our service is started.
559 ((DependencyActivation) dependency).start(this);
560 }
561 }
562 }
563
Marcel Offermanse14b3422009-11-25 23:04:32 +0000564 private void bindService(State state) {
565 String start;
566 synchronized (this) {
567 start = m_callbackStart;
568 }
Pierre De Rop79ac9712010-06-11 06:02:07 +0000569
570 // configure service with extra-dependencies which might have been added from init() method.
571 configureServiceWithExtraDependencies(state);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000572 // inform the state listeners we're starting
573 stateListenersStarting();
574 // invoke the start callback, since we're now ready to be used
575 invoke(start);
576 // start tracking optional services
577 startTrackingOptional(state);
578 // register the service in the framework's service registry
579 registerService();
580 // inform the state listeners we've started
581 stateListenersStarted();
582 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000583
Pierre De Rop79ac9712010-06-11 06:02:07 +0000584 private void configureServiceWithExtraDependencies(State state)
585 {
586 Iterator i = state.getDependencies().iterator();
587 while (i.hasNext()) {
588 Dependency dependency = (Dependency) i.next();
589 if (dependency.isAutoConfig() && dependency.isInstanceBound()) {
590 configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
591 }
592 if (dependency.isRequired() && dependency.isInstanceBound()) {
593 dependency.invokeAdded(this);
594 }
595 }
596 }
597
Marcel Offermanse14b3422009-11-25 23:04:32 +0000598 private void unbindService(State state) {
599 String stop;
600 synchronized (this) {
601 stop = m_callbackStop;
602 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000603 // service deactivation logic, first inform the state listeners
604 // we're stopping
605 stateListenersStopping();
606 // then, unregister the service from the framework
607 unregisterService();
608 // stop tracking optional services
609 stopTrackingOptional(state);
610 // invoke the stop callback
611 invoke(stop);
612 // inform the state listeners we've stopped
613 stateListenersStopped();
Marcel Offermanse14b3422009-11-25 23:04:32 +0000614 }
615
616 private void deactivateService(State state) {
617 String destroy;
618 synchronized (this) {
619 destroy = m_callbackDestroy;
620 }
Marcel Offermans78e5dfc2009-12-10 13:52:49 +0000621 // flag that our instance was destroyed
622 m_isInstantiated = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000623 // invoke the destroy callback
624 invoke(destroy);
625 // destroy the service instance
626 destroyService(state);
627 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000628
Marcel Offermansa962bc92009-11-21 17:59:33 +0000629 private void invoke(String name) {
630 if (name != null) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000631 // if a callback instance was specified, look for the method there, if not,
632 // ask the service for its composition instances
633 Object[] instances = m_callbackInstance != null ? new Object[] { m_callbackInstance } : getCompositionInstances();
634 invokeCallbackMethod(instances, name,
635 new Class[][] {{ Service.class }, {}},
636 new Object[][] {{ this }, {}});
637 }
638 }
639
640 public void invokeCallbackMethod(Object[] instances, String methodName, Class[][] signatures, Object[][] parameters) {
641 for (int i = 0; i < instances.length; i++) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000642 try {
Marcel Offermansea89b862010-06-24 13:14:43 +0000643 InvocationUtil.invokeCallbackMethod(instances[i], methodName, signatures, parameters);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000644 }
Marcel Offermanse43114b2010-04-04 18:37:44 +0000645 catch (NoSuchMethodException e) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000646 // if the method does not exist, ignore it
647 }
648 catch (InvocationTargetException e) {
649 // the method itself threw an exception, log that
650 m_logger.log(Logger.LOG_WARNING, "Invocation of '" + methodName + "' failed.", e.getCause());
Marcel Offermanse43114b2010-04-04 18:37:44 +0000651 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000652 catch (Exception e) {
Marcel Offermansea89b862010-06-24 13:14:43 +0000653 m_logger.log(Logger.LOG_WARNING, "Could not invoke '" + methodName + "'.", e);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000654 }
655 }
656 }
657
658 private void startTrackingOptional(State state) {
659 Iterator i = state.getDependencies().iterator();
660 while (i.hasNext()) {
661 Dependency dependency = (Dependency) i.next();
662 if (!dependency.isRequired()) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000663 ((DependencyActivation) dependency).start(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000664 }
665 }
666 }
667
668 private void stopTrackingOptional(State state) {
669 Iterator i = state.getDependencies().iterator();
670 while (i.hasNext()) {
671 Dependency dependency = (Dependency) i.next();
672 if (!dependency.isRequired()) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000673 ((DependencyActivation) dependency).stop(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000674 }
675 }
676 }
677
678 private void startTrackingRequired(State state) {
679 Iterator i = state.getDependencies().iterator();
680 while (i.hasNext()) {
681 Dependency dependency = (Dependency) i.next();
682 if (dependency.isRequired()) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000683 ((DependencyActivation) dependency).start(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000684 }
685 }
686 }
687
688 private void stopTrackingRequired(State state) {
689 Iterator i = state.getDependencies().iterator();
690 while (i.hasNext()) {
691 Dependency dependency = (Dependency) i.next();
692 if (dependency.isRequired()) {
Pierre De Ropd2ec3952009-12-04 22:40:05 +0000693 ((DependencyActivation) dependency).stop(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000694 }
695 }
696 }
697
698 private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
699 Constructor constructor = clazz.getConstructor(VOID);
700 constructor.setAccessible(true);
701 return clazz.newInstance();
702 }
703
Marcel Offermanse14b3422009-11-25 23:04:32 +0000704 public void initService() {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000705 if (m_serviceInstance == null) {
706 if (m_implementation instanceof Class) {
707 // instantiate
708 try {
709 m_serviceInstance = createInstance((Class) m_implementation);
710 }
711 catch (Exception e) {
712 m_logger.log(Logger.LOG_ERROR, "Could not create service instance of class " + m_implementation + ".", e);
713 }
714 }
715 else {
716 if (m_instanceFactoryCreateMethod != null) {
717 Object factory = null;
718 if (m_instanceFactory != null) {
719 if (m_instanceFactory instanceof Class) {
720 try {
721 factory = createInstance((Class) m_instanceFactory);
722 }
723 catch (Exception e) {
724 m_logger.log(Logger.LOG_ERROR, "Could not create factory instance of class " + m_instanceFactory + ".", e);
725 }
726 }
727 else {
728 factory = m_instanceFactory;
729 }
730 }
731 else {
732 // TODO review if we want to try to default to something if not specified
733 // for now the JavaDoc of setFactory(method) reflects the fact that we need
734 // to review it
735 }
736 if (factory == null) {
737 m_logger.log(Logger.LOG_ERROR, "Factory cannot be null.");
738 }
739 else {
740 try {
Marcel Offermansa6ffb992010-05-19 11:56:44 +0000741 m_serviceInstance = InvocationUtil.invokeMethod(factory, factory.getClass(), m_instanceFactoryCreateMethod, new Class[][] {{}}, new Object[][] {{}}, false);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000742 }
743 catch (Exception e) {
744 m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
745 }
746 }
747 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000748 if (m_serviceInstance == null) {
Marcel Offermanscc8adbb2010-02-17 10:20:11 +0000749 if (m_implementation == null) {
750 m_logger.log(Logger.LOG_ERROR, "Implementation cannot be null.");
751 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000752 m_serviceInstance = m_implementation;
753 }
754 }
755 // configure the bundle context
756 if (((Boolean) m_autoConfig.get(BundleContext.class)).booleanValue()) {
757 configureImplementation(BundleContext.class, m_context, (String) m_autoConfigInstance.get(BundleContext.class));
758 }
759 if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
760 configureImplementation(ServiceRegistration.class, NULL_REGISTRATION, (String) m_autoConfigInstance.get(ServiceRegistration.class));
761 }
762 if (((Boolean) m_autoConfig.get(DependencyManager.class)).booleanValue()) {
763 configureImplementation(DependencyManager.class, m_manager, (String) m_autoConfigInstance.get(DependencyManager.class));
764 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000765 if (((Boolean) m_autoConfig.get(Service.class)).booleanValue()) {
766 configureImplementation(Service.class, this, (String) m_autoConfigInstance.get(Service.class));
767 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000768 }
769 }
770
Marcel Offermans3d921212010-08-09 13:37:02 +0000771 public synchronized Service setAutoConfig(Class clazz, boolean autoConfig) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000772 m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
Marcel Offermans3d921212010-08-09 13:37:02 +0000773 return this;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000774 }
775
Marcel Offermans3d921212010-08-09 13:37:02 +0000776 public synchronized Service setAutoConfig(Class clazz, String instanceName) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000777 m_autoConfig.put(clazz, Boolean.valueOf(instanceName != null));
778 m_autoConfigInstance.put(clazz, instanceName);
Marcel Offermans3d921212010-08-09 13:37:02 +0000779 return this;
780 }
781
782 public boolean getAutoConfig(Class clazz) {
783 Boolean result = (Boolean) m_autoConfig.get(clazz);
784 return (result != null && result.booleanValue());
785 }
786
787 public String getAutoConfigInstance(Class clazz) {
788 return (String) m_autoConfigInstance.get(clazz);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000789 }
790
791 private void configureService(State state) {
792 // configure all services (the optional dependencies might be configured
793 // as null objects but that's what we want at this point)
794 configureServices(state);
795 }
796
797 private void destroyService(State state) {
798 unconfigureServices(state);
799 m_serviceInstance = null;
800 }
801
802 private void registerService() {
803 if (m_serviceName != null) {
804 ServiceRegistrationImpl wrapper = new ServiceRegistrationImpl();
805 m_registration = wrapper;
806 if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
807 configureImplementation(ServiceRegistration.class, m_registration, (String) m_autoConfigInstance.get(ServiceRegistration.class));
808 }
809
810 // service name can either be a string or an array of strings
811 ServiceRegistration registration;
812
813 // determine service properties
814 Dictionary properties = calculateServiceProperties();
815
816 // register the service
817 try {
818 if (m_serviceName instanceof String) {
819 registration = m_context.registerService((String) m_serviceName, m_serviceInstance, properties);
820 }
821 else {
822 registration = m_context.registerService((String[]) m_serviceName, m_serviceInstance, properties);
823 }
824 wrapper.setServiceRegistration(registration);
825 }
826 catch (IllegalArgumentException iae) {
827 m_logger.log(Logger.LOG_ERROR, "Could not register service " + m_serviceInstance, iae);
828 // set the registration to an illegal state object, which will make all invocations on this
829 // wrapper fail with an ISE (which also occurs when the SR becomes invalid)
830 wrapper.setIllegalState();
831 }
832 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000833 m_isBound = true;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000834 }
835
836 private Dictionary calculateServiceProperties() {
837 Dictionary properties = new Properties();
838 addTo(properties, m_serviceProperties);
839 for (int i = 0; i < m_dependencies.size(); i++) {
840 Dependency d = (Dependency) m_dependencies.get(i);
Marcel Offermans117aa2f2009-12-10 09:48:17 +0000841 if (d.isPropagated()) {
842 Dictionary dict = d.getProperties();
843 addTo(properties, dict);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000844 }
845 }
846 if (properties.size() == 0) {
847 properties = null;
848 }
849 return properties;
850 }
851
852 private void addTo(Dictionary properties, Dictionary additional) {
853 if (properties == null) {
854 throw new IllegalArgumentException("Dictionary to add to cannot be null.");
855 }
856 if (additional != null) {
857 Enumeration e = additional.keys();
858 while (e.hasMoreElements()) {
859 Object key = e.nextElement();
860 properties.put(key, additional.get(key));
861 }
862 }
863 }
864
865 private void unregisterService() {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000866 m_isBound = false;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000867 if (m_serviceName != null) {
868 m_registration.unregister();
869 configureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
870 }
871 }
872
873 private void updateInstance(Dependency dependency) {
Marcel Offermans937ab4f2009-12-10 10:53:01 +0000874 if (dependency.isAutoConfig()) {
875 configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
876 if (dependency.isPropagated() && m_registration != null) {
877 m_registration.setProperties(calculateServiceProperties());
Marcel Offermansa962bc92009-11-21 17:59:33 +0000878 }
879 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000880 }
881
882 /**
883 * Configure a field in the service implementation. The service implementation
884 * is searched for fields that have the same type as the class that was specified
885 * and for each of these fields, the specified instance is filled in.
886 *
887 * @param clazz the class to search for
888 * @param instance the instance to fill in
889 * @param instanceName the name of the instance to fill in, or <code>null</code> if not used
890 */
891 private void configureImplementation(Class clazz, Object instance, String instanceName) {
892 Object[] instances = getCompositionInstances();
893 if (instances != null) {
894 for (int i = 0; i < instances.length; i++) {
895 Object serviceInstance = instances[i];
896 Class serviceClazz = serviceInstance.getClass();
Marcel Offermansad760672010-03-03 15:30:01 +0000897 if (Proxy.isProxyClass(serviceClazz)) {
898 serviceInstance = Proxy.getInvocationHandler(serviceInstance);
899 serviceClazz = serviceInstance.getClass();
900 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000901 while (serviceClazz != null) {
902 Field[] fields = serviceClazz.getDeclaredFields();
903 for (int j = 0; j < fields.length; j++) {
Marcel Offermans9afe2f52010-05-11 11:33:39 +0000904 Field field = fields[j];
905 Class type = field.getType();
906 if ((instanceName == null && type.equals(clazz))
907 || (instanceName != null && field.getName().equals(instanceName) && type.isAssignableFrom(clazz))) {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000908 try {
Marcel Offermans9afe2f52010-05-11 11:33:39 +0000909 field.setAccessible(true);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000910 // synchronized makes sure the field is actually written to immediately
Marcel Offermanse14b3422009-11-25 23:04:32 +0000911 synchronized (SYNC) {
Marcel Offermans9afe2f52010-05-11 11:33:39 +0000912 field.set(serviceInstance, instance);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000913 }
914 }
915 catch (Exception e) {
Marcel Offermans9afe2f52010-05-11 11:33:39 +0000916 m_logger.log(Logger.LOG_ERROR, "Could not set field " + field, e);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000917 return;
918 }
919 }
920 }
921 serviceClazz = serviceClazz.getSuperclass();
922 }
923 }
924 }
925 }
926
927 public Object[] getCompositionInstances() {
Marcel Offermanse14b3422009-11-25 23:04:32 +0000928 Object[] instances = null;
929 if (m_compositionManagerGetMethod != null) {
930 if (m_compositionManager != null) {
931 m_compositionManagerInstance = m_compositionManager;
932 }
933 else {
934 m_compositionManagerInstance = m_serviceInstance;
935 }
936 if (m_compositionManagerInstance != null) {
937 try {
Marcel Offermans1391d682010-06-17 10:17:47 +0000938 instances = (Object[]) InvocationUtil.invokeMethod(m_compositionManagerInstance, m_compositionManagerInstance.getClass(), m_compositionManagerGetMethod, new Class[][] {{}}, new Object[][] {{}}, false);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000939 }
940 catch (Exception e) {
941 m_logger.log(Logger.LOG_ERROR, "Could not obtain instances from the composition manager.", e);
Marcel Offermans80eeafe2009-12-01 22:12:26 +0000942 instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
Marcel Offermanse14b3422009-11-25 23:04:32 +0000943 }
944 }
945 }
946 else {
Marcel Offermans80eeafe2009-12-01 22:12:26 +0000947 instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
Marcel Offermanse14b3422009-11-25 23:04:32 +0000948 }
949 return instances;
Marcel Offermansa962bc92009-11-21 17:59:33 +0000950 }
951
952 private void configureImplementation(Class clazz, Object instance) {
953 configureImplementation(clazz, instance, null);
954 }
955
956 private void configureServices(State state) {
957 Iterator i = state.getDependencies().iterator();
958 while (i.hasNext()) {
959 Dependency dependency = (Dependency) i.next();
Marcel Offermans001db052009-12-08 08:58:40 +0000960 if (dependency.isAutoConfig()) {
961 configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
Marcel Offermanse14b3422009-11-25 23:04:32 +0000962 }
Marcel Offermans001db052009-12-08 08:58:40 +0000963 if (dependency.isRequired()) {
964 dependency.invokeAdded(this);
Marcel Offermanse14b3422009-11-25 23:04:32 +0000965 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000966 }
967 }
968
969 private void unconfigureServices(State state) {
970 Iterator i = state.getDependencies().iterator();
971 while (i.hasNext()) {
972 Dependency dependency = (Dependency) i.next();
Marcel Offermans001db052009-12-08 08:58:40 +0000973 if (dependency.isRequired()) {
974 dependency.invokeRemoved(this);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000975 }
Marcel Offermans001db052009-12-08 08:58:40 +0000976// if (dependency instanceof ServiceDependencyImpl) {
977// ServiceDependencyImpl sd = (ServiceDependencyImpl) dependency;
978// // for required dependencies, we invoke any callbacks here
979// if (sd.isRequired()) {
980// sd.invokeRemoved(this, sd.lookupServiceReference(), sd.lookupService());
981// }
982// }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000983 }
984 }
985
Pierre De Rop19476fe2010-05-23 08:13:58 +0000986 protected void ensureNotActive() {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000987 State state;
988 synchronized (m_dependencies) {
989 state = m_state;
990 }
991 if (!state.isInactive()) {
992 throw new IllegalStateException("Cannot modify state while active.");
993 }
994 }
Marcel Offermanse14b3422009-11-25 23:04:32 +0000995
996 public boolean isRegistered() {
Marcel Offermansa962bc92009-11-21 17:59:33 +0000997 State state;
998 synchronized (m_dependencies) {
999 state = m_state;
1000 }
Marcel Offermans0f6605e2009-12-10 10:31:35 +00001001 return (state.isAllRequiredAvailable());
1002 }
1003
Marcel Offermansa962bc92009-11-21 17:59:33 +00001004 // ServiceComponent interface
1005
1006 static class SCDImpl implements ServiceComponentDependency {
1007 private final String m_name;
1008 private final int m_state;
1009 private final String m_type;
1010
1011 public SCDImpl(String name, int state, String type) {
1012 m_name = name;
1013 m_state = state;
1014 m_type = type;
1015 }
1016
1017 public String getName() {
1018 return m_name;
1019 }
1020
1021 public int getState() {
1022 return m_state;
1023 }
1024
1025 public String getType() {
1026 return m_type;
1027 }
1028 }
1029
1030 public ServiceComponentDependency[] getComponentDependencies() {
1031 List deps = getDependencies();
1032 if (deps != null) {
1033 ServiceComponentDependency[] result = new ServiceComponentDependency[deps.size()];
1034 for (int i = 0; i < result.length; i++) {
1035 Dependency dep = (Dependency) deps.get(i);
1036 if (dep instanceof ServiceComponentDependency) {
1037 result[i] = (ServiceComponentDependency) dep;
1038 }
1039 else {
1040 result[i] = new SCDImpl(dep.toString(), (dep.isAvailable() ? 1 : 0) + (dep.isRequired() ? 2 : 0), dep.getClass().getName());
1041 }
1042 }
1043 return result;
1044 }
1045 return null;
1046 }
1047
1048 public String getName() {
1049 if (m_serviceName instanceof String[]) {
1050 StringBuffer sb = new StringBuffer();
1051 String[] names = (String[]) m_serviceName;
1052 for (int i = 0; i < names.length; i++) {
1053 if (i > 0) {
1054 sb.append(", ");
1055 }
1056 sb.append(names[i]);
1057 }
1058 return sb.toString();
1059 }
1060 else if (m_serviceName instanceof String) {
1061 return m_serviceName.toString();
1062 }
1063 else {
1064 return m_implementation.toString();
1065 }
1066 }
1067
1068 public int getState() {
1069 return (isRegistered() ? 1 : 0);
1070 }
1071
Marcel Offermansea89b862010-06-24 13:14:43 +00001072 public DependencyManager getDependencyManager() {
1073 return m_manager;
1074 }
1075
Marcel Offermansa962bc92009-11-21 17:59:33 +00001076 static {
1077 NULL_REGISTRATION = (ServiceRegistration) Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(), new Class[] {ServiceRegistration.class}, new DefaultNullObject());
1078 }
1079}