| /** |
| * 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.apache.aries.cdi.container.internal; |
| |
| import static org.osgi.namespace.extender.ExtenderNamespace.EXTENDER_NAMESPACE; |
| import static org.osgi.service.cdi.CDIConstants.CDI_CAPABILITY_NAME; |
| import static org.osgi.service.cdi.CDIConstants.REQUIREMENT_BEANS_ATTRIBUTE; |
| |
| import java.util.Dictionary; |
| import java.util.Hashtable; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Observable; |
| import java.util.Observer; |
| import java.util.concurrent.CopyOnWriteArrayList; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.apache.aries.cdi.container.internal.command.CDICommand; |
| import org.apache.aries.cdi.container.internal.container.CDIBundle; |
| import org.apache.aries.cdi.container.internal.container.ConfigurationListener; |
| import org.apache.aries.cdi.container.internal.container.ContainerBootstrap; |
| import org.apache.aries.cdi.container.internal.container.ContainerState; |
| import org.apache.aries.cdi.container.internal.container.ExtensionPhase; |
| import org.apache.aries.cdi.container.internal.model.ContainerActivator; |
| import org.apache.aries.cdi.container.internal.model.ContainerComponent; |
| import org.apache.aries.cdi.container.internal.model.FactoryActivator; |
| import org.apache.aries.cdi.container.internal.model.FactoryComponent; |
| import org.apache.aries.cdi.container.internal.model.SingleActivator; |
| import org.apache.aries.cdi.container.internal.model.SingleComponent; |
| import org.apache.aries.cdi.container.internal.spi.ContainerListener; |
| import org.apache.aries.cdi.container.internal.util.Logs; |
| import org.apache.aries.cdi.spi.CDIContainerInitializer; |
| import org.apache.felix.utils.extender.AbstractExtender; |
| import org.apache.felix.utils.extender.Extension; |
| import org.osgi.annotation.bundle.Header; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.ServiceFactory; |
| import org.osgi.framework.ServiceObjects; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.ServiceRegistration; |
| import org.osgi.framework.wiring.BundleRequirement; |
| import org.osgi.framework.wiring.BundleWire; |
| import org.osgi.framework.wiring.BundleWiring; |
| import org.osgi.service.cdi.runtime.CDIComponentRuntime; |
| import org.osgi.service.cm.ConfigurationAdmin; |
| import org.osgi.service.cm.annotations.RequireConfigurationAdmin; |
| import org.osgi.service.log.Logger; |
| import org.osgi.service.log.LoggerFactory; |
| import org.osgi.util.promise.PromiseFactory; |
| import org.osgi.util.tracker.ServiceTracker; |
| import org.osgi.util.tracker.ServiceTrackerCustomizer; |
| |
| @Header( |
| name = Constants.BUNDLE_ACTIVATOR, |
| value = "${@class}" |
| ) |
| @RequireConfigurationAdmin |
| public class Activator extends AbstractExtender { |
| |
| private volatile CCR _ccr; |
| private volatile ExecutorService _executorService; |
| private volatile Logger _log; |
| private volatile Logs _logs; |
| private volatile PromiseFactory _promiseFactory; |
| private volatile ServiceTracker<CDIContainerInitializer, ServiceObjects<CDIContainerInitializer>> _containerTracker; |
| private volatile ServiceTracker<ContainerListener, ContainerListener> _containerListeners; |
| |
| public Activator() { |
| setSynchronous(true); |
| } |
| |
| @Override |
| public void start(BundleContext bundleContext) throws Exception { |
| _logs = new Logs.Builder(bundleContext).build(); |
| _log = _logs.getLogger(Activator.class); |
| _containerTracker = new ServiceTracker<>( |
| bundleContext, CDIContainerInitializer.class, |
| new ServiceTrackerCustomizer<CDIContainerInitializer, ServiceObjects<CDIContainerInitializer>>() { |
| |
| @Override |
| public ServiceObjects<CDIContainerInitializer> addingService( |
| ServiceReference<CDIContainerInitializer> reference) { |
| |
| return bundleContext.getServiceObjects(reference); |
| } |
| |
| @Override |
| public void modifiedService(ServiceReference<CDIContainerInitializer> reference, |
| ServiceObjects<CDIContainerInitializer> service) { |
| } |
| |
| @Override |
| public void removedService(ServiceReference<CDIContainerInitializer> reference, |
| ServiceObjects<CDIContainerInitializer> service) { |
| } |
| } |
| ); |
| _containerTracker.open(); |
| |
| _containerListeners = new ServiceTracker<>(bundleContext, ContainerListener.class, null); |
| _containerListeners.open(); |
| |
| _executorService = Executors.newSingleThreadExecutor(worker -> { |
| Thread t = new Thread(new ThreadGroup("Apache Aries CCR - CDI"), worker, "Aries CCR Thread (" + hashCode() + ")"); |
| t.setDaemon(false); |
| return t; |
| }); |
| _promiseFactory = new PromiseFactory(_executorService); |
| _ccr = new CCR(_promiseFactory, _logs); |
| _command = new CDICommand(_ccr); |
| |
| if (_log.isDebugEnabled()) { |
| _log.debug("CCR starting {}", bundleContext.getBundle()); |
| } |
| |
| _bundleContext = bundleContext; |
| |
| registerCCR(); |
| registerCDICommand(); |
| |
| super.start(bundleContext); |
| |
| if (_log.isDebugEnabled()) { |
| _log.debug("CCR started {}", bundleContext.getBundle()); |
| } |
| } |
| |
| private void registerCCR() { |
| Dictionary<String, Object> properties = new Hashtable<>(); |
| properties.put(Constants.SERVICE_CHANGECOUNT, _ccrChangeCount.get()); |
| properties.put(Constants.SERVICE_DESCRIPTION, "Aries CDI - CDI Component Runtime"); |
| properties.put(Constants.SERVICE_VENDOR, "Apache Software Foundation"); |
| |
| ChangeObserverFactory changeObserverFactory = new ChangeObserverFactory(); |
| |
| _ccrChangeCount.addObserver(changeObserverFactory); |
| |
| _ccrRegistration = _bundleContext.registerService( |
| CDIComponentRuntime.class, changeObserverFactory, properties); |
| } |
| |
| private void registerCDICommand() { |
| Dictionary<String, Object> properties = new Hashtable<>(); |
| properties.put("osgi.command.scope", "cdi"); |
| properties.put("osgi.command.function", new String[] {"list", "info"}); |
| properties.put(Constants.SERVICE_DESCRIPTION, "Aries CDI - Gogo Commands"); |
| properties.put(Constants.SERVICE_VENDOR, "Apache Software Foundation"); |
| |
| _commandRegistration = _bundleContext.registerService(Object.class, _command, properties); |
| } |
| |
| @Override |
| public void stop(BundleContext bundleContext) throws Exception { |
| if (_log.isDebugEnabled()) { |
| _log.debug("CCR stoping {}", bundleContext.getBundle()); |
| } |
| |
| super.stop(bundleContext); |
| |
| _commandRegistration.unregister(); |
| _ccrRegistration.unregister(); |
| |
| if (_log.isDebugEnabled()) { |
| _log.debug("CCR stoped {}", bundleContext.getBundle()); |
| } |
| _executorService.shutdownNow(); |
| _executorService.awaitTermination(2, TimeUnit.SECONDS); // not important but just to avoid to quit too fast |
| |
| _containerTracker.close(); |
| _containerListeners.close(); |
| } |
| |
| @Override |
| protected Extension doCreateExtension(Bundle bundle) throws Exception { |
| if (!requiresCDIExtender(bundle)) { |
| return null; |
| } |
| |
| ServiceTracker<ConfigurationAdmin, ConfigurationAdmin> caTracker = new ServiceTracker<>( |
| bundle.getBundleContext(), ConfigurationAdmin.class, null); |
| |
| caTracker.open(); |
| |
| ServiceTracker<LoggerFactory, LoggerFactory> loggerTracker = new ServiceTracker<>( |
| bundle.getBundleContext(), LoggerFactory.class, null); |
| |
| loggerTracker.open(); |
| |
| ContainerState containerState = new ContainerState( |
| bundle, _bundleContext.getBundle(), _ccrChangeCount, _promiseFactory, caTracker, _logs); |
| |
| // the CDI bundle |
| return new CDIBundle(_ccr, containerState, |
| // handle extensions |
| new ExtensionPhase(containerState, |
| // listen for configurations of the container component |
| new ConfigurationListener.Builder(containerState).component( |
| // the container component |
| new ContainerComponent.Builder(containerState, |
| // when dependencies are satisfied activate the container |
| new ContainerActivator.Builder(containerState, |
| // when the active container bootstraps CDI |
| new ContainerBootstrap( |
| containerState, _containerTracker, |
| // when CDI is bootstrapping is complete and is up and running |
| // activate the configuration listeners for single and factory components |
| new ConfigurationListener.Builder(containerState), |
| new SingleComponent.Builder(containerState, |
| new SingleActivator.Builder(containerState)), |
| new FactoryComponent.Builder(containerState, |
| new FactoryActivator.Builder(containerState)), |
| _containerListeners |
| ) |
| ) |
| ).build() |
| ).build() |
| ) |
| ); |
| } |
| |
| @Override |
| protected void debug(Bundle bundle, String msg) { |
| if (_log.isTraceEnabled()) { |
| _log.trace(msg, bundle); |
| } |
| } |
| |
| @Override |
| protected void warn(Bundle bundle, String msg, Throwable t) { |
| if (_log.isWarnEnabled()) { |
| _log.warn(msg, bundle, t); |
| } |
| } |
| |
| @Override |
| protected void error(String msg, Throwable t) { |
| if (_log.isErrorEnabled()) { |
| _log.error(msg, t); |
| } |
| } |
| |
| private boolean requiresCDIExtender(Bundle bundle) { |
| BundleWiring bundleWiring = bundle.adapt(BundleWiring.class); |
| List<BundleWire> requiredBundleWires = bundleWiring.getRequiredWires(EXTENDER_NAMESPACE); |
| |
| for (BundleWire bundleWire : requiredBundleWires) { |
| Map<String, Object> attributes = bundleWire.getCapability().getAttributes(); |
| |
| if (attributes.containsKey(EXTENDER_NAMESPACE) && |
| attributes.get(EXTENDER_NAMESPACE).equals(CDI_CAPABILITY_NAME)) { |
| |
| Bundle providerWiringBundle = bundleWire.getProviderWiring().getBundle(); |
| |
| if (providerWiringBundle.equals(_bundleContext.getBundle())) { |
| BundleRequirement requirement = bundleWire.getRequirement(); |
| Map<String, Object> requirementAttributes = requirement.getAttributes(); |
| |
| @SuppressWarnings("unchecked") |
| List<String> beans = (List<String>)requirementAttributes.get(REQUIREMENT_BEANS_ATTRIBUTE); |
| |
| if (beans != null && !beans.isEmpty()) { |
| return true; |
| } |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| private BundleContext _bundleContext; |
| private final ChangeCount _ccrChangeCount = new ChangeCount(); |
| private ServiceRegistration<CDIComponentRuntime> _ccrRegistration; |
| private volatile CDICommand _command; |
| private ServiceRegistration<?> _commandRegistration; |
| |
| private class ChangeObserverFactory implements Observer, ServiceFactory<CDIComponentRuntime> { |
| |
| @Override |
| public CDIComponentRuntime getService( |
| Bundle bundle, |
| ServiceRegistration<CDIComponentRuntime> registration) { |
| |
| _registrations.add(registration); |
| |
| return _ccr; |
| } |
| |
| @Override |
| public void ungetService( |
| Bundle bundle, ServiceRegistration<CDIComponentRuntime> registration, |
| CDIComponentRuntime service) { |
| |
| _registrations.remove(registration); |
| } |
| |
| @Override |
| public void update(Observable o, Object arg) { |
| if (!(o instanceof ChangeCount)) { |
| return; |
| } |
| |
| ChangeCount changeCount = (ChangeCount)o; |
| |
| for (ServiceRegistration<CDIComponentRuntime> registration : _registrations) { |
| Dictionary<String, Object> properties = registration.getReference().getProperties(); |
| properties.put(Constants.SERVICE_CHANGECOUNT, changeCount.get()); |
| registration.setProperties(properties); |
| } |
| } |
| |
| private final List<ServiceRegistration<CDIComponentRuntime>> _registrations = new CopyOnWriteArrayList<>(); |
| |
| } |
| |
| } |