| /******************************************************************************* |
| * Copyright (c) 2008, 2010 VMware Inc. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * VMware Inc. - initial contribution |
| *******************************************************************************/ |
| |
| package org.eclipse.virgo.kernel.userregion.internal; |
| |
| import static org.eclipse.virgo.kernel.osgi.framework.ServiceUtils.PROPERTY_KERNEL_STARTUP_WAIT_LIMIT; |
| import static org.eclipse.virgo.kernel.osgi.framework.ServiceUtils.getPotentiallyDelayedService; |
| import static org.eclipse.virgo.kernel.osgi.framework.ServiceUtils.getWaitLimitSeconds; |
| |
| import java.io.IOException; |
| import java.util.Dictionary; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.Set; |
| import java.util.concurrent.TimeoutException; |
| |
| import org.eclipse.equinox.region.RegionDigraph; |
| import org.eclipse.osgi.service.resolver.PlatformAdmin; |
| import org.eclipse.virgo.nano.core.ConfigurationExporter; |
| import org.eclipse.virgo.nano.core.Shutdown; |
| import org.eclipse.virgo.nano.deployer.api.config.ConfigurationDeployer; |
| import org.eclipse.virgo.nano.deployer.api.core.ApplicationDeployer; |
| import org.eclipse.virgo.nano.deployer.api.core.DeployUriNormaliser; |
| import org.eclipse.virgo.kernel.install.artifact.ScopeServiceRepository; |
| import org.eclipse.virgo.kernel.module.ModuleContextAccessor; |
| import org.eclipse.virgo.kernel.osgi.framework.ImportExpander; |
| import org.eclipse.virgo.kernel.osgi.framework.OsgiFramework; |
| import org.eclipse.virgo.kernel.osgi.framework.OsgiFrameworkUtils; |
| import org.eclipse.virgo.kernel.osgi.framework.PackageAdminUtil; |
| import org.eclipse.virgo.kernel.osgi.quasi.QuasiFrameworkFactory; |
| import org.eclipse.virgo.kernel.services.work.WorkArea; |
| import org.eclipse.virgo.nano.shim.scope.ScopeFactory; |
| import org.eclipse.virgo.kernel.userregion.internal.dump.StandardDumpExtractor; |
| import org.eclipse.virgo.kernel.userregion.internal.equinox.EquinoxHookRegistrar; |
| import org.eclipse.virgo.kernel.userregion.internal.equinox.EquinoxOsgiFramework; |
| import org.eclipse.virgo.kernel.userregion.internal.equinox.StandardPackageAdminUtil; |
| import org.eclipse.virgo.kernel.userregion.internal.equinox.TransformedManifestProvidingBundleFileWrapper; |
| import org.eclipse.virgo.kernel.userregion.internal.importexpansion.ImportExpansionHandler; |
| import org.eclipse.virgo.kernel.userregion.internal.management.StateDumpMXBeanExporter; |
| import org.eclipse.virgo.kernel.userregion.internal.quasi.ResolutionFailureDetective; |
| import org.eclipse.virgo.kernel.userregion.internal.quasi.StandardQuasiFrameworkFactory; |
| import org.eclipse.virgo.kernel.userregion.internal.quasi.StandardResolutionFailureDetective; |
| import org.eclipse.virgo.medic.eventlog.EventLogger; |
| import org.eclipse.virgo.medic.eventlog.EventLoggerFactory; |
| import org.eclipse.virgo.kernel.equinox.extensions.hooks.MetaInfResourceClassLoaderDelegateHook; |
| import org.eclipse.virgo.repository.Repository; |
| import org.eclipse.virgo.util.osgi.ServiceRegistrationTracker; |
| import org.osgi.framework.BundleActivator; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.Constants; |
| import org.osgi.service.cm.Configuration; |
| import org.osgi.service.cm.ConfigurationAdmin; |
| import org.osgi.service.event.EventAdmin; |
| import org.osgi.service.event.EventConstants; |
| import org.osgi.service.event.EventHandler; |
| import org.osgi.service.packageadmin.ExportedPackage; |
| import org.osgi.service.packageadmin.PackageAdmin; |
| |
| /** |
| * {@link BundleActivator} for the Equinox-specific OSGi integration |
| * <p /> |
| * |
| * <strong>Concurrent Semantics</strong><br /> |
| * |
| * Thread-safe. |
| * |
| */ |
| @SuppressWarnings("deprecation") |
| public class Activator implements BundleActivator { |
| |
| private static final long SYSTEM_BUNDLE_ID = 0; |
| |
| private static final String PROPERTY_USER_REGION_ARTIFACTS = "initialArtifacts"; |
| |
| private static final String PROPERTY_USER_REGION_COMMANDLINE_ARTIFACTS = "commandLineArtifacts"; |
| |
| private static final String USER_REGION_CONFIGURATION_PID = "org.eclipse.virgo.kernel.userregion"; |
| |
| private static final String KERNEL_REGION_CONFIGURATION_PID = "org.eclipse.virgo.kernel"; |
| |
| private final ServiceRegistrationTracker registrationTracker = new ServiceRegistrationTracker(); |
| |
| private volatile EquinoxHookRegistrar hookRegistrar; |
| |
| private StateDumpMXBeanExporter stateDumpMBeanExorter; |
| |
| private ConsoleConfigurationConvertor consoleConfigurationConvertor = null; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void start(BundleContext context) throws Exception { |
| publishConfigurations(context); |
| ResolutionFailureDetective rfd = createResolutionFailureDetective(context); |
| Repository repository = getPotentiallyDelayedService(context, Repository.class); |
| PackageAdmin packageAdmin = getPotentiallyDelayedService(context, PackageAdmin.class); |
| |
| EventLogger eventLogger = getPotentiallyDelayedService(context, EventLoggerFactory.class).createEventLogger(context.getBundle()); |
| |
| RegionDigraph regionDigraph = getPotentiallyDelayedService(context, RegionDigraph.class); |
| |
| WorkArea workArea = getPotentiallyDelayedService(context, WorkArea.class); |
| |
| ImportExpansionHandler importExpansionHandler = createImportExpansionHandler(context, packageAdmin, repository, eventLogger); |
| this.registrationTracker.track(context.registerService(ImportExpander.class.getName(), importExpansionHandler, null)); |
| |
| TransformedManifestProvidingBundleFileWrapper bundleTransformerHandler = createBundleTransformationHandler(importExpansionHandler); |
| |
| OsgiFramework osgiFramework = createOsgiFramework(context, packageAdmin, bundleTransformerHandler); |
| this.registrationTracker.track(context.registerService(OsgiFramework.class.getName(), osgiFramework, null)); |
| |
| DumpExtractor dumpExtractor = new StandardDumpExtractor(workArea); |
| QuasiFrameworkFactory quasiFrameworkFactory = createQuasiFrameworkFactory(context, rfd, repository, bundleTransformerHandler, regionDigraph, |
| dumpExtractor); |
| this.registrationTracker.track(context.registerService(QuasiFrameworkFactory.class.getName(), quasiFrameworkFactory, null)); |
| |
| EquinoxHookRegistrar hookRegistrar = createHookRegistrar(context, packageAdmin, bundleTransformerHandler); |
| hookRegistrar.init(); |
| this.hookRegistrar = hookRegistrar; |
| |
| PackageAdminUtil packageAdminUtil = createPackageAdminUtil(context); |
| this.registrationTracker.track(context.registerService(PackageAdminUtil.class.getName(), packageAdminUtil, null)); |
| |
| scheduleRegistrationOfServiceScopingRegistryHooks(context, eventLogger); |
| |
| Dictionary<String, Object> properties = new Hashtable<>(); |
| properties.put(Constants.SERVICE_RANKING, Integer.MIN_VALUE); |
| this.registrationTracker.track(context.registerService(ModuleContextAccessor.class.getName(), new EmptyModuleContextAccessor(), properties)); |
| |
| scheduleInitialArtifactDeployerCreation(context, eventLogger); |
| |
| context.registerService(ConfigurationDeployer.class, new UserRegionConfigurationDeployer(context), null); |
| initializeConsoleConfigurationConvertor(context); |
| this.stateDumpMBeanExorter = new StateDumpMXBeanExporter(quasiFrameworkFactory); |
| } |
| |
| /** |
| * This method gets the kernel and user regions configurations from the kernel region and publishes them in the |
| * configuration admin in the user region. |
| */ |
| private void publishConfigurations(BundleContext context) throws Exception { |
| ConfigurationExporter configurationExporter = getPotentiallyDelayedService(context, ConfigurationExporter.class); |
| ConfigurationAdmin admin = getPotentiallyDelayedService(context, ConfigurationAdmin.class); |
| |
| try { |
| publishConfigurationFromKernelRegion(configurationExporter.getUserRegionConfigurationProperties(), |
| admin.getConfiguration(USER_REGION_CONFIGURATION_PID)); |
| publishConfigurationFromKernelRegion(configurationExporter.getKernelRegionConfigurationProperties(), |
| admin.getConfiguration(KERNEL_REGION_CONFIGURATION_PID)); |
| } catch (IOException e) { |
| throw new RuntimeException("Failed to publish required configurations. Startup sequence can't continue", e); |
| } |
| } |
| |
| private void publishConfigurationFromKernelRegion(Dictionary<String, Object> configurationProperties, Configuration config) throws IOException { |
| config.update(configurationProperties); |
| } |
| |
| private ResolutionFailureDetective createResolutionFailureDetective(BundleContext context) { |
| PlatformAdmin platformAdmin = OsgiFrameworkUtils.getService(context, PlatformAdmin.class).getService(); |
| return new StandardResolutionFailureDetective(platformAdmin); |
| } |
| |
| private OsgiFramework createOsgiFramework(BundleContext context, PackageAdmin packageAdmin, |
| TransformedManifestProvidingBundleFileWrapper bundleTransformerHandler) { |
| return new EquinoxOsgiFramework(context, packageAdmin, bundleTransformerHandler); |
| } |
| |
| private QuasiFrameworkFactory createQuasiFrameworkFactory(BundleContext bundleContext, ResolutionFailureDetective detective, |
| Repository repository, TransformedManifestProvidingBundleFileWrapper bundleTransformerHandler, RegionDigraph regionDigraph, |
| DumpExtractor dumpExtractor) { |
| return new StandardQuasiFrameworkFactory(bundleContext, detective, repository, bundleTransformerHandler, regionDigraph, dumpExtractor); |
| } |
| |
| private TransformedManifestProvidingBundleFileWrapper createBundleTransformationHandler(ImportExpansionHandler importExpander) { |
| return new TransformedManifestProvidingBundleFileWrapper(importExpander); |
| } |
| |
| private ImportExpansionHandler createImportExpansionHandler(BundleContext context, PackageAdmin packageAdmin, Repository repository, |
| EventLogger eventLogger) { |
| |
| Set<String> packagesExportedBySystemBundle = new HashSet<String>(30); |
| ExportedPackage[] exportedPackages = packageAdmin.getExportedPackages(context.getBundle(SYSTEM_BUNDLE_ID)); |
| |
| for (ExportedPackage exportedPackage : exportedPackages) { |
| packagesExportedBySystemBundle.add(exportedPackage.getName()); |
| } |
| |
| return new ImportExpansionHandler(repository, context, packagesExportedBySystemBundle, eventLogger); |
| } |
| |
| private EquinoxHookRegistrar createHookRegistrar(BundleContext context, PackageAdmin packageAdmin, |
| TransformedManifestProvidingBundleFileWrapper bundleFileWrapper) { |
| MetaInfResourceClassLoaderDelegateHook hook = new MetaInfResourceClassLoaderDelegateHook(context, packageAdmin); |
| return new EquinoxHookRegistrar(bundleFileWrapper, hook); |
| } |
| |
| private PackageAdminUtil createPackageAdminUtil(BundleContext context) { |
| return new StandardPackageAdminUtil(context); |
| } |
| |
| private void scheduleRegistrationOfServiceScopingRegistryHooks(final BundleContext context, EventLogger eventLogger) { |
| Runnable runnable = new ServiceScopingHookRegisteringRunnable(context, this.registrationTracker, eventLogger); |
| Thread thread = new Thread(runnable); |
| thread.setDaemon(true); |
| thread.start(); |
| } |
| |
| private void scheduleInitialArtifactDeployerCreation(BundleContext context, EventLogger eventLogger) { |
| KernelStartedAwaiter startedAwaiter = new KernelStartedAwaiter(); |
| |
| Dictionary<String, String> properties = new Hashtable<>(); |
| properties.put(EventConstants.EVENT_TOPIC, "org/eclipse/virgo/kernel/*"); |
| this.registrationTracker.track(context.registerService(EventHandler.class.getName(), startedAwaiter, properties)); |
| |
| Runnable runnable = new InitialArtifactDeployerCreatingRunnable(context, eventLogger, this.registrationTracker, startedAwaiter); |
| Thread thread = new Thread(runnable); |
| thread.setDaemon(true); |
| thread.start(); |
| } |
| |
| private void initializeConsoleConfigurationConvertor(BundleContext context) { |
| consoleConfigurationConvertor = new ConsoleConfigurationConvertor(context); |
| consoleConfigurationConvertor.start(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void stop(BundleContext context) { |
| this.registrationTracker.unregisterAll(); |
| |
| if (this.consoleConfigurationConvertor != null) { |
| this.consoleConfigurationConvertor.stop(); |
| } |
| |
| StateDumpMXBeanExporter localStateDumpMBeanExporter = this.stateDumpMBeanExorter; |
| if (localStateDumpMBeanExporter != null) { |
| localStateDumpMBeanExporter.close(); |
| this.stateDumpMBeanExorter = null; |
| } |
| |
| EquinoxHookRegistrar hookRegistrar = this.hookRegistrar; |
| if (hookRegistrar != null) { |
| hookRegistrar.destroy(); |
| this.hookRegistrar = null; |
| } |
| |
| } |
| |
| private static final class ServiceScopingHookRegisteringRunnable implements Runnable { |
| |
| private final EventLogger eventLogger; |
| |
| private final BundleContext context; |
| |
| private final ServiceRegistrationTracker registrationTracker; |
| |
| ServiceScopingHookRegisteringRunnable(BundleContext context, ServiceRegistrationTracker registrationTracker, EventLogger eventLogger) { |
| this.context = context; |
| this.registrationTracker = registrationTracker; |
| this.eventLogger = eventLogger; |
| } |
| |
| public void run() { |
| ScopeFactory scopeFactory = OsgiFrameworkUtils.getService(context, ScopeFactory.class).getService(); |
| Shutdown shutdown = OsgiFrameworkUtils.getService(context, Shutdown.class).getService(); |
| |
| try { |
| ScopeServiceRepository scopeServiceRepository = getPotentiallyDelayedService(context, ScopeServiceRepository.class); |
| |
| ServiceScopingStrategy serviceScopingStrategy = new ServiceScopingStrategy(scopeFactory, scopeServiceRepository); |
| |
| ServiceScopingRegistryHook serviceScopingRegistryHook = new ServiceScopingRegistryHook(serviceScopingStrategy); |
| |
| this.registrationTracker.track(context.registerService(new String[] { "org.osgi.framework.hooks.service.FindHook", |
| "org.osgi.framework.hooks.service.EventHook" }, serviceScopingRegistryHook, null)); |
| } catch (TimeoutException te) { |
| this.eventLogger.log(UserRegionLogEvents.KERNEL_SERVICE_NOT_AVAILABLE, te, getWaitLimitSeconds(), PROPERTY_KERNEL_STARTUP_WAIT_LIMIT); |
| shutdown.immediateShutdown(); |
| } catch (InterruptedException ie) { |
| this.eventLogger.log(UserRegionLogEvents.USERREGION_START_INTERRUPTED, ie); |
| shutdown.immediateShutdown(); |
| } |
| } |
| } |
| |
| private static final class InitialArtifactDeployerCreatingRunnable implements Runnable { |
| |
| private final BundleContext context; |
| |
| private final EventLogger eventLogger; |
| |
| private final KernelStartedAwaiter startAwaiter; |
| |
| private final ServiceRegistrationTracker registrationTracker; |
| |
| InitialArtifactDeployerCreatingRunnable(BundleContext context, EventLogger eventLogger, |
| ServiceRegistrationTracker registrationTracker, KernelStartedAwaiter startAwaiter) { |
| this.context = context; |
| this.eventLogger = eventLogger; |
| this.startAwaiter = startAwaiter; |
| this.registrationTracker = registrationTracker; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void run() { |
| EventAdmin eventAdmin = OsgiFrameworkUtils.getService(context, EventAdmin.class).getService(); |
| Shutdown shutdown = OsgiFrameworkUtils.getService(context, Shutdown.class).getService(); |
| |
| try { |
| DeployUriNormaliser uriNormaliser = getPotentiallyDelayedService(context, DeployUriNormaliser.class); |
| ApplicationDeployer deployer = getPotentiallyDelayedService(context, ApplicationDeployer.class); |
| |
| Dictionary<String, Object> artifactConfiguration = getRegionArtifactConfiguration(); |
| |
| InitialArtifactDeployer initialArtifactDeployer = new InitialArtifactDeployer(this.startAwaiter, deployer, |
| artifactConfiguration.get(PROPERTY_USER_REGION_ARTIFACTS), artifactConfiguration.get(PROPERTY_USER_REGION_COMMANDLINE_ARTIFACTS), |
| uriNormaliser, eventAdmin, eventLogger, shutdown); |
| Dictionary<String, String> properties = new Hashtable<>(); |
| properties.put(EventConstants.EVENT_TOPIC, "org/eclipse/virgo/kernel/*"); |
| this.registrationTracker.track(context.registerService(EventHandler.class.getName(), initialArtifactDeployer, properties)); |
| |
| initialArtifactDeployer.deployArtifacts(); |
| } catch (TimeoutException te) { |
| this.eventLogger.log(UserRegionLogEvents.KERNEL_SERVICE_NOT_AVAILABLE, te, getWaitLimitSeconds(), PROPERTY_KERNEL_STARTUP_WAIT_LIMIT); |
| shutdown.immediateShutdown(); |
| } catch (InterruptedException ie) { |
| this.eventLogger.log(UserRegionLogEvents.USERREGION_START_INTERRUPTED, ie); |
| shutdown.immediateShutdown(); |
| } |
| } |
| |
| private Dictionary<String, Object> getRegionArtifactConfiguration() { |
| ConfigurationAdmin configAdmin = OsgiFrameworkUtils.getService(this.context, ConfigurationAdmin.class).getService(); |
| try { |
| Configuration config = configAdmin.getConfiguration(USER_REGION_CONFIGURATION_PID, null); |
| return config.getProperties(); |
| } catch (IOException ioe) { |
| throw new RuntimeException("Failed to read region artifact configuration", ioe); |
| } |
| } |
| |
| } |
| |
| } |