001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.logging.log4j.core.osgi;
019    
020    import java.util.concurrent.atomic.AtomicReference;
021    
022    import org.apache.logging.log4j.Logger;
023    import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
024    import org.apache.logging.log4j.core.util.BundleResourceLoader;
025    import org.apache.logging.log4j.status.StatusLogger;
026    import org.osgi.framework.Bundle;
027    import org.osgi.framework.BundleActivator;
028    import org.osgi.framework.BundleContext;
029    import org.osgi.framework.BundleEvent;
030    import org.osgi.framework.SynchronousBundleListener;
031    
032    /**
033     * OSGi BundleActivator.
034     */
035    public final class Activator implements BundleActivator, SynchronousBundleListener {
036    
037        private static final Logger LOGGER = StatusLogger.getLogger();
038    
039        private final AtomicReference<BundleContext> context = new AtomicReference<BundleContext>();
040    
041        @Override
042        public void start(final BundleContext context) throws Exception {
043            if (this.context.compareAndSet(null, context)) {
044                context.addBundleListener(this);
045                // done after the BundleListener as to not miss any new bundle installs in the interim
046                scanInstalledBundlesForPlugins(context);
047            }
048        }
049    
050        private static void scanInstalledBundlesForPlugins(final BundleContext context) {
051            final Bundle[] bundles = context.getBundles();
052            for (final Bundle bundle : bundles) {
053                if (bundle.getState() == Bundle.ACTIVE) {
054                    // TODO: bundle state can change during this
055                    scanBundleForPlugins(bundle);
056                }
057            }
058        }
059    
060        private static void scanBundleForPlugins(final Bundle bundle) {
061            LOGGER.trace("Scanning bundle [{}] for plugins.", bundle.getSymbolicName());
062            PluginManager.loadPlugins(new BundleResourceLoader(bundle));
063        }
064    
065        @Override
066        public void stop(final BundleContext context) throws Exception {
067            // not much can be done that isn't already automated by the framework
068            this.context.compareAndSet(context, null);
069        }
070    
071        @Override
072        public void bundleChanged(BundleEvent event) {
073            switch (event.getType()) {
074                case BundleEvent.STARTED:
075                    scanBundleForPlugins(event.getBundle());
076                    break;
077    
078                default:
079                    break;
080            }
081        }
082    }