1 package com.atlassian.plugin.osgi.container.felix;
2
3 import com.atlassian.plugin.event.PluginEventListener;
4 import com.atlassian.plugin.event.PluginEventManager;
5 import com.atlassian.plugin.event.events.PluginFrameworkShutdownEvent;
6 import com.atlassian.plugin.event.events.PluginFrameworkStartingEvent;
7 import com.atlassian.plugin.event.events.PluginFrameworkWarmRestartingEvent;
8 import com.atlassian.plugin.event.events.PluginUninstalledEvent;
9 import com.atlassian.plugin.event.events.PluginUpgradedEvent;
10 import com.atlassian.plugin.osgi.container.OsgiContainerException;
11 import com.atlassian.plugin.osgi.container.OsgiContainerManager;
12 import com.atlassian.plugin.osgi.container.OsgiContainerStartedEvent;
13 import com.atlassian.plugin.osgi.container.OsgiContainerStoppedEvent;
14 import com.atlassian.plugin.osgi.container.OsgiPersistentCache;
15 import com.atlassian.plugin.osgi.container.PackageScannerConfiguration;
16 import com.atlassian.plugin.osgi.container.impl.DefaultOsgiPersistentCache;
17 import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
18 import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
19 import com.atlassian.plugin.osgi.hostcomponents.impl.DefaultComponentRegistrar;
20 import com.atlassian.plugin.osgi.util.OsgiHeaderUtil;
21 import com.atlassian.plugin.util.ClassLoaderUtils;
22 import com.atlassian.plugin.util.ContextClassLoaderSwitchingUtil;
23 import com.atlassian.plugin.util.PluginUtils;
24 import com.google.common.annotations.VisibleForTesting;
25 import org.apache.commons.lang.StringUtils;
26 import org.apache.felix.framework.Felix;
27 import org.apache.felix.framework.Logger;
28 import org.apache.felix.framework.cache.BundleCache;
29 import org.apache.felix.framework.util.FelixConstants;
30 import org.apache.felix.framework.util.StringMap;
31 import org.osgi.framework.Bundle;
32 import org.osgi.framework.BundleActivator;
33 import org.osgi.framework.BundleContext;
34 import org.osgi.framework.BundleEvent;
35 import org.osgi.framework.BundleException;
36 import org.osgi.framework.BundleListener;
37 import org.osgi.framework.Constants;
38 import org.osgi.framework.FrameworkEvent;
39 import org.osgi.framework.FrameworkListener;
40 import org.osgi.framework.ServiceReference;
41 import org.osgi.framework.ServiceRegistration;
42 import org.osgi.service.packageadmin.PackageAdmin;
43 import org.osgi.util.tracker.ServiceTracker;
44 import org.osgi.util.tracker.ServiceTrackerCustomizer;
45 import org.slf4j.LoggerFactory;
46
47 import java.io.File;
48 import java.io.FilenameFilter;
49 import java.io.IOException;
50 import java.net.URL;
51 import java.util.ArrayList;
52 import java.util.Collection;
53 import java.util.Collections;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.concurrent.CountDownLatch;
58 import java.util.concurrent.ThreadFactory;
59 import java.util.concurrent.TimeUnit;
60 import java.util.jar.JarFile;
61
62 import static com.google.common.base.Preconditions.checkNotNull;
63
64
65
66
67 public class FelixOsgiContainerManager implements OsgiContainerManager
68 {
69 public static final String OSGI_FRAMEWORK_BUNDLES_ZIP = "osgi-framework-bundles.zip";
70 public static final int REFRESH_TIMEOUT = 10;
71
72 private static final org.slf4j.Logger log = LoggerFactory.getLogger(FelixOsgiContainerManager.class);
73 private static final String OSGI_BOOTDELEGATION = "org.osgi.framework.bootdelegation";
74 private static final String ATLASSIAN_PREFIX = "atlassian.";
75
76 private final OsgiPersistentCache persistentCache;
77 private final URL frameworkBundlesUrl;
78 private final PackageScannerConfiguration packageScannerConfig;
79 private final HostComponentProvider hostComponentProvider;
80 private final List<ServiceTracker> trackers;
81 private final ExportsBuilder exportsBuilder;
82 private final ThreadFactory threadFactory = new ThreadFactory()
83 {
84 public Thread newThread(final Runnable r)
85 {
86 final Thread thread = new Thread(r, "Felix:Startup");
87 thread.setDaemon(true);
88 return thread;
89 }
90 };
91
92 private BundleRegistration registration = null;
93 private Felix felix = null;
94 private boolean felixRunning = false;
95 private boolean disableMultipleBundleVersions = true;
96 private Logger felixLogger;
97 private final PluginEventManager pluginEventManager;
98
99
100
101
102
103
104
105
106
107
108 @Deprecated
109 public FelixOsgiContainerManager(final File frameworkBundlesDir, final PackageScannerConfiguration packageScannerConfig, final HostComponentProvider provider, final PluginEventManager eventManager)
110 {
111 this(ClassLoaderUtils.getResource(OSGI_FRAMEWORK_BUNDLES_ZIP, FelixOsgiContainerManager.class), frameworkBundlesDir, packageScannerConfig,
112 provider, eventManager);
113 }
114
115
116
117
118
119
120
121
122
123
124
125 @Deprecated
126 public FelixOsgiContainerManager(final URL frameworkBundlesZip, final File frameworkBundlesDir, final PackageScannerConfiguration packageScannerConfig, final HostComponentProvider provider, final PluginEventManager eventManager)
127 {
128 this(frameworkBundlesZip, new DefaultOsgiPersistentCache(new File(frameworkBundlesDir.getParentFile(),
129 "osgi-cache")), packageScannerConfig, provider, eventManager);
130 }
131
132
133
134
135
136
137
138
139
140
141 public FelixOsgiContainerManager(final OsgiPersistentCache persistentCache, final PackageScannerConfiguration packageScannerConfig, final HostComponentProvider provider, final PluginEventManager eventManager)
142 {
143 this(ClassLoaderUtils.getResource(OSGI_FRAMEWORK_BUNDLES_ZIP, FelixOsgiContainerManager.class), persistentCache, packageScannerConfig,
144 provider, eventManager);
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159 public FelixOsgiContainerManager(final URL frameworkBundlesZip, OsgiPersistentCache persistentCache,
160 final PackageScannerConfiguration packageScannerConfig,
161 final HostComponentProvider provider, final PluginEventManager eventManager)
162 throws OsgiContainerException
163 {
164 checkNotNull(frameworkBundlesZip, "The framework bundles zip is required");
165 checkNotNull(persistentCache, "The framework bundles directory must not be null");
166 checkNotNull(packageScannerConfig, "The package scanner configuration must not be null");
167 checkNotNull(eventManager, "The plugin event manager is required");
168
169 frameworkBundlesUrl = frameworkBundlesZip;
170 this.packageScannerConfig = packageScannerConfig;
171 this.persistentCache = persistentCache;
172 hostComponentProvider = provider;
173 trackers = Collections.synchronizedList(new ArrayList<ServiceTracker>());
174 this.pluginEventManager = eventManager;
175 eventManager.register(this);
176 felixLogger = new FelixLoggerBridge(log);
177 exportsBuilder = new ExportsBuilder();
178 }
179
180 public void setFelixLogger(final Logger logger)
181 {
182 felixLogger = logger;
183 }
184
185 public void setDisableMultipleBundleVersions(final boolean val)
186 {
187 disableMultipleBundleVersions = val;
188 }
189
190
191
192
193
194
195 public void clearExportCache()
196 {
197 exportsBuilder.clearExportCache();
198 }
199
200 @SuppressWarnings ({ "UnusedDeclaration" })
201 @PluginEventListener
202 public void onStart(final PluginFrameworkStartingEvent event)
203 {
204 start();
205 }
206
207 @SuppressWarnings ({ "UnusedDeclaration" })
208 @PluginEventListener
209 public void onShutdown(final PluginFrameworkShutdownEvent event)
210 {
211 stop();
212 }
213
214 @SuppressWarnings ({ "UnusedDeclaration" })
215 @PluginEventListener
216 public void onPluginUpgrade(PluginUpgradedEvent event)
217 {
218 registration.refreshPackages();
219 }
220
221 @SuppressWarnings ({ "UnusedDeclaration" })
222 @PluginEventListener
223 public void onPluginUninstallation(PluginUninstalledEvent event)
224 {
225 registration.refreshPackages();
226 }
227
228 @SuppressWarnings ({ "UnusedDeclaration" })
229 @PluginEventListener
230 public void onPluginFrameworkWarmRestarting(PluginFrameworkWarmRestartingEvent event)
231 {
232 registration.loadHostComponents(collectHostComponents(hostComponentProvider));
233 }
234
235 public void start() throws OsgiContainerException
236 {
237 if (isRunning())
238 {
239 return;
240 }
241
242 final DefaultComponentRegistrar registrar = collectHostComponents(hostComponentProvider);
243
244 final StringMap configMap = new StringMap();
245
246
247
248 configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, exportsBuilder.getExports(registrar.getRegistry(), packageScannerConfig));
249
250
251 configMap.put(BundleCache.CACHE_ROOTDIR_PROP, persistentCache.getOsgiBundleCache().getAbsolutePath());
252
253 configMap.put(FelixConstants.LOG_LEVEL_PROP, String.valueOf(felixLogger.getLogLevel()));
254 configMap.put(FelixConstants.LOG_LOGGER_PROP, felixLogger);
255 String bootDelegation = getAtlassianSpecificOsgiSystemProperty(OSGI_BOOTDELEGATION);
256 if ((bootDelegation == null) || (bootDelegation.trim().length() == 0))
257 {
258
259
260
261 bootDelegation = "weblogic,weblogic.*," +
262 "META-INF.services," +
263 "com.yourkit,com.yourkit.*," +
264 "com.chronon,com.chronon.*," +
265 "com.jprofiler,com.jprofiler.*," +
266 "org.apache.xerces,org.apache.xerces.*," +
267 "org.apache.xalan,org.apache.xalan.*," +
268 "org.apache.xml.serializer," +
269 "sun.*," +
270 "com.sun.xml.bind.v2," +
271 "com.icl.saxon," +
272 "com_cenqua_clover," +
273 "com.cenqua.clover,com.cenqua.clover.*," +
274 "com.atlassian.clover,com.atlassian.clover.*";
275 }
276
277 configMap.put(FelixConstants.FRAMEWORK_BOOTDELEGATION, bootDelegation);
278 configMap.put(FelixConstants.IMPLICIT_BOOT_DELEGATION_PROP, "false");
279
280 configMap.put(FelixConstants.FRAMEWORK_BUNDLE_PARENT, FelixConstants.FRAMEWORK_BUNDLE_PARENT_FRAMEWORK);
281 if (log.isDebugEnabled())
282 {
283 log.debug("Felix configuration: " + configMap);
284 }
285
286 validateConfiguration(configMap);
287
288 try
289 {
290
291 registration = new BundleRegistration(frameworkBundlesUrl, persistentCache.getFrameworkBundleCache(), registrar);
292 final List<BundleActivator> list = new ArrayList<BundleActivator>();
293 list.add(registration);
294 configMap.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, list);
295
296
297
298 felix = new Felix(configMap);
299
300
301 final Runnable start = new Runnable()
302 {
303 public void run()
304 {
305 try
306 {
307 Thread.currentThread().setContextClassLoader(null);
308 felix.start();
309 felixRunning = true;
310 }
311 catch (final BundleException e)
312 {
313 throw new OsgiContainerException("Unable to start felix", e);
314 }
315 }
316 };
317 final Thread t = threadFactory.newThread(start);
318 t.start();
319
320
321 t.join(10 * 60 * 1000);
322
323 }
324 catch (final Exception ex)
325 {
326 throw new OsgiContainerException("Unable to start OSGi container", ex);
327 }
328 pluginEventManager.broadcast(new OsgiContainerStartedEvent(this));
329 }
330
331
332
333
334
335
336 private void validateConfiguration(StringMap configMap) throws OsgiContainerException
337 {
338 String systemExports = (String) configMap.get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
339
340 String cacheKeySource = StringUtils.join(new Object[] {this.getRuntimeEnvironment(), systemExports }, ',');
341
342 validateCaches(cacheKeySource);
343
344 detectIncorrectOsgiVersion();
345 detectXercesOverride(systemExports);
346 }
347
348
349
350
351
352
353
354
355 void detectXercesOverride(String systemExports) throws OsgiContainerException
356 {
357 int pos = systemExports.indexOf("org.apache.xerces.util");
358 if (pos > -1)
359 {
360 if (pos == 0 || (pos > 0 && systemExports.charAt(pos - 1) == ','))
361 {
362 pos += "org.apache.xerces.util".length();
363
364
365 if (pos >= systemExports.length() || ';' != systemExports.charAt(pos))
366 {
367 throw new OsgiContainerException(
368 "Detected an incompatible version of Apache Xerces on the classpath. If using Tomcat, you may have " +
369 "an old version of Xerces in $TOMCAT_HOME/common/lib/endorsed that will need to be removed.");
370 }
371 }
372 }
373 }
374
375
376
377
378
379
380
381 private void validateCaches(String cacheKeySource)
382 {
383 log.info("Using Felix bundle cacheKey source: {}", cacheKeySource);
384 persistentCache.validate(cacheKeySource);
385 log.debug("Using Felix bundle cache directory: {}", persistentCache.getOsgiBundleCache().getAbsolutePath());
386 }
387
388
389
390
391 private void detectIncorrectOsgiVersion()
392 {
393 try
394 {
395 Bundle.class.getMethod("getBundleContext");
396 }
397 catch (final NoSuchMethodException e)
398 {
399 throw new OsgiContainerException(
400 "Detected older version (4.0 or earlier) of OSGi. If using WebSphere " + "6.1, please enable application-first (parent-last) classloading and the 'Single classloader for " + "application' WAR classloader policy.");
401 }
402 }
403
404 public void stop() throws OsgiContainerException
405 {
406 if (felixRunning)
407 {
408 for (final ServiceTracker tracker : new HashSet<ServiceTracker>(trackers))
409 {
410 tracker.close();
411 }
412 FrameworkListener listener = new FrameworkListener()
413 {
414 @Override
415 public void frameworkEvent(FrameworkEvent event)
416 {
417 if (event.getType() == FrameworkEvent.WAIT_TIMEDOUT)
418 {
419 log.error("Timeout waiting for OSGi to shutdown");
420 threadDump();
421 } else if (event.getType() == FrameworkEvent.STOPPED)
422 {
423 log.info("OSGi shutdown successful");
424 }
425 }
426 };
427 try
428 {
429 felix.getBundleContext().addFrameworkListener(listener);
430 felix.stop();
431 felix.waitForStop(TimeUnit.SECONDS.toMillis(60));
432 }
433 catch (InterruptedException e)
434 {
435 log.warn("Interrupting Felix shutdown", e);
436 }
437 catch (BundleException ex)
438 {
439 log.error("An error occurred while stopping the Felix OSGi Container. ", ex);
440 }
441 }
442
443 felixRunning = false;
444 felix = null;
445 pluginEventManager.broadcast(new OsgiContainerStoppedEvent(this));
446 }
447
448 private void threadDump()
449 {
450 StringBuilder sb = new StringBuilder();
451 String nl = System.getProperty("line.separator");
452 for (Map.Entry<Thread,StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet())
453 {
454 Thread key = entry.getKey();
455 StackTraceElement[] trace = entry.getValue();
456 sb.append(key).append(nl);
457 for (StackTraceElement aTrace : trace)
458 {
459 sb.append(" ").append(aTrace).append(nl);
460 }
461 }
462 log.debug("Thread dump: " + nl + sb.toString());
463 }
464
465 public Bundle[] getBundles()
466 {
467 if (isRunning())
468 {
469 return registration.getBundles();
470 }
471 else
472 {
473 throw new IllegalStateException(
474 "Cannot retrieve the bundles if the Felix container isn't running. Check earlier in the logs for the possible cause as to why Felix didn't start correctly.");
475 }
476 }
477
478 public ServiceReference[] getRegisteredServices()
479 {
480 return felix.getRegisteredServices();
481 }
482
483 public ServiceTracker getServiceTracker(final String interfaceClassName)
484 {
485 return getServiceTracker(interfaceClassName, null);
486 }
487
488 @Override
489 public ServiceTracker getServiceTracker(String interfaceClassName, ServiceTrackerCustomizer serviceTrackerCustomizer)
490 {
491 if (!isRunning())
492 {
493 throw new IllegalStateException("Unable to create a tracker when osgi is not running");
494 }
495
496 final ServiceTracker tracker = registration.getServiceTracker(interfaceClassName, trackers, serviceTrackerCustomizer);
497 tracker.open();
498 trackers.add(tracker);
499 return tracker;
500 }
501
502 public Bundle installBundle(final File file) throws OsgiContainerException
503 {
504 try
505 {
506 return registration.install(file, disableMultipleBundleVersions);
507 }
508 catch (final BundleException e)
509 {
510 throw new OsgiContainerException("Unable to install bundle", e);
511 }
512 }
513
514 DefaultComponentRegistrar collectHostComponents(final HostComponentProvider provider)
515 {
516 final DefaultComponentRegistrar registrar = new DefaultComponentRegistrar();
517 if (provider != null)
518 {
519 provider.provide(registrar);
520 }
521 return registrar;
522 }
523
524 public boolean isRunning()
525 {
526 return felixRunning;
527 }
528
529 public List<HostComponentRegistration> getHostComponentRegistrations()
530 {
531 return registration.getHostComponentRegistrations();
532 }
533
534 private String getAtlassianSpecificOsgiSystemProperty(final String originalSystemProperty)
535 {
536 return System.getProperty(ATLASSIAN_PREFIX + originalSystemProperty);
537 }
538
539
540
541
542
543 @VisibleForTesting
544 String getRuntimeEnvironment()
545 {
546
547
548
549 return String.format("java.version=%s,plugin.enable.timeout=%d", System.getProperty("java.version"),
550 PluginUtils.getDefaultEnablingWaitPeriod());
551 }
552
553
554
555
556
557 static class BundleRegistration implements BundleActivator, BundleListener, FrameworkListener
558 {
559 private BundleContext bundleContext;
560 private DefaultComponentRegistrar registrar;
561 private List<ServiceRegistration> hostServicesReferences;
562 private List<HostComponentRegistration> hostComponentRegistrations;
563 private final URL frameworkBundlesUrl;
564 private final File frameworkBundlesDir;
565 private ClassLoader initializedClassLoader;
566 private PackageAdmin packageAdmin;
567
568 public BundleRegistration(final URL frameworkBundlesUrl, final File frameworkBundlesDir, final DefaultComponentRegistrar registrar)
569 {
570 this.registrar = registrar;
571 this.frameworkBundlesUrl = frameworkBundlesUrl;
572 this.frameworkBundlesDir = frameworkBundlesDir;
573 this.initializedClassLoader = Thread.currentThread().getContextClassLoader();
574 }
575
576 public void start(final BundleContext context) throws Exception
577 {
578 bundleContext = context;
579 final ServiceReference ref = context.getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class.getName());
580 packageAdmin = (PackageAdmin) context.getService(ref);
581
582 context.addBundleListener(this);
583 context.addFrameworkListener(this);
584
585 loadHostComponents(registrar);
586 extractAndInstallFrameworkBundles();
587 }
588
589 public void stop(final BundleContext ctx) throws Exception
590 {
591 ctx.removeBundleListener(this);
592 ctx.removeFrameworkListener(this);
593 if (hostServicesReferences != null)
594 {
595 for (ServiceRegistration ref : hostServicesReferences)
596 {
597 ref.unregister();
598 }
599 }
600 bundleContext = null;
601 packageAdmin = null;
602 hostServicesReferences = null;
603 hostComponentRegistrations = null;
604 registrar = null;
605 initializedClassLoader = null;
606 }
607
608 public void bundleChanged(final BundleEvent evt)
609 {
610 switch (evt.getType())
611 {
612 case BundleEvent.INSTALLED:
613 log.info("Installed bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
614 break;
615 case BundleEvent.RESOLVED:
616 log.info("Resolved bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
617 break;
618 case BundleEvent.UNRESOLVED:
619 log.info("Unresolved bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
620 break;
621 case BundleEvent.STARTED:
622 log.info("Started bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
623 break;
624 case BundleEvent.STOPPED:
625 log.info("Stopped bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
626 break;
627 case BundleEvent.UNINSTALLED:
628 log.info("Uninstalled bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
629 break;
630 }
631 }
632
633 public Bundle install(final File path, final boolean uninstallOtherVersions) throws BundleException
634 {
635 boolean bundleUninstalled = false;
636 if (uninstallOtherVersions)
637 {
638 try
639 {
640 JarFile jar = new JarFile(path);
641 String pluginKey = null;
642 try
643 {
644 pluginKey = OsgiHeaderUtil.getPluginKey(jar.getManifest());
645 }
646 finally
647 {
648 jar.close();
649 }
650 for (final Bundle oldBundle : bundleContext.getBundles())
651 {
652 if (pluginKey.equals(OsgiHeaderUtil.getPluginKey(oldBundle)))
653 {
654 log.info("Uninstalling existing version " + oldBundle.getHeaders().get(Constants.BUNDLE_VERSION));
655 oldBundle.uninstall();
656 bundleUninstalled = true;
657 }
658 }
659 }
660 catch (final IOException e)
661 {
662 throw new BundleException("Invalid bundle format", e);
663 }
664 }
665 final Bundle bundle = bundleContext.installBundle(path.toURI().toString());
666 if (bundleUninstalled)
667 {
668 refreshPackages();
669 }
670 return bundle;
671 }
672
673 public Bundle[] getBundles()
674 {
675 return bundleContext.getBundles();
676 }
677
678 public ServiceTracker getServiceTracker(final String clazz,
679 final Collection<ServiceTracker> trackedTrackers)
680 {
681 return getServiceTracker(clazz, trackedTrackers, null);
682 }
683
684 public ServiceTracker getServiceTracker(final String clazz,
685 final Collection<ServiceTracker> trackedTrackers,
686 final ServiceTrackerCustomizer customizer)
687 {
688 return new ServiceTracker(bundleContext, clazz, customizer)
689 {
690 @Override
691 public void close()
692 {
693 super.close();
694 trackedTrackers.remove(this);
695 }
696 };
697 }
698
699 public List<HostComponentRegistration> getHostComponentRegistrations()
700 {
701 return hostComponentRegistrations;
702 }
703
704 void loadHostComponents(final DefaultComponentRegistrar registrar)
705 {
706
707 if (hostServicesReferences != null)
708 {
709 for (final ServiceRegistration reg : hostServicesReferences)
710 {
711 reg.unregister();
712 }
713 }
714
715 ContextClassLoaderSwitchingUtil.runInContext(initializedClassLoader, new Runnable()
716 {
717 public void run()
718 {
719 hostServicesReferences = registrar.writeRegistry(bundleContext);
720 hostComponentRegistrations = registrar.getRegistry();
721 }
722 });
723 }
724
725 private void extractAndInstallFrameworkBundles() throws BundleException
726 {
727 final List<Bundle> bundles = new ArrayList<Bundle>();
728 com.atlassian.plugin.util.FileUtils.conditionallyExtractZipFile(frameworkBundlesUrl, frameworkBundlesDir);
729 for (final File bundleFile : frameworkBundlesDir.listFiles(new FilenameFilter()
730 {
731 public boolean accept(final File file, final String s)
732 {
733 return s.endsWith(".jar");
734 }
735 }))
736 {
737 bundles.add(install(bundleFile, false));
738 }
739
740 packageAdmin.resolveBundles(null);
741
742 for (final Bundle bundle : bundles)
743 {
744 if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) == null)
745 {
746 bundle.start();
747 }
748 }
749 }
750
751 public void refreshPackages()
752 {
753 final CountDownLatch latch = new CountDownLatch(1);
754 FrameworkListener refreshListener = new FrameworkListener()
755 {
756
757 public void frameworkEvent(FrameworkEvent event)
758 {
759 if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED)
760 {
761 log.info("Packages refreshed");
762 latch.countDown();
763 }
764 }
765 };
766
767 bundleContext.addFrameworkListener(refreshListener);
768 try
769 {
770 packageAdmin.refreshPackages(null);
771 boolean refreshed = false;
772 try
773 {
774 refreshed = latch.await(REFRESH_TIMEOUT, TimeUnit.SECONDS);
775 }
776 catch (InterruptedException e)
777 {
778
779 }
780 if (!refreshed)
781 {
782 log.warn("Timeout exceeded waiting for package refresh");
783 }
784 }
785 finally
786 {
787 bundleContext.removeFrameworkListener(refreshListener);
788 }
789 }
790
791 @SuppressWarnings ({ "ThrowableResultOfMethodCallIgnored" })
792 public void frameworkEvent(FrameworkEvent event)
793 {
794 String bundleBits = "";
795 if (event.getBundle() != null)
796 {
797 bundleBits = " in bundle " + event.getBundle().getSymbolicName();
798 }
799 switch (event.getType())
800 {
801 case FrameworkEvent.ERROR:
802 log.error("Framework error" + bundleBits, event.getThrowable());
803 break;
804 case FrameworkEvent.WARNING:
805 log.warn("Framework warning" + bundleBits, event.getThrowable());
806 break;
807 case FrameworkEvent.INFO:
808 log.info("Framework info" + bundleBits, event.getThrowable());
809 break;
810 }
811 }
812 }
813
814 }