1 package org.springframework.osgi.extender.internal.dependencies.startup;
2
3 import java.security.AccessControlContext;
4 import java.security.AccessController;
5 import java.security.PrivilegedAction;
6 import java.security.PrivilegedExceptionAction;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.Collections;
10 import java.util.Iterator;
11 import java.util.LinkedHashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15
16 import org.apache.commons.logging.Log;
17 import org.apache.commons.logging.LogFactory;
18 import org.osgi.framework.BundleContext;
19 import org.osgi.framework.Filter;
20 import org.osgi.framework.ServiceEvent;
21 import org.osgi.framework.ServiceListener;
22 import org.osgi.framework.ServiceReference;
23 import org.springframework.beans.factory.BeanFactoryUtils;
24 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
25 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
26 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
27 import org.springframework.osgi.context.DelegatedExecutionOsgiBundleApplicationContext;
28 import org.springframework.osgi.context.event.OsgiBundleApplicationContextEvent;
29 import org.springframework.osgi.extender.OsgiServiceDependencyFactory;
30 import org.springframework.osgi.extender.event.BootstrappingDependenciesEvent;
31 import org.springframework.osgi.extender.event.BootstrappingDependencyEvent;
32 import org.springframework.osgi.extender.internal.util.PrivilegedUtils;
33 import org.springframework.osgi.service.importer.OsgiServiceDependency;
34 import org.springframework.osgi.service.importer.event.OsgiServiceDependencyEvent;
35 import org.springframework.osgi.service.importer.event.OsgiServiceDependencyWaitEndedEvent;
36 import org.springframework.osgi.service.importer.event.OsgiServiceDependencyWaitStartingEvent;
37 import org.springframework.osgi.util.OsgiFilterUtils;
38 import org.springframework.osgi.util.OsgiListenerUtils;
39 import org.springframework.osgi.util.OsgiStringUtils;
40
41
42
43
44
45
46
47
48
49 public class DependencyServiceManager {
50
51 private static final Log log = LogFactory.getLog(DependencyServiceManager.class);
52
53 protected final Map<MandatoryServiceDependency, String> dependencies =
54 Collections.synchronizedMap(new LinkedHashMap<MandatoryServiceDependency, String>());
55
56 protected final Map<MandatoryServiceDependency, String> unsatisfiedDependencies =
57 Collections.synchronizedMap(new LinkedHashMap<MandatoryServiceDependency, String>());
58
59 private final ContextExecutorAccessor contextStateAccessor;
60
61 private final BundleContext bundleContext;
62
63 private final ServiceListener listener;
64
65 private final DelegatedExecutionOsgiBundleApplicationContext context;
66
67
68
69
70 private final Runnable executeIfDone;
71
72
73 private final long waitTime;
74
75
76 private List<OsgiServiceDependencyFactory> dependencyFactories;
77
78
79
80
81
82
83
84 private class DependencyServiceListener implements ServiceListener {
85
86
87
88
89
90
91
92 public void serviceChanged(ServiceEvent serviceEvent) {
93 boolean trace = log.isTraceEnabled();
94
95 try {
96 if (unsatisfiedDependencies.isEmpty()) {
97
98
99 if (trace) {
100 log.trace("Handling service event, but no unsatisfied dependencies exist for "
101 + context.getDisplayName());
102 }
103
104 return;
105 }
106
107 ServiceReference ref = serviceEvent.getServiceReference();
108 if (trace) {
109 log.trace("Handling service event [" + OsgiStringUtils.nullSafeToString(serviceEvent) + ":"
110 + OsgiStringUtils.nullSafeToString(ref) + "] for " + context.getDisplayName());
111 }
112
113 updateDependencies(serviceEvent);
114
115 ContextState state = contextStateAccessor.getContextState();
116
117
118 if (state.isResolved()) {
119 deregister();
120 return;
121 }
122
123
124 if (unsatisfiedDependencies.isEmpty()) {
125 deregister();
126
127 log.info("No unsatisfied OSGi service dependencies; completing initialization for "
128 + context.getDisplayName());
129
130
131
132
133
134 executeIfDone.run();
135 }
136 } catch (Throwable th) {
137
138 log.error("Exception during dependency processing for " + context.getDisplayName(), th);
139 contextStateAccessor.fail(th);
140 }
141 }
142
143 private void updateDependencies(ServiceEvent serviceEvent) {
144 boolean trace = log.isTraceEnabled();
145 boolean debug = log.isDebugEnabled();
146
147 String referenceToString = null;
148 String contextToString = null;
149
150 if (debug) {
151 referenceToString = OsgiStringUtils.nullSafeToString(serviceEvent.getServiceReference());
152 contextToString = context.getDisplayName();
153 }
154
155 for (MandatoryServiceDependency dependency : dependencies.keySet()) {
156
157 if (dependency.matches(serviceEvent)) {
158 if (trace) {
159 log.trace(dependency + " matched: " + referenceToString);
160 }
161
162 switch (serviceEvent.getType()) {
163
164 case ServiceEvent.REGISTERED:
165 case ServiceEvent.MODIFIED:
166 dependency.increment();
167 if (unsatisfiedDependencies.remove(dependency) != null) {
168 if (debug) {
169 log.debug("Registered dependency for " + contextToString + "; eliminating "
170 + dependency + ", remaining [" + unsatisfiedDependencies + "]");
171 }
172
173 sendDependencySatisfiedEvent(dependency);
174 sendBootstrappingDependenciesEvent(unsatisfiedDependencies.keySet());
175 } else {
176 if (debug) {
177 log.debug("Increasing the number of matching services for " + contextToString + "; "
178 + dependency + ", remaining [" + unsatisfiedDependencies + "]");
179 }
180 }
181
182 break;
183
184 case ServiceEvent.UNREGISTERING:
185 int count = dependency.decrement();
186 if (count == 0) {
187 unsatisfiedDependencies.put(dependency, dependency.getBeanName());
188 if (debug) {
189 log.debug("Unregistered dependency for " + contextToString + " adding " + dependency
190 + "; total unsatisfied [" + unsatisfiedDependencies + "]");
191 }
192
193 sendDependencyUnsatisfiedEvent(dependency);
194 sendBootstrappingDependenciesEvent(unsatisfiedDependencies.keySet());
195 } else {
196 if (debug) {
197 log.debug("Decreasing the number of matching services for " + contextToString + "; "
198 + dependency + " still has " + count + " matches left");
199 }
200 }
201 break;
202 default:
203 if (debug) {
204 log.debug("Unknown service event type for: " + dependency);
205 }
206 break;
207 }
208 } else {
209 if (trace) {
210 log.trace(dependency + " does not match: " + referenceToString);
211 }
212 }
213 }
214 }
215 }
216
217
218
219
220
221
222
223
224
225 public DependencyServiceManager(ContextExecutorAccessor executor,
226 DelegatedExecutionOsgiBundleApplicationContext context,
227 List<OsgiServiceDependencyFactory> dependencyFactories, Runnable executeIfDone, long maxWaitTime) {
228 this.contextStateAccessor = executor;
229 this.context = context;
230 this.dependencyFactories = new ArrayList<OsgiServiceDependencyFactory>(8);
231
232 if (dependencyFactories != null)
233 this.dependencyFactories.addAll(dependencyFactories);
234
235 this.waitTime = maxWaitTime;
236 this.bundleContext = context.getBundleContext();
237 this.listener = new DependencyServiceListener();
238
239 this.executeIfDone = executeIfDone;
240 }
241
242 protected void findServiceDependencies() throws Exception {
243 try {
244 if (System.getSecurityManager() != null) {
245 final AccessControlContext acc = getAcc();
246
247 PrivilegedUtils.executeWithCustomTCCL(context.getClassLoader(),
248 new PrivilegedUtils.UnprivilegedThrowableExecution<Object>() {
249 public Object run() throws Throwable {
250 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
251 public Object run() throws Exception {
252 doFindDependencies();
253 return null;
254 }
255 }, acc);
256 return null;
257 }
258 });
259 } else {
260 doFindDependencies();
261 }
262 } catch (Throwable th) {
263 if (th instanceof Exception)
264 throw ((Exception) th);
265 throw (Error) th;
266 }
267
268 if (log.isDebugEnabled()) {
269 log.debug(dependencies.size() + " OSGi service dependencies, " + unsatisfiedDependencies.size()
270 + " unsatisfied (for beans " + unsatisfiedDependencies.values() + ") in "
271 + context.getDisplayName());
272 }
273
274 if (!unsatisfiedDependencies.isEmpty()) {
275 log.info(context.getDisplayName() + " is waiting for unsatisfied dependencies ["
276 + unsatisfiedDependencies.values() + "]");
277 }
278 if (log.isTraceEnabled()) {
279 log.trace("Total OSGi service dependencies beans " + dependencies.values());
280 log.trace("Unsatified OSGi service dependencies beans " + unsatisfiedDependencies.values());
281 }
282 }
283
284 private void doFindDependencies() throws Exception {
285 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
286 boolean debug = log.isDebugEnabled();
287 boolean trace = log.isTraceEnabled();
288
289 if (trace)
290 log.trace("Looking for dependency factories inside bean factory [" + beanFactory.toString() + "]");
291
292 Map<String, OsgiServiceDependencyFactory> localFactories =
293 BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, OsgiServiceDependencyFactory.class, true,
294 false);
295
296 if (trace)
297 log.trace("Discovered local dependency factories: " + localFactories.keySet());
298
299 dependencyFactories.addAll(localFactories.values());
300
301 for (Iterator<OsgiServiceDependencyFactory> iterator = dependencyFactories.iterator(); iterator.hasNext();) {
302 OsgiServiceDependencyFactory dependencyFactory = iterator.next();
303 Collection<OsgiServiceDependency> discoveredDependencies = null;
304
305 if (trace) {
306 log.trace("Interogating dependency factory " + dependencyFactory);
307 }
308 try {
309 discoveredDependencies = dependencyFactory.getServiceDependencies(bundleContext, beanFactory);
310 } catch (Exception ex) {
311 log.warn("Dependency factory " + dependencyFactory
312 + " threw exception while detecting dependencies for beanFactory " + beanFactory + " in "
313 + context.getDisplayName(), ex);
314 throw ex;
315 }
316
317 if (discoveredDependencies != null)
318 for (OsgiServiceDependency dependency : discoveredDependencies) {
319 if (dependency.isMandatory()) {
320 MandatoryServiceDependency msd = new MandatoryServiceDependency(bundleContext, dependency);
321 dependencies.put(msd, dependency.getBeanName());
322
323 if (!msd.isServicePresent()) {
324 log.info("Adding OSGi service dependency for importer [" + msd.getBeanName()
325 + "] matching OSGi filter [" + msd.filterAsString + "]");
326 unsatisfiedDependencies.put(msd, dependency.getBeanName());
327 } else {
328 if (debug)
329 log.debug("OSGi service dependency for importer [" + msd.getBeanName()
330 + "] is already satisfied");
331 }
332 }
333 }
334 }
335 }
336
337 protected boolean isSatisfied() {
338 return unsatisfiedDependencies.isEmpty();
339 }
340
341 public Map<MandatoryServiceDependency, String> getUnsatisfiedDependencies() {
342 return unsatisfiedDependencies;
343 }
344
345 protected void register() {
346 final String filter = createDependencyFilter();
347 if (log.isDebugEnabled()) {
348 log.debug(context.getDisplayName() + " has registered service dependency dependencyDetector with filter: "
349 + filter);
350 }
351
352
353 sendInitialBootstrappingEvents(unsatisfiedDependencies.keySet());
354
355 if (System.getSecurityManager() != null) {
356 AccessControlContext acc = getAcc();
357 AccessController.doPrivileged(new PrivilegedAction<Object>() {
358 public Object run() {
359 OsgiListenerUtils.addServiceListener(bundleContext, listener, filter);
360 return null;
361 }
362 }, acc);
363 } else {
364 OsgiListenerUtils.addServiceListener(bundleContext, listener, filter);
365 }
366 }
367
368
369
370
371
372
373
374 private String createDependencyFilter() {
375 return createDependencyFilter(dependencies.keySet());
376 }
377
378 String createUnsatisfiedDependencyFilter() {
379 return createDependencyFilter(unsatisfiedDependencies.keySet());
380 }
381
382 private String createDependencyFilter(Collection<MandatoryServiceDependency> dependencies) {
383 if (dependencies.isEmpty()) {
384 return null;
385 }
386
387 boolean multiple = dependencies.size() > 1;
388 StringBuilder sb = new StringBuilder(dependencies.size() << 7);
389 if (multiple) {
390 sb.append("(|");
391 }
392 for (MandatoryServiceDependency dependency : dependencies) {
393 sb.append(dependency.filterAsString);
394 }
395 if (multiple) {
396 sb.append(')');
397 }
398
399 String filter = sb.toString();
400
401 return filter;
402 }
403
404 protected void deregister() {
405 if (log.isDebugEnabled()) {
406 log.debug("Deregistering service dependency dependencyDetector for " + context.getDisplayName());
407 }
408
409 OsgiListenerUtils.removeServiceListener(bundleContext, listener);
410 }
411
412 List<OsgiServiceDependencyEvent> getUnsatisfiedDependenciesAsEvents() {
413 return getUnsatisfiedDependenciesAsEvents(unsatisfiedDependencies.keySet());
414 }
415
416 private List<OsgiServiceDependencyEvent> getUnsatisfiedDependenciesAsEvents(
417 Collection<MandatoryServiceDependency> deps) {
418 List<OsgiServiceDependencyEvent> dependencies = new ArrayList<OsgiServiceDependencyEvent>(deps.size());
419
420 for (MandatoryServiceDependency entry : deps) {
421 OsgiServiceDependencyEvent nestedEvent =
422 new OsgiServiceDependencyWaitStartingEvent(context, entry.getServiceDependency(), waitTime);
423 dependencies.add(nestedEvent);
424 }
425
426 return Collections.unmodifiableList(dependencies);
427
428 }
429
430
431 private void sendDependencyUnsatisfiedEvent(MandatoryServiceDependency dependency) {
432 OsgiServiceDependencyEvent nestedEvent =
433 new OsgiServiceDependencyWaitStartingEvent(context, dependency.getServiceDependency(), waitTime);
434 BootstrappingDependencyEvent dependencyEvent =
435 new BootstrappingDependencyEvent(context, context.getBundle(), nestedEvent);
436 publishEvent(dependencyEvent);
437 }
438
439 private void sendDependencySatisfiedEvent(MandatoryServiceDependency dependency) {
440 OsgiServiceDependencyEvent nestedEvent =
441 new OsgiServiceDependencyWaitEndedEvent(context, dependency.getServiceDependency(), waitTime);
442 BootstrappingDependencyEvent dependencyEvent =
443 new BootstrappingDependencyEvent(context, context.getBundle(), nestedEvent);
444 publishEvent(dependencyEvent);
445 }
446
447 private void sendInitialBootstrappingEvents(Set<MandatoryServiceDependency> deps) {
448
449 List<OsgiServiceDependencyEvent> events = getUnsatisfiedDependenciesAsEvents(deps);
450 for (OsgiServiceDependencyEvent nestedEvent : events) {
451 BootstrappingDependencyEvent dependencyEvent =
452 new BootstrappingDependencyEvent(context, context.getBundle(), nestedEvent);
453 publishEvent(dependencyEvent);
454 }
455
456
457 String filterAsString = createDependencyFilter(deps);
458 Filter filter = (filterAsString != null ? OsgiFilterUtils.createFilter(filterAsString) : null);
459 BootstrappingDependenciesEvent event =
460 new BootstrappingDependenciesEvent(context, context.getBundle(), events, filter, waitTime);
461
462 publishEvent(event);
463 }
464
465 private void sendBootstrappingDependenciesEvent(Set<MandatoryServiceDependency> deps) {
466 List<OsgiServiceDependencyEvent> events = getUnsatisfiedDependenciesAsEvents(deps);
467 String filterAsString = createDependencyFilter(deps);
468 Filter filter = (filterAsString != null ? OsgiFilterUtils.createFilter(filterAsString) : null);
469 BootstrappingDependenciesEvent event =
470 new BootstrappingDependenciesEvent(context, context.getBundle(), events, filter, waitTime);
471
472 publishEvent(event);
473 }
474
475 private void publishEvent(OsgiBundleApplicationContextEvent dependencyEvent) {
476 this.contextStateAccessor.getEventMulticaster().multicastEvent(dependencyEvent);
477 }
478
479 private AccessControlContext getAcc() {
480 AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
481 if (beanFactory instanceof ConfigurableBeanFactory) {
482 return ((ConfigurableBeanFactory) beanFactory).getAccessControlContext();
483 }
484 return null;
485 }
486 }