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    package org.apache.logging.log4j.util;
018    
019    import java.net.URL;
020    import java.security.Permission;
021    import java.util.List;
022    
023    import org.apache.logging.log4j.Logger;
024    import org.apache.logging.log4j.spi.LoggerContextFactory;
025    import org.apache.logging.log4j.status.StatusLogger;
026    import org.osgi.framework.AdaptPermission;
027    import org.osgi.framework.AdminPermission;
028    import org.osgi.framework.Bundle;
029    import org.osgi.framework.BundleActivator;
030    import org.osgi.framework.BundleContext;
031    import org.osgi.framework.BundleEvent;
032    import org.osgi.framework.SynchronousBundleListener;
033    import org.osgi.framework.wiring.BundleWire;
034    import org.osgi.framework.wiring.BundleWiring;
035    
036    /**
037     * OSGi bundle activator. Used for locating an implementation of
038     * {@link org.apache.logging.log4j.spi.LoggerContextFactory} et al. that have corresponding
039     * {@code META-INF/log4j-provider.properties} files. As with all OSGi BundleActivator classes, this class is not for
040     * public use and is only useful in an OSGi framework environment.
041     */
042    public class Activator implements BundleActivator, SynchronousBundleListener {
043    
044        private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager();
045    
046        private static final Logger LOGGER = StatusLogger.getLogger();
047    
048        private static void checkPermission(final Permission permission) {
049            if (SECURITY_MANAGER != null) {
050                SECURITY_MANAGER.checkPermission(permission);
051            }
052        }
053    
054        private void loadProvider(final Bundle bundle) {
055            if (bundle.getState() == Bundle.UNINSTALLED) {
056                return;
057            }
058            try {
059                checkPermission(new AdminPermission(bundle, AdminPermission.RESOURCE));
060                checkPermission(new AdaptPermission(BundleWiring.class.getName(), bundle, AdaptPermission.ADAPT));
061                loadProvider(bundle.adapt(BundleWiring.class));
062            } catch (final SecurityException e) {
063                LOGGER.debug("Cannot access bundle [{}] contents. Ignoring.", bundle.getSymbolicName(), e);
064            } catch (final Exception e) {
065                LOGGER.warn("Problem checking bundle {} for Log4j 2 provider.", bundle.getSymbolicName(), e);
066            }
067        }
068    
069        private void loadProvider(BundleWiring provider) {
070            final List<URL> urls = provider.findEntries("META-INF", "log4j-provider.properties", 0);
071            for (final URL url : urls) {
072                ProviderUtil.loadProvider(url, provider.getClassLoader());
073            }
074        }
075    
076        @Override
077        public void start(final BundleContext context) throws Exception {
078            final BundleWiring self = context.getBundle().adapt(BundleWiring.class);
079            final List<BundleWire> required = self.getRequiredWires(LoggerContextFactory.class.getName());
080            for (BundleWire wire : required) {
081                loadProvider(wire.getProviderWiring());
082            }
083            context.addBundleListener(this);
084            final Bundle[] bundles = context.getBundles();
085            for (final Bundle bundle : bundles) {
086                loadProvider(bundle);
087            }
088        }
089    
090        @Override
091        public void stop(final BundleContext context) throws Exception {
092            context.removeBundleListener(this);
093        }
094    
095        @Override
096        public void bundleChanged(final BundleEvent event) {
097            switch (event.getType()) {
098                case BundleEvent.STARTED:
099                    // FIXME: LogManager won't see this update if it happens after LogManager is loaded
100                    loadProvider(event.getBundle());
101                    break;
102    
103                default:
104                    break;
105            }
106        }
107    
108    }