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 // until we have at least one Provider, we'll lock ProviderUtil which locks LogManager.<clinit> by extension.
049 // this variable needs to be reset once the lock has been released
050 private boolean lockingProviderUtil;
051
052 private static void checkPermission(final Permission permission) {
053 if (SECURITY_MANAGER != null) {
054 SECURITY_MANAGER.checkPermission(permission);
055 }
056 }
057
058 private void loadProvider(final Bundle bundle) {
059 if (bundle.getState() == Bundle.UNINSTALLED) {
060 return;
061 }
062 try {
063 checkPermission(new AdminPermission(bundle, AdminPermission.RESOURCE));
064 checkPermission(new AdaptPermission(BundleWiring.class.getName(), bundle, AdaptPermission.ADAPT));
065 loadProvider(bundle.adapt(BundleWiring.class));
066 } catch (final SecurityException e) {
067 LOGGER.debug("Cannot access bundle [{}] contents. Ignoring.", bundle.getSymbolicName(), e);
068 } catch (final Exception e) {
069 LOGGER.warn("Problem checking bundle {} for Log4j 2 provider.", bundle.getSymbolicName(), e);
070 }
071 }
072
073 private void loadProvider(final BundleWiring provider) {
074 final List<URL> urls = provider.findEntries("META-INF", "log4j-provider.properties", 0);
075 for (final URL url : urls) {
076 ProviderUtil.loadProvider(url, provider.getClassLoader());
077 }
078 }
079
080 @Override
081 public void start(final BundleContext context) throws Exception {
082 ProviderUtil.STARTUP_LOCK.lock();
083 lockingProviderUtil = true;
084 final BundleWiring self = context.getBundle().adapt(BundleWiring.class);
085 final List<BundleWire> required = self.getRequiredWires(LoggerContextFactory.class.getName());
086 for (final BundleWire wire : required) {
087 loadProvider(wire.getProviderWiring());
088 }
089 context.addBundleListener(this);
090 final Bundle[] bundles = context.getBundles();
091 for (final Bundle bundle : bundles) {
092 loadProvider(bundle);
093 }
094 unlockIfReady();
095 }
096
097 private void unlockIfReady() {
098 if (lockingProviderUtil && !ProviderUtil.PROVIDERS.isEmpty()) {
099 ProviderUtil.STARTUP_LOCK.unlock();
100 lockingProviderUtil = false;
101 }
102 }
103
104 @Override
105 public void stop(final BundleContext context) throws Exception {
106 context.removeBundleListener(this);
107 unlockIfReady();
108 }
109
110 @Override
111 public void bundleChanged(final BundleEvent event) {
112 switch (event.getType()) {
113 case BundleEvent.STARTED:
114 loadProvider(event.getBundle());
115 unlockIfReady();
116 break;
117
118 default:
119 break;
120 }
121 }
122
123 }