/*
* JBoss, Home of Professional Open Source.
* Copyright 2010, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.osgi.service;
import static org.jboss.as.osgi.OSGiLogger.LOGGER;
import static org.jboss.as.osgi.OSGiMessages.MESSAGES;
import static org.jboss.osgi.framework.spi.IntegrationConstants.STORAGE_STATE_KEY;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.jboss.as.osgi.OSGiConstants;
import org.jboss.as.osgi.parser.SubsystemState;
import org.jboss.as.osgi.parser.SubsystemState.OSGiCapability;
import org.jboss.as.server.ServerEnvironment;
import org.jboss.as.server.ServerEnvironmentService;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceTarget;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.value.InjectedValue;
import org.jboss.osgi.deployment.deployer.Deployment;
import org.jboss.osgi.deployment.deployer.DeploymentFactory;
import org.jboss.osgi.framework.Services;
import org.jboss.osgi.framework.spi.BootstrapBundlesActivate;
import org.jboss.osgi.framework.spi.BootstrapBundlesInstall;
import org.jboss.osgi.framework.spi.BootstrapBundlesResolve;
import org.jboss.osgi.framework.spi.BundleManager;
import org.jboss.osgi.framework.spi.IntegrationServices;
import org.jboss.osgi.framework.spi.StorageManager;
import org.jboss.osgi.framework.spi.StorageState;
import org.jboss.osgi.repository.ResourceInstaller;
import org.jboss.osgi.repository.XRepository;
import org.jboss.osgi.repository.spi.MavenIdentityRepository;
import org.jboss.osgi.resolver.MavenCoordinates;
import org.jboss.osgi.resolver.XBundle;
import org.jboss.osgi.resolver.XBundleRevision;
import org.jboss.osgi.resolver.XCapability;
import org.jboss.osgi.resolver.XEnvironment;
import org.jboss.osgi.resolver.XRequirement;
import org.jboss.osgi.resolver.XRequirementBuilder;
import org.jboss.osgi.resolver.XResource;
import org.jboss.osgi.spi.BundleInfo;
import org.jboss.osgi.vfs.AbstractVFS;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.startlevel.BundleStartLevel;
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.service.repository.ContentNamespace;
/**
* An {@link org.jboss.osgi.framework.spi.IntegrationService} to install the configured capability bundles.
*
* @author Thomas.Diesler@jboss.com
* @since 11-Sep-2010
*/
class BootstrapBundlesIntegration extends BootstrapBundlesInstall<Void> {
private final InjectedValue<BundleManager> injectedBundleManager = new InjectedValue<BundleManager>();
private final InjectedValue<StorageManager> injectedStorageManager = new InjectedValue<StorageManager>();
private final InjectedValue<ServerEnvironment> injectedServerEnvironment = new InjectedValue<ServerEnvironment>();
private final InjectedValue<BundleContext> injectedSystemContext = new InjectedValue<BundleContext>();
private final InjectedValue<SubsystemState> injectedSubsystemState = new InjectedValue<SubsystemState>();
private final InjectedValue<XEnvironment> injectedEnvironment = new InjectedValue<XEnvironment>();
private final InjectedValue<XRepository> injectedRepository = new InjectedValue<XRepository>();
private final InjectedValue<ResourceInstaller> injectedResourceInstaller = new InjectedValue<ResourceInstaller>();
private List<OSGiCapability> modulecaps;
private List<File> bundlesPath;
BootstrapBundlesIntegration() {
super(IntegrationServices.BOOTSTRAP_BUNDLES);
}
@Override
protected void addServiceDependencies(ServiceBuilder<Void> builder) {
super.addServiceDependencies(builder);
builder.addDependency(OSGiConstants.SUBSYSTEM_STATE_SERVICE_NAME, SubsystemState.class, injectedSubsystemState);
builder.addDependency(ServerEnvironmentService.SERVICE_NAME, ServerEnvironment.class, injectedServerEnvironment);
builder.addDependency(ResourceInstallerService.SERVICE_NAME, ResourceInstaller.class, injectedResourceInstaller);
builder.addDependency(OSGiConstants.REPOSITORY_SERVICE_NAME, XRepository.class, injectedRepository);
builder.addDependency(Services.BUNDLE_MANAGER, BundleManager.class, injectedBundleManager);
builder.addDependency(Services.FRAMEWORK_CREATE, BundleContext.class, injectedSystemContext);
builder.addDependency(Services.ENVIRONMENT, XEnvironment.class, injectedEnvironment);
builder.addDependency(IntegrationServices.STORAGE_MANAGER_PLUGIN, StorageManager.class, injectedStorageManager);
}
@Override
public synchronized void start(StartContext context) throws StartException {
List<Deployment> deployments = new ArrayList<Deployment>();
ServerEnvironment serverEnvironment = injectedServerEnvironment.getValue();
bundlesPath = LayeredBundlePathFactory.resolveLayeredBundlePath(serverEnvironment);
modulecaps = new ArrayList<OSGiCapability>();
List<OSGiCapability> configcaps = new ArrayList<OSGiCapability>();
for (String capspec : SystemPackagesIntegration.DEFAULT_CAPABILITIES) {
configcaps.add(new OSGiCapability(capspec, null));
}
configcaps.addAll(injectedSubsystemState.getValue().getCapabilities());
Iterator<OSGiCapability> iterator = configcaps.iterator();
while (iterator.hasNext()) {
OSGiCapability configcap = iterator.next();
String identifier = configcap.getIdentifier();
if (isValidModuleIdentifier(identifier)) {
try {
XBundle bundle = installInitialModuleCapability(configcap);
if (bundle != null) {
modulecaps.add(configcap);
iterator.remove();
}
} catch (Exception ex) {
throw MESSAGES.startFailedToProcessInitialCapability(ex, identifier);
}
}
}
for (OSGiCapability configcap : configcaps) {
String identifier = configcap.getIdentifier();
try {
Deployment dep = getInitialBundleDeployment(configcap);
deployments.add(dep);
} catch (Exception ex) {
throw MESSAGES.startFailedToProcessInitialCapability(ex, identifier);
}
}
// Install the bundles from the given locations
installBootstrapBundles(context.getChildTarget(), deployments);
}
@Override
protected ServiceController<Void> installResolveService(ServiceTarget serviceTarget, Set<XBundleRevision> installedRevisions) {
return new BootstrapResolveIntegration(getServiceName().getParent(), installedRevisions).install(serviceTarget, getServiceListener());
}
private XBundle installInitialModuleCapability(OSGiCapability configcap) throws Exception {
String identifier = configcap.getIdentifier();
ModuleIdentifier moduleId = ModuleIdentifier.fromString(identifier);
// Find the module in the bundles hierarchy
ModuleIdentityRepositoryIntegration repository = getModuleIdentityRepository();
File bundleFile = repository.getRepositoryEntry(bundlesPath, moduleId);
if (bundleFile != null)
return null;
LOGGER.tracef("Installing initial module capability: %s", identifier);
// Build the module requirement
XRequirementBuilder reqbuilder = XRequirementBuilder.create(moduleId);
XRequirement modreq = reqbuilder.getRequirement();
Collection<Capability> caps = repository.findProviders(modreq);
if (caps.isEmpty()) {
throw MESSAGES.cannotResolveInitialCapability(null, identifier);
}
XCapability icap = (XCapability) caps.iterator().next();
XResource resource = icap.getResource();
BundleContext syscontext = injectedSystemContext.getValue();
ResourceInstaller installer = injectedResourceInstaller.getValue();
XBundle bundle = installer.installModuleResource(syscontext, resource);
// Set the start level of the adapted bundle
Integer startlevel = configcap.getStartLevel();
if (startlevel != null && startlevel > 0) {
BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class);
bundleStartLevel.setStartLevel(startlevel);
}
return bundle;
}
private Deployment getInitialBundleDeployment(OSGiCapability configcap) throws Exception {
String identifier = configcap.getIdentifier();
Integer level = configcap.getStartLevel();
Deployment deployment = null;
// Try the identifier as ModuleIdentifier
if (isValidModuleIdentifier(identifier)) {
ModuleIdentifier moduleId = ModuleIdentifier.fromString(identifier);
// Attempt to install the bundle from the bundles hierarchy
File bundleFile = getModuleIdentityRepository().getRepositoryEntry(bundlesPath, moduleId);
if (bundleFile != null) {
LOGGER.tracef("Installing initial bundle capability: %s", identifier);
URL bundleURL = bundleFile.toURI().toURL();
deployment = getDeploymentFromURL(bundleURL, identifier, level);
}
}
// Try the identifier as MavenCoordinates
else if (isValidMavenIdentifier(identifier)) {
LOGGER.tracef("Installing initial maven capability: %s", identifier);
MavenCoordinates mavenId = MavenCoordinates.parse(identifier);
Requirement req = XRequirementBuilder.create(mavenId).getRequirement();
Collection<Capability> caps = getMavenIdentityRepository().findProviders(req);
if (caps.isEmpty() == false) {
XResource resource = (XResource) caps.iterator().next().getResource();
XCapability ccap = (XCapability) resource.getCapabilities(ContentNamespace.CONTENT_NAMESPACE).get(0);
URL bundleURL = new URL((String) ccap.getAttribute(ContentNamespace.CAPABILITY_URL_ATTRIBUTE));
deployment = getDeploymentFromURL(bundleURL, identifier, level);
}
}
if (deployment == null)
throw MESSAGES.cannotResolveInitialCapability(null, identifier);
return deployment;
}
private ModuleIdentityRepositoryIntegration getModuleIdentityRepository() {
XRepository repository = injectedRepository.getValue();
return repository.adapt(ModuleIdentityRepositoryIntegration.class);
}
private MavenIdentityRepository getMavenIdentityRepository() {
XRepository repository = injectedRepository.getValue();
return repository.adapt(MavenIdentityRepository.class);
}
private boolean isValidModuleIdentifier(String identifier) {
try {
ModuleIdentifier.fromString(identifier);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
private boolean isValidMavenIdentifier(String identifier) {
try {
MavenCoordinates.parse(identifier);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
private Deployment getDeploymentFromURL(URL bundleURL, String location, Integer level) throws Exception {
BundleInfo info = BundleInfo.createBundleInfo(AbstractVFS.toVirtualFile(bundleURL), location);
Deployment dep = DeploymentFactory.createDeployment(info);
int startlevel = level != null ? level.intValue() : 0;
if (startlevel > 0) {
dep.setStartLevel(level.intValue());
dep.setAutoStart(true);
}
StorageManager storageManager = injectedStorageManager.getValue();
Long bundleId = injectedEnvironment.getValue().nextResourceIdentifier(null, dep.getSymbolicName());
StorageState storageState = storageManager.createStorageState(bundleId, location, startlevel, null);
dep.putAttachment(STORAGE_STATE_KEY, storageState);
return dep;
}
class BootstrapResolveIntegration extends BootstrapBundlesResolve<Void> {
BootstrapResolveIntegration(ServiceName baseName, Set<XBundleRevision> installedRevisions) {
super(baseName, installedRevisions);
}
@Override
protected ServiceController<Void> installActivateService(ServiceTarget serviceTarget, Set<XBundle> resolvedBundles) {
return new BootstrapActivateIntegration(getServiceName().getParent(), resolvedBundles).install(serviceTarget, getServiceListener());
}
}
class BootstrapActivateIntegration extends BootstrapBundlesActivate<Void> {
BootstrapActivateIntegration(ServiceName baseName, Set<XBundle> resolvedBundles) {
super(baseName, resolvedBundles);
}
@Override
public void start(StartContext context) throws StartException {
// Start the module capabilities that have a start level assigned
BundleManager bundleManager = injectedBundleManager.getValue();
for (OSGiCapability modcap : modulecaps) {
if (modcap.getStartLevel() != null) {
String identifier = modcap.getIdentifier();
XBundle bundle = bundleManager.getBundleByLocation(identifier);
try {
bundle.start(Bundle.START_ACTIVATION_POLICY);
} catch (BundleException ex) {
LOGGER.errorCannotStartBundle(ex, bundle);
}
}
}
// Start the bundle capabilities
super.start(context);
}
}
}