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 }
273
274 configMap.put(FelixConstants.FRAMEWORK_BOOTDELEGATION, bootDelegation);
275 configMap.put(FelixConstants.IMPLICIT_BOOT_DELEGATION_PROP, "false");
276
277 configMap.put(FelixConstants.FRAMEWORK_BUNDLE_PARENT, FelixConstants.FRAMEWORK_BUNDLE_PARENT_FRAMEWORK);
278 if (log.isDebugEnabled())
279 {
280 log.debug("Felix configuration: " + configMap);
281 }
282
283 validateConfiguration(configMap);
284
285 try
286 {
287
288 registration = new BundleRegistration(frameworkBundlesUrl, persistentCache.getFrameworkBundleCache(), registrar);
289 final List<BundleActivator> list = new ArrayList<BundleActivator>();
290 list.add(registration);
291 configMap.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, list);
292
293
294
295 felix = new Felix(configMap);
296
297
298 final Runnable start = new Runnable()
299 {
300 public void run()
301 {
302 try
303 {
304 Thread.currentThread().setContextClassLoader(null);
305 felix.start();
306 felixRunning = true;
307 }
308 catch (final BundleException e)
309 {
310 throw new OsgiContainerException("Unable to start felix", e);
311 }
312 }
313 };
314 final Thread t = threadFactory.newThread(start);
315 t.start();
316
317
318 t.join(10 * 60 * 1000);
319
320 }
321 catch (final Exception ex)
322 {
323 throw new OsgiContainerException("Unable to start OSGi container", ex);
324 }
325 pluginEventManager.broadcast(new OsgiContainerStartedEvent(this));
326 }
327
328
329
330
331
332
333 private void validateConfiguration(StringMap configMap) throws OsgiContainerException
334 {
335 String systemExports = (String) configMap.get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
336
337 String cacheKeySource = StringUtils.join(new Object[] {this.getRuntimeEnvironment(), systemExports }, ',');
338
339 validateCaches(cacheKeySource);
340
341 detectIncorrectOsgiVersion();
342 detectXercesOverride(systemExports);
343 }
344
345
346
347
348
349
350
351
352 void detectXercesOverride(String systemExports) throws OsgiContainerException
353 {
354 int pos = systemExports.indexOf("org.apache.xerces.util");
355 if (pos > -1)
356 {
357 if (pos == 0 || (pos > 0 && systemExports.charAt(pos - 1) == ','))
358 {
359 pos += "org.apache.xerces.util".length();
360
361
362 if (pos >= systemExports.length() || ';' != systemExports.charAt(pos))
363 {
364 throw new OsgiContainerException(
365 "Detected an incompatible version of Apache Xerces on the classpath. If using Tomcat, you may have " +
366 "an old version of Xerces in $TOMCAT_HOME/common/lib/endorsed that will need to be removed.");
367 }
368 }
369 }
370 }
371
372
373
374
375
376
377
378 private void validateCaches(String cacheKeySource)
379 {
380 log.info("Using Felix bundle cacheKey source: {}", cacheKeySource);
381 persistentCache.validate(cacheKeySource);
382 log.debug("Using Felix bundle cache directory: {}", persistentCache.getOsgiBundleCache().getAbsolutePath());
383 }
384
385
386
387
388 private void detectIncorrectOsgiVersion()
389 {
390 try
391 {
392 Bundle.class.getMethod("getBundleContext");
393 }
394 catch (final NoSuchMethodException e)
395 {
396 throw new OsgiContainerException(
397 "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.");
398 }
399 }
400
401 public void stop() throws OsgiContainerException
402 {
403 if (felixRunning)
404 {
405 for (final ServiceTracker tracker : new HashSet<ServiceTracker>(trackers))
406 {
407 tracker.close();
408 }
409 FrameworkListener listener = new FrameworkListener()
410 {
411 @Override
412 public void frameworkEvent(FrameworkEvent event)
413 {
414 if (event.getType() == FrameworkEvent.WAIT_TIMEDOUT)
415 {
416 log.error("Timeout waiting for OSGi to shutdown");
417 threadDump();
418 } else if (event.getType() == FrameworkEvent.STOPPED)
419 {
420 log.info("OSGi shutdown successful");
421 }
422 }
423 };
424 try
425 {
426 felix.getBundleContext().addFrameworkListener(listener);
427 felix.stop();
428 felix.waitForStop(TimeUnit.SECONDS.toMillis(60));
429 }
430 catch (InterruptedException e)
431 {
432 log.warn("Interrupting Felix shutdown", e);
433 }
434 catch (BundleException ex)
435 {
436 log.error("An error occurred while stopping the Felix OSGi Container. ", ex);
437 }
438 }
439
440 felixRunning = false;
441 felix = null;
442 pluginEventManager.broadcast(new OsgiContainerStoppedEvent(this));
443 }
444
445 private void threadDump()
446 {
447 StringBuilder sb = new StringBuilder();
448 String nl = System.getProperty("line.separator");
449 for (Map.Entry<Thread,StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet())
450 {
451 Thread key = entry.getKey();
452 StackTraceElement[] trace = entry.getValue();
453 sb.append(key).append(nl);
454 for (StackTraceElement aTrace : trace)
455 {
456 sb.append(" ").append(aTrace).append(nl);
457 }
458 }
459 log.debug("Thread dump: " + nl + sb.toString());
460 }
461
462 public Bundle[] getBundles()
463 {
464 if (isRunning())
465 {
466 return registration.getBundles();
467 }
468 else
469 {
470 throw new IllegalStateException(
471 "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.");
472 }
473 }
474
475 public ServiceReference[] getRegisteredServices()
476 {
477 return felix.getRegisteredServices();
478 }
479
480 public ServiceTracker getServiceTracker(final String interfaceClassName)
481 {
482 return getServiceTracker(interfaceClassName, null);
483 }
484
485 @Override
486 public ServiceTracker getServiceTracker(String interfaceClassName, ServiceTrackerCustomizer serviceTrackerCustomizer)
487 {
488 if (!isRunning())
489 {
490 throw new IllegalStateException("Unable to create a tracker when osgi is not running");
491 }
492
493 final ServiceTracker tracker = registration.getServiceTracker(interfaceClassName, trackers, serviceTrackerCustomizer);
494 tracker.open();
495 trackers.add(tracker);
496 return tracker;
497 }
498
499 public Bundle installBundle(final File file) throws OsgiContainerException
500 {
501 try
502 {
503 return registration.install(file, disableMultipleBundleVersions);
504 }
505 catch (final BundleException e)
506 {
507 throw new OsgiContainerException("Unable to install bundle", e);
508 }
509 }
510
511 DefaultComponentRegistrar collectHostComponents(final HostComponentProvider provider)
512 {
513 final DefaultComponentRegistrar registrar = new DefaultComponentRegistrar();
514 if (provider != null)
515 {
516 provider.provide(registrar);
517 }
518 return registrar;
519 }
520
521 public boolean isRunning()
522 {
523 return felixRunning;
524 }
525
526 public List<HostComponentRegistration> getHostComponentRegistrations()
527 {
528 return registration.getHostComponentRegistrations();
529 }
530
531 private String getAtlassianSpecificOsgiSystemProperty(final String originalSystemProperty)
532 {
533 return System.getProperty(ATLASSIAN_PREFIX + originalSystemProperty);
534 }
535
536
537
538
539
540 @VisibleForTesting
541 String getRuntimeEnvironment()
542 {
543
544
545
546 return String.format("java.version=%s,plugin.enable.timeout=%d", System.getProperty("java.version"),
547 PluginUtils.getDefaultEnablingWaitPeriod());
548 }
549
550
551
552
553
554 static class BundleRegistration implements BundleActivator, BundleListener, FrameworkListener
555 {
556 private BundleContext bundleContext;
557 private DefaultComponentRegistrar registrar;
558 private List<ServiceRegistration> hostServicesReferences;
559 private List<HostComponentRegistration> hostComponentRegistrations;
560 private final URL frameworkBundlesUrl;
561 private final File frameworkBundlesDir;
562 private ClassLoader initializedClassLoader;
563 private PackageAdmin packageAdmin;
564
565 public BundleRegistration(final URL frameworkBundlesUrl, final File frameworkBundlesDir, final DefaultComponentRegistrar registrar)
566 {
567 this.registrar = registrar;
568 this.frameworkBundlesUrl = frameworkBundlesUrl;
569 this.frameworkBundlesDir = frameworkBundlesDir;
570 this.initializedClassLoader = Thread.currentThread().getContextClassLoader();
571 }
572
573 public void start(final BundleContext context) throws Exception
574 {
575 bundleContext = context;
576 final ServiceReference ref = context.getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class.getName());
577 packageAdmin = (PackageAdmin) context.getService(ref);
578
579 context.addBundleListener(this);
580 context.addFrameworkListener(this);
581
582 loadHostComponents(registrar);
583 extractAndInstallFrameworkBundles();
584 }
585
586 public void stop(final BundleContext ctx) throws Exception
587 {
588 ctx.removeBundleListener(this);
589 ctx.removeFrameworkListener(this);
590 if (hostServicesReferences != null)
591 {
592 for (ServiceRegistration ref : hostServicesReferences)
593 {
594 ref.unregister();
595 }
596 }
597 bundleContext = null;
598 packageAdmin = null;
599 hostServicesReferences = null;
600 hostComponentRegistrations = null;
601 registrar = null;
602 initializedClassLoader = null;
603 }
604
605 public void bundleChanged(final BundleEvent evt)
606 {
607 switch (evt.getType())
608 {
609 case BundleEvent.INSTALLED:
610 log.info("Installed bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
611 break;
612 case BundleEvent.RESOLVED:
613 log.info("Resolved bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
614 break;
615 case BundleEvent.UNRESOLVED:
616 log.info("Unresolved bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
617 break;
618 case BundleEvent.STARTED:
619 log.info("Started bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
620 break;
621 case BundleEvent.STOPPED:
622 log.info("Stopped bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
623 break;
624 case BundleEvent.UNINSTALLED:
625 log.info("Uninstalled bundle " + evt.getBundle().getSymbolicName() + " (" + evt.getBundle().getBundleId() + ")");
626 break;
627 }
628 }
629
630 public Bundle install(final File path, final boolean uninstallOtherVersions) throws BundleException
631 {
632 boolean bundleUninstalled = false;
633 if (uninstallOtherVersions)
634 {
635 try
636 {
637 JarFile jar = new JarFile(path);
638 String pluginKey = null;
639 try
640 {
641 pluginKey = OsgiHeaderUtil.getPluginKey(jar.getManifest());
642 }
643 finally
644 {
645 jar.close();
646 }
647 for (final Bundle oldBundle : bundleContext.getBundles())
648 {
649 if (pluginKey.equals(OsgiHeaderUtil.getPluginKey(oldBundle)))
650 {
651 log.info("Uninstalling existing version " + oldBundle.getHeaders().get(Constants.BUNDLE_VERSION));
652 oldBundle.uninstall();
653 bundleUninstalled = true;
654 }
655 }
656 }
657 catch (final IOException e)
658 {
659 throw new BundleException("Invalid bundle format", e);
660 }
661 }
662 final Bundle bundle = bundleContext.installBundle(path.toURI().toString());
663 if (bundleUninstalled)
664 {
665 refreshPackages();
666 }
667 return bundle;
668 }
669
670 public Bundle[] getBundles()
671 {
672 return bundleContext.getBundles();
673 }
674
675 public ServiceTracker getServiceTracker(final String clazz,
676 final Collection<ServiceTracker> trackedTrackers)
677 {
678 return getServiceTracker(clazz, trackedTrackers, null);
679 }
680
681 public ServiceTracker getServiceTracker(final String clazz,
682 final Collection<ServiceTracker> trackedTrackers,
683 final ServiceTrackerCustomizer customizer)
684 {
685 return new ServiceTracker(bundleContext, clazz, customizer)
686 {
687 @Override
688 public void close()
689 {
690 super.close();
691 trackedTrackers.remove(this);
692 }
693 };
694 }
695
696 public List<HostComponentRegistration> getHostComponentRegistrations()
697 {
698 return hostComponentRegistrations;
699 }
700
701 void loadHostComponents(final DefaultComponentRegistrar registrar)
702 {
703
704 if (hostServicesReferences != null)
705 {
706 for (final ServiceRegistration reg : hostServicesReferences)
707 {
708 reg.unregister();
709 }
710 }
711
712 ContextClassLoaderSwitchingUtil.runInContext(initializedClassLoader, new Runnable()
713 {
714 public void run()
715 {
716 hostServicesReferences = registrar.writeRegistry(bundleContext);
717 hostComponentRegistrations = registrar.getRegistry();
718 }
719 });
720 }
721
722 private void extractAndInstallFrameworkBundles() throws BundleException
723 {
724 final List<Bundle> bundles = new ArrayList<Bundle>();
725 com.atlassian.plugin.util.FileUtils.conditionallyExtractZipFile(frameworkBundlesUrl, frameworkBundlesDir);
726 for (final File bundleFile : frameworkBundlesDir.listFiles(new FilenameFilter()
727 {
728 public boolean accept(final File file, final String s)
729 {
730 return s.endsWith(".jar");
731 }
732 }))
733 {
734 bundles.add(install(bundleFile, false));
735 }
736
737 packageAdmin.resolveBundles(null);
738
739 for (final Bundle bundle : bundles)
740 {
741 if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) == null)
742 {
743 bundle.start();
744 }
745 }
746 }
747
748 public void refreshPackages()
749 {
750 final CountDownLatch latch = new CountDownLatch(1);
751 FrameworkListener refreshListener = new FrameworkListener()
752 {
753
754 public void frameworkEvent(FrameworkEvent event)
755 {
756 if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED)
757 {
758 log.info("Packages refreshed");
759 latch.countDown();
760 }
761 }
762 };
763
764 bundleContext.addFrameworkListener(refreshListener);
765 try
766 {
767 packageAdmin.refreshPackages(null);
768 boolean refreshed = false;
769 try
770 {
771 refreshed = latch.await(REFRESH_TIMEOUT, TimeUnit.SECONDS);
772 }
773 catch (InterruptedException e)
774 {
775
776 }
777 if (!refreshed)
778 {
779 log.warn("Timeout exceeded waiting for package refresh");
780 }
781 }
782 finally
783 {
784 bundleContext.removeFrameworkListener(refreshListener);
785 }
786 }
787
788 @SuppressWarnings ({ "ThrowableResultOfMethodCallIgnored" })
789 public void frameworkEvent(FrameworkEvent event)
790 {
791 String bundleBits = "";
792 if (event.getBundle() != null)
793 {
794 bundleBits = " in bundle " + event.getBundle().getSymbolicName();
795 }
796 switch (event.getType())
797 {
798 case FrameworkEvent.ERROR:
799 log.error("Framework error" + bundleBits, event.getThrowable());
800 break;
801 case FrameworkEvent.WARNING:
802 log.warn("Framework warning" + bundleBits, event.getThrowable());
803 break;
804 case FrameworkEvent.INFO:
805 log.info("Framework info" + bundleBits, event.getThrowable());
806 break;
807 }
808 }
809 }
810
811 }