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