/*
* #%L
* Gravia :: Provision
* %%
* Copyright (C) 2013 - 2014 JBoss by Red Hat
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.jboss.gravia.provision.internal;
import static org.jboss.gravia.provision.spi.ProvisionLogger.LOGGER;
import org.jboss.gravia.provision.ProvisionException;
import org.jboss.gravia.provision.ResourceHandle;
import org.jboss.gravia.provision.spi.AbstractResourceHandle;
import org.jboss.gravia.provision.spi.AbstractResourceInstaller;
import org.jboss.gravia.provision.spi.RuntimeEnvironment;
import org.jboss.gravia.resource.Resource;
import org.jboss.gravia.resource.ResourceContent;
import org.jboss.gravia.resource.ResourceIdentity;
import org.jboss.gravia.runtime.Module;
import org.jboss.gravia.runtime.ModuleException;
import org.jboss.gravia.runtime.Runtime;
import org.jboss.gravia.runtime.RuntimeLocator;
import org.jboss.gravia.runtime.spi.ThreadResourceAssociation;
import org.jboss.gravia.utils.IllegalStateAssertion;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.wiring.BundleWiring;
public class BundleResourceInstaller extends AbstractResourceInstaller {
private final RuntimeEnvironment environment;
private final BundleContext context;
BundleResourceInstaller(BundleContext context, RuntimeEnvironment environment) {
this.context = context;
this.environment = environment;
}
@Override
public RuntimeEnvironment getEnvironment() {
return environment;
}
@Override
public ResourceHandle installResourceProtected(Context context, Resource resource) throws ProvisionException {
LOGGER.info("Installing resource: {}", resource);
return installBundleResource(resource);
}
private ResourceHandle installBundleResource(Resource resource) throws ProvisionException {
// Install the Bundle
ResourceIdentity resid = resource.getIdentity();
ResourceContent content = getFirstRelevantResourceContent(resource);
IllegalStateAssertion.assertNotNull(content.getContent(), "Cannot obtain content from: " + resource);
Bundle bundle;
try {
String location = "resource#" + resid;
bundle = context.installBundle(location, content.getContent());
} catch (BundleException ex) {
throw new ProvisionException(ex);
}
// Start the bundle. This relies on provision ordering.
ThreadResourceAssociation.putResource(resource);
try {
bundle.start();
} catch (BundleException ex) {
// The start exception must be reported back to the client
// WildFly also relies on provision ordering.
throw new ProvisionException(ex);
} finally {
ThreadResourceAssociation.removeResource();
}
// Install the bundle as module if it has not already happened
// A bundle that could not get resolved will not have an associated module
Runtime runtime = RuntimeLocator.getRequiredRuntime();
Module module = runtime.getModule(resid);
BundleWiring wiring = bundle.adapt(BundleWiring.class);
if (module == null && wiring != null) {
try {
ClassLoader classLoader = wiring.getClassLoader();
module = runtime.installModule(classLoader, resource, null);
} catch (ModuleException ex) {
throw new ProvisionException(ex);
}
}
// Installing a bundle does not trigger a {@link ModuleEvent#INSTALLED}
// event because the Bundle's class loader is not (yet) available
// We manually add the resource to the {@link RuntimeEnvironment}
// [TODO] Revisit {@link ModuleListener} handling for OSGi
Resource envres = environment.getResource(resid);
if (envres == null && module != null) {
RuntimeEnvironment runtimeEnv = RuntimeEnvironment.assertRuntimeEnvironment(environment);
runtimeEnv.addRuntimeResource(resource);
}
return new BundleResourceHandle(resource, module, bundle);
}
static class BundleResourceHandle extends AbstractResourceHandle {
private final Bundle bundle;
BundleResourceHandle(Resource resource, Module module, Bundle bundle) {
super(module.adapt(Resource.class), module);
this.bundle = bundle;
}
@Override
public void uninstall() {
try {
bundle.uninstall();
} catch (BundleException ex) {
LOGGER.warn("Cannot uninstall bundle: " + bundle, ex);
}
}
}
}