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 */ 017package org.apache.logging.log4j.util; 018 019import java.net.URL; 020import java.security.Permission; 021import java.util.Collection; 022import java.util.List; 023 024import org.apache.logging.log4j.Logger; 025import org.apache.logging.log4j.spi.LoggerContextFactory; 026import org.apache.logging.log4j.spi.Provider; 027import org.apache.logging.log4j.status.StatusLogger; 028import org.osgi.framework.AdaptPermission; 029import org.osgi.framework.AdminPermission; 030import org.osgi.framework.Bundle; 031import org.osgi.framework.BundleActivator; 032import org.osgi.framework.BundleContext; 033import org.osgi.framework.BundleEvent; 034import org.osgi.framework.InvalidSyntaxException; 035import org.osgi.framework.ServiceReference; 036import org.osgi.framework.SynchronousBundleListener; 037import org.osgi.framework.wiring.BundleWire; 038import org.osgi.framework.wiring.BundleWiring; 039 040/** 041 * <em>Consider this class private.</em> 042 * OSGi bundle activator. Used for locating an implementation of 043 * {@link org.apache.logging.log4j.spi.LoggerContextFactory} et al. that have corresponding 044 * {@code META-INF/log4j-provider.properties} files. As with all OSGi BundleActivator classes, this class is not for 045 * public use and is only useful in an OSGi framework environment. 046 */ 047public class Activator implements BundleActivator, SynchronousBundleListener { 048 049 private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); 050 051 private static final Logger LOGGER = StatusLogger.getLogger(); 052 053 // until we have at least one Provider, we'll lock ProviderUtil which locks LogManager.<clinit> by extension. 054 // this variable needs to be reset once the lock has been released 055 private boolean lockingProviderUtil; 056 057 private static void checkPermission(final Permission permission) { 058 if (SECURITY_MANAGER != null) { 059 SECURITY_MANAGER.checkPermission(permission); 060 } 061 } 062 063 private void loadProvider(final Bundle bundle) { 064 if (bundle.getState() == Bundle.UNINSTALLED) { 065 return; 066 } 067 try { 068 checkPermission(new AdminPermission(bundle, AdminPermission.RESOURCE)); 069 checkPermission(new AdaptPermission(BundleWiring.class.getName(), bundle, AdaptPermission.ADAPT)); 070 loadProvider(bundle.getBundleContext(), bundle.adapt(BundleWiring.class)); 071 } catch (final SecurityException e) { 072 LOGGER.debug("Cannot access bundle [{}] contents. Ignoring.", bundle.getSymbolicName(), e); 073 } catch (final Exception e) { 074 LOGGER.warn("Problem checking bundle {} for Log4j 2 provider.", bundle.getSymbolicName(), e); 075 } 076 } 077 078 private void loadProvider(final BundleContext context, final BundleWiring bundleWiring) { 079 final String filter = "(APIVersion>=2.60)"; 080 try { 081 final Collection<ServiceReference<Provider>> serviceReferences = context.getServiceReferences(Provider.class, filter); 082 Provider maxProvider = null; 083 for (final ServiceReference<Provider> serviceReference : serviceReferences) { 084 final Provider provider = context.getService(serviceReference); 085 if (maxProvider == null || provider.getPriority() > maxProvider.getPriority()) { 086 maxProvider = provider; 087 } 088 } 089 if (maxProvider != null) { 090 ProviderUtil.addProvider(maxProvider); 091 } 092 } catch (final InvalidSyntaxException ex) { 093 LOGGER.error("Invalid service filter: " + filter, ex); 094 } 095 final List<URL> urls = bundleWiring.findEntries("META-INF", "log4j-provider.properties", 0); 096 for (final URL url : urls) { 097 ProviderUtil.loadProvider(url, bundleWiring.getClassLoader()); 098 } 099 } 100 101 @Override 102 public void start(final BundleContext context) throws Exception { 103 ProviderUtil.STARTUP_LOCK.lock(); 104 lockingProviderUtil = true; 105 final BundleWiring self = context.getBundle().adapt(BundleWiring.class); 106 final List<BundleWire> required = self.getRequiredWires(LoggerContextFactory.class.getName()); 107 for (final BundleWire wire : required) { 108 loadProvider(context, wire.getProviderWiring()); 109 } 110 context.addBundleListener(this); 111 final Bundle[] bundles = context.getBundles(); 112 for (final Bundle bundle : bundles) { 113 loadProvider(bundle); 114 } 115 unlockIfReady(); 116 } 117 118 private void unlockIfReady() { 119 if (lockingProviderUtil && !ProviderUtil.PROVIDERS.isEmpty()) { 120 ProviderUtil.STARTUP_LOCK.unlock(); 121 lockingProviderUtil = false; 122 } 123 } 124 125 @Override 126 public void stop(final BundleContext context) throws Exception { 127 context.removeBundleListener(this); 128 unlockIfReady(); 129 } 130 131 @Override 132 public void bundleChanged(final BundleEvent event) { 133 switch (event.getType()) { 134 case BundleEvent.STARTED: 135 loadProvider(event.getBundle()); 136 unlockIfReady(); 137 break; 138 139 default: 140 break; 141 } 142 } 143 144}