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