1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.osgi.extender.internal.dependencies.startup;
18
19 import java.security.AccessController;
20 import java.security.PrivilegedAction;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Timer;
24 import java.util.TimerTask;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.osgi.framework.Bundle;
29 import org.osgi.framework.Filter;
30 import org.springframework.beans.BeansException;
31 import org.springframework.context.ApplicationContextException;
32 import org.springframework.context.ConfigurableApplicationContext;
33 import org.springframework.core.task.TaskExecutor;
34 import org.springframework.osgi.context.DelegatedExecutionOsgiBundleApplicationContext;
35 import org.springframework.osgi.context.OsgiBundleApplicationContextExecutor;
36 import org.springframework.osgi.context.event.OsgiBundleApplicationContextEventMulticaster;
37 import org.springframework.osgi.context.event.OsgiBundleContextFailedEvent;
38 import org.springframework.osgi.extender.OsgiServiceDependencyFactory;
39 import org.springframework.osgi.extender.event.BootstrappingDependenciesFailedEvent;
40 import org.springframework.osgi.extender.internal.util.concurrent.Counter;
41 import org.springframework.osgi.service.importer.event.OsgiServiceDependencyEvent;
42 import org.springframework.osgi.util.OsgiFilterUtils;
43 import org.springframework.osgi.util.OsgiStringUtils;
44 import org.springframework.util.Assert;
45
46
47
48
49
50
51
52
53
54
55 public class DependencyWaiterApplicationContextExecutor implements OsgiBundleApplicationContextExecutor,
56 ContextExecutorAccessor {
57
58 private static final Log log = LogFactory.getLog(DependencyWaiterApplicationContextExecutor.class);
59
60
61
62
63
64 private final Object monitor = new Object();
65
66
67 private long timeout;
68
69
70
71 private Timer watchdog;
72
73
74 private TimerTask watchdogTask;
75
76
77 protected DependencyServiceManager dependencyDetector;
78
79 protected final DelegatedExecutionOsgiBundleApplicationContext delegateContext;
80
81
82 private ContextState state = ContextState.INITIALIZED;
83
84 private TaskExecutor taskExecutor;
85
86
87
88
89 private Counter monitorCounter;
90
91
92 private final boolean synchronousWait;
93
94
95 private final Counter waitBarrier = new Counter("syncCounterWait");
96
97
98 private OsgiBundleApplicationContextEventMulticaster delegatedMulticaster;
99
100 private List<OsgiServiceDependencyFactory> dependencyFactories;
101
102
103
104
105
106
107 private class WatchDogTask extends TimerTask {
108
109 public void run() {
110 timeout();
111 }
112 }
113
114
115
116
117
118
119
120
121 private class CompleteRefreshTask implements Runnable {
122
123 public void run() {
124 boolean debug = log.isDebugEnabled();
125 if (debug) {
126 log.debug("Completing refresh for " + getDisplayName());
127 }
128
129 synchronized (monitor) {
130 if (state != ContextState.DEPENDENCIES_RESOLVED) {
131 logWrongState(ContextState.DEPENDENCIES_RESOLVED);
132 return;
133 }
134 }
135
136
137 try {
138 delegateContext.completeRefresh();
139 } catch (Throwable th) {
140 fail(th, true);
141 }
142
143
144 synchronized (monitor) {
145
146 if (state != ContextState.DEPENDENCIES_RESOLVED) {
147 return;
148 }
149 state = ContextState.STARTED;
150 }
151 }
152 }
153
154 public DependencyWaiterApplicationContextExecutor(DelegatedExecutionOsgiBundleApplicationContext delegateContext,
155 boolean syncWait, List<OsgiServiceDependencyFactory> dependencyFactories) {
156 this.delegateContext = delegateContext;
157 this.delegateContext.setExecutor(this);
158 this.synchronousWait = syncWait;
159 this.dependencyFactories = dependencyFactories;
160
161 synchronized (monitor) {
162 watchdogTask = new WatchDogTask();
163 }
164 }
165
166
167
168
169
170 public void refresh() throws BeansException, IllegalStateException {
171 if (log.isDebugEnabled())
172 log.debug("Starting first stage of refresh for " + getDisplayName());
173
174
175 init();
176
177
178 stageOne();
179 }
180
181
182
183
184 protected void init() {
185 synchronized (monitor) {
186 Assert.notNull(watchdog, "watchdog timer required");
187 Assert.notNull(monitorCounter, " monitorCounter required");
188 if (state != ContextState.INTERRUPTED && state != ContextState.STOPPED)
189 state = ContextState.INITIALIZED;
190 else {
191 RuntimeException ex = new IllegalStateException("cannot refresh an interrupted/closed context");
192 log.fatal(ex);
193 throw ex;
194 }
195 }
196 }
197
198
199
200
201
202
203
204 protected void stageOne() {
205
206 boolean debug = log.isDebugEnabled();
207
208 boolean skipExceptionEvent = true;
209
210 try {
211 if (debug)
212 log.debug("Calling preRefresh on " + getDisplayName());
213
214 synchronized (monitor) {
215
216
217 if (state != ContextState.INITIALIZED) {
218 logWrongState(ContextState.INITIALIZED);
219 return;
220 }
221
222 state = ContextState.RESOLVING_DEPENDENCIES;
223 }
224
225 delegateContext.startRefresh();
226
227 if (debug)
228 log.debug("Pre-refresh completed; determining dependencies...");
229
230 Runnable task = null;
231
232 if (synchronousWait) {
233 task = new Runnable() {
234
235 public void run() {
236
237 waitBarrier.decrement();
238 }
239 };
240 } else
241 task = new Runnable() {
242
243 public void run() {
244
245 stageTwo();
246 }
247 };
248
249 skipExceptionEvent = false;
250
251 DependencyServiceManager dl = createDependencyServiceListener(task);
252 dl.findServiceDependencies();
253
254 skipExceptionEvent = true;
255
256
257 if (dl.isSatisfied()) {
258 log.info("No outstanding OSGi service dependencies, completing initialization for " + getDisplayName());
259 stageTwo();
260 } else {
261
262
263 synchronized (monitor) {
264 dependencyDetector = dl;
265 }
266
267 if (debug)
268 log.debug("Registering service dependency dependencyDetector for " + getDisplayName());
269
270 dependencyDetector.register();
271
272 if (synchronousWait) {
273 waitBarrier.increment();
274 if (debug)
275 log.debug("Synchronous wait-for-dependencies; waiting...");
276
277
278 if (waitBarrier.waitForZero(timeout)) {
279 timeout();
280 } else
281 stageTwo();
282 } else {
283
284 startWatchDog();
285 }
286 }
287 } catch (Throwable e) {
288 fail(e, skipExceptionEvent);
289 }
290
291 }
292
293 protected void stageTwo() {
294 boolean debug = log.isDebugEnabled();
295
296 if (debug)
297 log.debug("Starting stage two for " + getDisplayName());
298
299 synchronized (monitor) {
300
301 if (state != ContextState.RESOLVING_DEPENDENCIES) {
302 logWrongState(ContextState.RESOLVING_DEPENDENCIES);
303 return;
304 }
305
306 stopWatchDog();
307 state = ContextState.DEPENDENCIES_RESOLVED;
308 }
309
310
311
312 taskExecutor.execute(new CompleteRefreshTask());
313 }
314
315
316
317
318
319 public void close() {
320 boolean debug = log.isDebugEnabled();
321
322 boolean normalShutdown = false;
323 stopWatchDog();
324
325 synchronized (monitor) {
326
327
328 if (state.isDown()) {
329 return;
330 }
331
332 if (debug) {
333 log.debug("Closing appCtx for " + getDisplayName());
334 }
335
336
337
338
339
340
341
342
343 if (state == ContextState.RESOLVING_DEPENDENCIES) {
344 if (debug)
345 log.debug("Cleaning up appCtx " + getDisplayName());
346 if (delegateContext.isActive()) {
347 try {
348 delegateContext.getBeanFactory().destroySingletons();
349 } catch (Exception ex) {
350 log.trace("Caught exception while interrupting context refresh ", ex);
351 }
352 state = ContextState.INTERRUPTED;
353 }
354 }
355
356
357 else if (state == ContextState.DEPENDENCIES_RESOLVED) {
358 if (debug)
359 log.debug("Shutting down appCtx " + getDisplayName() + " once stageTwo() is complete");
360 state = ContextState.STOPPED;
361 normalShutdown = true;
362 }
363
364 else if (state == ContextState.STARTED) {
365 if (debug)
366 log.debug("Shutting down normally appCtx " + getDisplayName());
367 state = ContextState.STOPPED;
368 normalShutdown = true;
369 }
370
371 else {
372 if (debug)
373 log.debug("No need to stop context (it hasn't been started yet)");
374 state = ContextState.INTERRUPTED;
375 }
376
377 if (dependencyDetector != null) {
378 dependencyDetector.deregister();
379 }
380 }
381 try {
382 if (normalShutdown) {
383 delegateContext.normalClose();
384 }
385 } catch (Exception ex) {
386 log.fatal("Could not succesfully close context " + delegateContext, ex);
387 } finally {
388 monitorCounter.decrement();
389 }
390
391 }
392
393 public void fail(Throwable t) {
394 fail(t, false);
395 }
396
397
398
399
400
401
402
403
404
405 private void fail(Throwable t, boolean skipEvent) {
406
407
408 close();
409
410 StringBuilder buf = new StringBuilder();
411
412 synchronized (monitor) {
413 if (dependencyDetector == null || dependencyDetector.getUnsatisfiedDependencies().isEmpty()) {
414 buf.append("none");
415 } else {
416 for (Iterator<MandatoryServiceDependency> iterator =
417 dependencyDetector.getUnsatisfiedDependencies().keySet().iterator(); iterator.hasNext();) {
418 MandatoryServiceDependency dependency = iterator.next();
419 buf.append(dependency.toString());
420 if (iterator.hasNext()) {
421 buf.append(", ");
422 }
423 }
424 }
425 }
426
427 final StringBuilder message = new StringBuilder();
428 message.append("Unable to create application context for [");
429 if (System.getSecurityManager() != null) {
430 AccessController.doPrivileged(new PrivilegedAction<Object>() {
431 public Object run() {
432 message.append(OsgiStringUtils.nullSafeSymbolicName(getBundle()));
433 return null;
434 }
435 });
436 } else {
437 message.append(OsgiStringUtils.nullSafeSymbolicName(getBundle()));
438 }
439
440 message.append("], unsatisfied dependencies: ");
441 message.append(buf.toString());
442
443 log.error(message.toString(), t);
444
445
446 if (!skipEvent) {
447 delegatedMulticaster.multicastEvent(new OsgiBundleContextFailedEvent(delegateContext, delegateContext
448 .getBundle(), t));
449 }
450 }
451
452
453
454
455 private void timeout() {
456 ApplicationContextException e;
457 List<OsgiServiceDependencyEvent> events = null;
458 String filterAsString = null;
459
460 synchronized (monitor) {
461
462
463
464 if (dependencyDetector != null) {
465 dependencyDetector.deregister();
466 events = dependencyDetector.getUnsatisfiedDependenciesAsEvents();
467 filterAsString = dependencyDetector.createUnsatisfiedDependencyFilter();
468 }
469 }
470
471 Filter filter = (filterAsString != null ? OsgiFilterUtils.createFilter(filterAsString) : null);
472
473 log.warn("Timeout occurred before finding service dependencies for [" + delegateContext.getDisplayName() + "]");
474
475 String bundleName = null;
476 if (System.getSecurityManager() != null) {
477 bundleName = AccessController.doPrivileged(new PrivilegedAction<String>() {
478 public String run() {
479 return OsgiStringUtils.nullSafeSymbolicName(getBundle());
480 }
481 });
482 } else {
483 bundleName = OsgiStringUtils.nullSafeSymbolicName(getBundle());
484 }
485
486
487 e =
488 new ApplicationContextException("Application context " + "initialization for '" + bundleName
489 + "' has timed out waiting for " + filterAsString);
490 e.fillInStackTrace();
491
492
493 delegatedMulticaster.multicastEvent(new BootstrappingDependenciesFailedEvent(delegateContext, delegateContext
494 .getBundle(), e, events, filter));
495
496 fail(e, true);
497 }
498
499 protected DependencyServiceManager createDependencyServiceListener(Runnable task) {
500 return new DependencyServiceManager(this, delegateContext, dependencyFactories, task, timeout);
501 }
502
503
504
505
506 protected void startWatchDog() {
507 boolean started = false;
508 synchronized (monitor) {
509 if (watchdogTask != null) {
510 started = true;
511 watchdog.schedule(watchdogTask, timeout);
512 }
513 }
514
515 boolean debug = log.isDebugEnabled();
516 if (debug) {
517 if (started)
518 log.debug("Asynch wait-for-dependencies started...");
519 else
520 log.debug("Dependencies satisfied; no need to start a watchdog...");
521 }
522 }
523
524 protected void stopWatchDog() {
525 boolean stopped = false;
526 synchronized (monitor) {
527 if (watchdogTask != null) {
528 watchdogTask.cancel();
529 watchdogTask = null;
530 stopped = true;
531 }
532 }
533
534 if (stopped && log.isDebugEnabled()) {
535 log.debug("Cancelled dependency watchdog...");
536 }
537 }
538
539
540
541
542
543
544 public void setTimeout(long timeout) {
545 synchronized (monitor) {
546 this.timeout = timeout;
547 }
548 }
549
550 public void setTaskExecutor(TaskExecutor taskExec) {
551 synchronized (monitor) {
552 this.taskExecutor = taskExec;
553 }
554 }
555
556 private Bundle getBundle() {
557 synchronized (monitor) {
558 return delegateContext.getBundle();
559 }
560 }
561
562 private String getDisplayName() {
563 synchronized (monitor) {
564 return delegateContext.getDisplayName();
565 }
566
567 }
568
569 public void setWatchdog(Timer watchdog) {
570 synchronized (monitor) {
571 this.watchdog = watchdog;
572 }
573 }
574
575
576
577
578
579
580 private void logWrongState(ContextState expected) {
581 log.error("Expecting state (" + expected + ") not (" + state + ") for context [" + getDisplayName()
582 + "]; assuming an interruption and bailing out");
583 }
584
585
586
587
588
589
590 public void setMonitoringCounter(Counter contextsStarted) {
591 this.monitorCounter = contextsStarted;
592 }
593
594
595
596
597
598
599 public void setDelegatedMulticaster(OsgiBundleApplicationContextEventMulticaster multicaster) {
600 this.delegatedMulticaster = multicaster;
601 }
602
603
604
605
606
607 public ContextState getContextState() {
608 synchronized (monitor) {
609 return state;
610 }
611 }
612
613 public OsgiBundleApplicationContextEventMulticaster getEventMulticaster() {
614 return this.delegatedMulticaster;
615 }
616 }