1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.osgi.context.support;
18
19 import java.beans.PropertyEditor;
20 import java.io.IOException;
21 import java.util.Dictionary;
22 import java.util.Map;
23
24 import org.osgi.framework.Bundle;
25 import org.osgi.framework.BundleContext;
26 import org.osgi.framework.Constants;
27 import org.osgi.framework.ServiceRegistration;
28 import org.springframework.beans.BeanUtils;
29 import org.springframework.beans.BeansException;
30 import org.springframework.beans.factory.BeanFactoryAware;
31 import org.springframework.beans.factory.config.BeanPostProcessor;
32 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
33 import org.springframework.beans.factory.config.Scope;
34 import org.springframework.context.ApplicationContext;
35 import org.springframework.context.ApplicationContextException;
36 import org.springframework.context.support.AbstractRefreshableApplicationContext;
37 import org.springframework.core.io.Resource;
38 import org.springframework.core.io.support.ResourcePatternResolver;
39 import org.springframework.osgi.context.BundleContextAware;
40 import org.springframework.osgi.context.ConfigurableOsgiBundleApplicationContext;
41 import org.springframework.osgi.context.internal.classloader.ClassLoaderFactory;
42 import org.springframework.osgi.context.support.internal.OsgiBundleScope;
43 import org.springframework.osgi.io.OsgiBundleResource;
44 import org.springframework.osgi.io.OsgiBundleResourcePatternResolver;
45 import org.springframework.osgi.util.OsgiBundleUtils;
46 import org.springframework.osgi.util.OsgiServiceUtils;
47 import org.springframework.osgi.util.OsgiStringUtils;
48 import org.springframework.osgi.util.internal.MapBasedDictionary;
49 import org.springframework.util.Assert;
50 import org.springframework.util.ClassUtils;
51 import org.springframework.util.ObjectUtils;
52 import org.springframework.util.StringUtils;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 public abstract class AbstractOsgiBundleApplicationContext extends AbstractRefreshableApplicationContext implements
96 ConfigurableOsgiBundleApplicationContext {
97
98 private static final String EXPORTER_IMPORTER_DEPENDENCY_MANAGER = "org.springframework.osgi.service.dependency.internal.MandatoryDependencyBeanPostProcessor";
99
100
101 private Bundle bundle;
102
103
104 private BundleContext bundleContext;
105
106
107 private String[] configLocations;
108
109
110 private ServiceRegistration serviceRegistration;
111
112
113 private boolean publishContextAsService = true;
114
115
116 private ClassLoader classLoader;
117
118
119
120
121
122
123 private ResourcePatternResolver osgiPatternResolver;
124
125
126
127
128
129
130 public AbstractOsgiBundleApplicationContext() {
131 super();
132 setDisplayName("Root OsgiBundleApplicationContext");
133 }
134
135
136
137
138
139
140
141 public AbstractOsgiBundleApplicationContext(ApplicationContext parent) {
142 super(parent);
143 }
144
145
146
147
148
149
150
151
152
153 public void setBundleContext(BundleContext bundleContext) {
154 this.bundleContext = bundleContext;
155 this.bundle = bundleContext.getBundle();
156 this.osgiPatternResolver = createResourcePatternResolver();
157
158 if (getClassLoader() == null)
159 this.setClassLoader(createBundleClassLoader(this.bundle));
160
161 this.setDisplayName(ClassUtils.getShortName(getClass()) + "(bundle=" + getBundleSymbolicName() + ", config="
162 + StringUtils.arrayToCommaDelimitedString(getConfigLocations()) + ")");
163 }
164
165 public BundleContext getBundleContext() {
166 return this.bundleContext;
167 }
168
169 public Bundle getBundle() {
170 return this.bundle;
171 }
172
173 public void setConfigLocations(String[] configLocations) {
174 this.configLocations = configLocations;
175 }
176
177
178
179
180
181
182
183
184
185 public String[] getConfigLocations() {
186 return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
187 }
188
189
190
191
192 protected void doClose() {
193 if (!OsgiServiceUtils.unregisterService(serviceRegistration)) {
194 logger.info("Unpublishing application context OSGi service for bundle "
195 + OsgiStringUtils.nullSafeNameAndSymName(bundle));
196 serviceRegistration = null;
197 }
198 else {
199 if (publishContextAsService)
200 logger.info("Application Context service already unpublished");
201 }
202
203
204 super.doClose();
205 }
206
207
208
209
210 protected void destroyBeans() {
211 super.destroyBeans();
212
213 try {
214 cleanOsgiBundleScope(getBeanFactory());
215 }
216 catch (Exception ex) {
217 logger.warn("got exception when closing", ex);
218 }
219 }
220
221
222
223
224
225
226
227
228
229
230
231 protected String[] getDefaultConfigLocations() {
232 return null;
233 }
234
235 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
236 super.postProcessBeanFactory(beanFactory);
237
238 beanFactory.addBeanPostProcessor(new BundleContextAwareProcessor(this.bundleContext));
239 beanFactory.ignoreDependencyInterface(BundleContextAware.class);
240
241 enforceExporterImporterDependency(beanFactory);
242
243
244 if (!beanFactory.containsLocalBean(BUNDLE_CONTEXT_BEAN_NAME)) {
245 logger.debug("Registering BundleContext as a bean named " + BUNDLE_CONTEXT_BEAN_NAME);
246 beanFactory.registerSingleton(BUNDLE_CONTEXT_BEAN_NAME, this.bundleContext);
247 }
248 else {
249 logger.warn("A bean named " + BUNDLE_CONTEXT_BEAN_NAME
250 + " already exists; the bundleContext will not be registered as a bean");
251 }
252
253
254 registerPropertyEditors(beanFactory);
255
256
257 beanFactory.registerScope(OsgiBundleScope.SCOPE_NAME, new OsgiBundleScope());
258 }
259
260
261
262
263
264
265 private void enforceExporterImporterDependency(ConfigurableListableBeanFactory beanFactory) {
266
267 ClassLoader loader = AbstractOsgiBundleApplicationContext.class.getClassLoader();
268 Object instance = null;
269 try {
270 Class managerClass = loader.loadClass(EXPORTER_IMPORTER_DEPENDENCY_MANAGER);
271 instance = BeanUtils.instantiateClass(managerClass);
272 }
273 catch (ClassNotFoundException cnfe) {
274 throw new ApplicationContextException("Cannot load class " + EXPORTER_IMPORTER_DEPENDENCY_MANAGER, cnfe);
275 }
276
277
278 Assert.isInstanceOf(BeanFactoryAware.class, instance);
279 Assert.isInstanceOf(BeanPostProcessor.class, instance);
280 ((BeanFactoryAware) instance).setBeanFactory(beanFactory);
281 beanFactory.addBeanPostProcessor((BeanPostProcessor) instance);
282 }
283
284
285
286
287
288
289 private void registerPropertyEditors(ConfigurableListableBeanFactory beanFactory) {
290 beanFactory.addPropertyEditorRegistrar(new OsgiPropertyEditorRegistrar());
291 }
292
293 private void cleanOsgiBundleScope(ConfigurableListableBeanFactory beanFactory) {
294 Scope scope = beanFactory.getRegisteredScope(OsgiBundleScope.SCOPE_NAME);
295 if (scope != null && scope instanceof OsgiBundleScope) {
296 if (logger.isDebugEnabled())
297 logger.debug("Destroying existing bundle scope beans...");
298 ((OsgiBundleScope) scope).destroy();
299 }
300 }
301
302
303
304
305
306
307
308 void publishContextAsOsgiServiceIfNecessary() {
309 if (publishContextAsService) {
310 Dictionary serviceProperties = new MapBasedDictionary();
311
312 customizeApplicationContextServiceProperties((Map) serviceProperties);
313
314 if (logger.isInfoEnabled()) {
315 logger.info("Publishing application context as OSGi service with properties " + serviceProperties);
316 }
317
318
319 Class[] classes = org.springframework.osgi.util.internal.ClassUtils.getClassHierarchy(getClass(),
320 org.springframework.osgi.util.internal.ClassUtils.INCLUDE_INTERFACES);
321
322
323 Class[] filterClasses = org.springframework.osgi.util.internal.ClassUtils.getVisibleClasses(classes,
324 this.getClass().getClassLoader());
325
326 String[] serviceNames = org.springframework.osgi.util.internal.ClassUtils.toStringArray(filterClasses);
327
328 if (logger.isDebugEnabled())
329 logger.debug("Publishing service under classes " + ObjectUtils.nullSafeToString(serviceNames));
330
331
332 this.serviceRegistration = getBundleContext().registerService(serviceNames, this, serviceProperties);
333 }
334 else {
335 if (logger.isInfoEnabled()) {
336 logger.info("Not publishing application context OSGi service for bundle "
337 + OsgiStringUtils.nullSafeNameAndSymName(bundle));
338 }
339 }
340 }
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 protected void customizeApplicationContextServiceProperties(Map serviceProperties) {
360 serviceProperties.put(APPLICATION_CONTEXT_SERVICE_PROPERTY_NAME, getBundleSymbolicName());
361 serviceProperties.put(Constants.BUNDLE_SYMBOLICNAME, getBundleSymbolicName());
362 serviceProperties.put(Constants.BUNDLE_VERSION, OsgiBundleUtils.getBundleVersion(bundle));
363 }
364
365 private String getBundleSymbolicName() {
366 return OsgiStringUtils.nullSafeSymbolicName(getBundle());
367 }
368
369
370
371
372
373
374 protected ResourcePatternResolver createResourcePatternResolver() {
375 return new OsgiBundleResourcePatternResolver(getBundle());
376 }
377
378
379
380
381
382
383 protected ResourcePatternResolver getResourcePatternResolver() {
384 return osgiPatternResolver;
385 }
386
387
388
389 public ClassLoader getClassLoader() {
390 return classLoader;
391 }
392
393 public Resource getResource(String location) {
394 return (osgiPatternResolver != null ? osgiPatternResolver.getResource(location) : null);
395 }
396
397 public Resource[] getResources(String locationPattern) throws IOException {
398 return (osgiPatternResolver != null ? osgiPatternResolver.getResources(locationPattern) : null);
399 }
400
401 public void setClassLoader(ClassLoader classLoader) {
402 this.classLoader = classLoader;
403 }
404
405 protected Resource getResourceByPath(String path) {
406 Assert.notNull(path, "Path is required");
407 return new OsgiBundleResource(this.bundle, path);
408 }
409
410 public void setPublishContextAsService(boolean publishContextAsService) {
411 this.publishContextAsService = publishContextAsService;
412 }
413
414
415
416
417
418
419
420 private ClassLoader createBundleClassLoader(Bundle bundle) {
421 return ClassLoaderFactory.getBundleClassLoaderFor(bundle);
422 }
423 }