/* * Copyright 2012 Harald Wellmann. * * 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. */ package org.ops4j.pax.cdi.weld.impl; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.event.Event; import javax.enterprise.inject.Instance; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.InjectionTarget; import org.jboss.weld.bootstrap.WeldBootstrap; import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive; import org.jboss.weld.config.ConfigurationKey; import org.jboss.weld.configuration.spi.ExternalConfiguration; import org.jboss.weld.configuration.spi.helpers.ExternalConfigurationBuilder; import org.jboss.weld.manager.BeanManagerImpl; import org.jboss.weld.serialization.spi.ProxyServices; import org.ops4j.pax.cdi.spi.AbstractCdiContainer; import org.ops4j.pax.cdi.spi.DestroyedLiteral; import org.ops4j.pax.cdi.spi.InitializedLiteral; import org.ops4j.pax.cdi.spi.util.Exceptions; import org.ops4j.pax.cdi.weld.impl.bda.BundleDeployment; import org.ops4j.pax.cdi.weld.impl.util.OsgiProxyService; import org.osgi.framework.Bundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@code CdiContainer} implementation wrapping a JBoss Weld container, represented by a * {@link WeldBootstrap}. * * @author Harald Wellmann * */ public class WeldCdiContainer extends AbstractCdiContainer { private Logger log = LoggerFactory.getLogger(WeldCdiContainer.class); /** * Helper for accessing Instance and Event of CDI container. */ private InstanceManager instanceManager; private WeldBootstrap bootstrap; private BeanManagerImpl manager; private Object environment; private AtomicInteger pauses = new AtomicInteger(); /** * Construct a CDI container for the given extended bundle. * * @param ownBundle * bundle containing this class * @param bundle * bundle to be extended with CDI container * @param extensionBundles * CDI extension bundles to be loaded by OpenWebBeans */ public WeldCdiContainer(Bundle ownBundle, Bundle bundle, Collection<Bundle> extensionBundles) { super(bundle, extensionBundles, Collections.singletonList(ownBundle)); log.debug("creating Weld CDI container for bundle {}", bundle); } @Override protected void doStart(Object start) { this.environment = start; try { doWithClassLoader(new Callable<Object>() { @Override public Object call() throws Exception { createBeanManager(); return null; } }); } // CHECKSTYLE:SKIP catch (Exception exc) { throw Exceptions.unchecked(exc); } } private void createBeanManager() { bootstrap = new WeldBootstrap(); BundleDeployment deployment = new BundleDeployment(getBundle(), bootstrap, getContextClassLoader()); BeanDeploymentArchive beanDeploymentArchive = deployment.getBeanDeploymentArchive(); pause(); String contextId = getBundle().getSymbolicName() + ":" + getBundle().getBundleId(); ExternalConfigurationBuilder configurationBuilder = new ExternalConfigurationBuilder() // Use relaxed construction by default .add(ConfigurationKey.RELAXED_CONSTRUCTION.get(), true) .add(ConfigurationKey.CONCURRENT_DEPLOYMENT.get(), false); deployment.getServices() .add(ExternalConfiguration.class, configurationBuilder.build()); bootstrap.startContainer(contextId, OsgiEnvironment.getInstance(), deployment); // Add the ProxyServices service: we rely on the BeanManager to use its annotated // types cache to discover type closures which is required for proxied beans // whose type closures span multiple bundles deployment.getServices() .add(ProxyServices.class, new OsgiProxyService( bootstrap.getManager(beanDeploymentArchive), getContextClassLoader())); bootstrap.startInitialization(); bootstrap.deployBeans(); bootstrap.validateBeans(); manager = bootstrap.getManager(beanDeploymentArchive); resume(); } @Override public void pause() { pauses.incrementAndGet(); } @Override public void resume() { if (pauses.decrementAndGet() == 0) { try { doWithClassLoader(new Callable<Object>() { @Override public Object call() throws Exception { bootstrap.endInitialization(); manager.fireEvent(environment, InitializedLiteral.APPLICATION); return null; } }); } // CHECKSTYLE:SKIP catch (Exception exc) { throw Exceptions.unchecked(exc); } } } @Override public void doStop() { try { doWithClassLoader(new Callable<Object>() { @Override public Object call() throws Exception { manager.fireEvent(environment, DestroyedLiteral.APPLICATION); bootstrap.shutdown(); return null; } }); } // CHECKSTYLE:SKIP catch (Exception exc) { throw Exceptions.unchecked(exc); } } @Override public Event<Object> getEvent() { return getInstanceManager().getEvent(); } @Override public BeanManager getBeanManager() { return manager; } @Override public Instance<Object> getInstance() { return getInstanceManager().getInstance(); } private InstanceManager getInstanceManager() { if (instanceManager == null) { BeanManager beanManager = getBeanManager(); instanceManager = new InstanceManager(); AnnotatedType<InstanceManager> annotatedType = beanManager .createAnnotatedType(InstanceManager.class); InjectionTarget<InstanceManager> target = beanManager .createInjectionTarget(annotatedType); CreationalContext<InstanceManager> cc = beanManager.createCreationalContext(null); target.inject(instanceManager, cc); } return instanceManager; } @Override public <T> T unwrap(Class<T> wrappedClass) { if (wrappedClass.isAssignableFrom(WeldBootstrap.class)) { return wrappedClass.cast(bootstrap); } if (wrappedClass.isAssignableFrom(BeanManagerImpl.class)) { return wrappedClass.cast(manager); } return null; } @Override public void startContext(Class<? extends Annotation> scope) { throw new UnsupportedOperationException("not yet implemented"); } @Override public void stopContext(Class<? extends Annotation> scope) { throw new UnsupportedOperationException("not yet implemented"); } }