| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.logging.log4j.core.config; |
| |
| import org.apache.logging.log4j.Logger; |
| import org.apache.logging.log4j.core.config.plugins.PluginManager; |
| import org.apache.logging.log4j.core.config.plugins.PluginType; |
| import org.apache.logging.log4j.core.helpers.FileUtils; |
| import org.apache.logging.log4j.core.helpers.Loader; |
| import org.apache.logging.log4j.status.StatusLogger; |
| import org.xml.sax.InputSource; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.MalformedURLException; |
| import java.net.URI; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| /** |
| * ConfigurationFactory allows the configuration implementation to be dynamically chosen in 1 |
| * of 3 ways: |
| * 1. A system property named "log4j.configurationFactory" can be set with the name of the |
| * ConfigurationFactory to be used. |
| * 2. setConfigurationFactory can be called with the instance of the ConfigurationFactory to |
| * be used. This must be called before any other calls to Log4j. |
| * 3. A ConfigurationFactory implementation can be added to the classpath and configured as a |
| * plugin. The Order annotation should be used to configure the factory to be the first one |
| * inspected. See XMLConfigurationFactory for an example. |
| * |
| * If the ConfigurationFactory that was added returns null on a call to getConfiguration the |
| * any other ConfigurationFactories found as plugins will be called in their respective order. |
| * DefaultConfiguration is always called last if no configuration has been returned. |
| */ |
| public abstract class ConfigurationFactory { |
| /** |
| * Allow the ConfigurationFactory class to be specified as a system property. |
| */ |
| public static final String CONFIGURATION_FACTORY_PROPERTY = "log4j.configurationFactory"; |
| |
| /** |
| * Allow the location of the configuration file to be specified as a system property. |
| */ |
| public static final String CONFIGURATION_FILE_PROPERTY = "log4j.configurationFile"; |
| |
| /** |
| * Allow subclasses access to the status logger without creating another instance. |
| */ |
| protected static final Logger LOGGER = StatusLogger.getLogger(); |
| |
| /** |
| * File name prefix for test configurations. |
| */ |
| protected static final String TEST_PREFIX = "log4j2-test"; |
| |
| /** |
| * File name prefix for standard configurations. |
| */ |
| protected static final String DEFAULT_PREFIX = "log4j2"; |
| |
| private static List<ConfigurationFactory> factories = new ArrayList<ConfigurationFactory>(); |
| |
| private static ConfigurationFactory configFactory = new Factory(); |
| |
| /** |
| * The configuration File. |
| */ |
| protected File configFile = null; |
| |
| /** |
| * Return the ConfigurationFactory. |
| * @return the ConfigurationFactory. |
| */ |
| public static ConfigurationFactory getInstance() { |
| String factoryClass = System.getProperty(CONFIGURATION_FACTORY_PROPERTY); |
| if (factoryClass != null) { |
| addFactory(factoryClass); |
| } |
| PluginManager manager = new PluginManager("ConfigurationFactory"); |
| manager.collectPlugins(); |
| Map<String, PluginType> plugins = manager.getPlugins(); |
| Set<WeightedFactory> ordered = new TreeSet<WeightedFactory>(); |
| for (PluginType type : plugins.values()) { |
| try { |
| Class<ConfigurationFactory> clazz = type.getPluginClass(); |
| Order o = clazz.getAnnotation(Order.class); |
| Integer weight = o.value(); |
| if (o != null) { |
| ordered.add(new WeightedFactory(weight, clazz)); |
| } |
| } catch (Exception ex) { |
| LOGGER.warn("Unable to add class " + type.getPluginClass()); |
| } |
| } |
| for (WeightedFactory wf : ordered) { |
| addFactory(wf.factoryClass); |
| } |
| return configFactory; |
| } |
| |
| private static void addFactory(String factoryClass) { |
| try { |
| Class clazz = Class.forName(factoryClass); |
| addFactory(clazz); |
| } catch (ClassNotFoundException ex) { |
| LOGGER.error("Unable to load class " + factoryClass, ex); |
| } catch (Exception ex) { |
| LOGGER.error("Unable to load class " + factoryClass, ex); |
| } |
| } |
| |
| private static void addFactory(Class factoryClass) { |
| try { |
| factories.add((ConfigurationFactory) factoryClass.newInstance()); |
| } catch (Exception ex) { |
| LOGGER.error("Unable to create instance of " + factoryClass.getName(), ex); |
| } |
| } |
| |
| /** |
| * Set the configuration factory. |
| * @param factory the ConfigurationFactory. |
| */ |
| public static void setConfigurationFactory(ConfigurationFactory factory) { |
| configFactory = factory; |
| } |
| |
| /** |
| * Reset the ConfigurationFactory to the default. |
| */ |
| public static void resetConfigurationFactory() { |
| configFactory = new Factory(); |
| } |
| |
| /** |
| * Remove the ConfigurationFactory. |
| * @param factory The factory to remove. |
| */ |
| public static void removeConfigurationFactory(ConfigurationFactory factory) { |
| factories.remove(factory); |
| } |
| |
| protected abstract String[] getSupportedTypes(); |
| |
| protected boolean isActive() { |
| return true; |
| } |
| |
| public abstract Configuration getConfiguration(InputSource source); |
| |
| /** |
| * Return the Configuration. |
| * @param name The configuration name. |
| * @param configLocation The configuration location. |
| * @return The Configuration. |
| */ |
| public Configuration getConfiguration(String name, URI configLocation) { |
| if (!isActive()) { |
| return null; |
| } |
| if (configLocation != null) { |
| InputSource source = getInputFromURI(configLocation); |
| if (source != null) { |
| return getConfiguration(source); |
| } |
| } |
| return null; |
| } |
| |
| protected InputSource getInputFromURI(URI configLocation) { |
| configFile = FileUtils.fileFromURI(configLocation); |
| if (configFile != null && configFile.exists() && configFile.canRead()) { |
| try { |
| InputSource source = new InputSource(new FileInputStream(configFile)); |
| source.setSystemId(configLocation.getPath()); |
| return source; |
| } catch (FileNotFoundException ex) { |
| LOGGER.error("Cannot locate file " + configLocation.getPath(), ex); |
| } |
| } |
| try { |
| InputSource source = new InputSource(configLocation.toURL().openStream()); |
| source.setSystemId(configLocation.getPath()); |
| return source; |
| } catch (MalformedURLException ex) { |
| LOGGER.error("Invalid URL " + configLocation.toString(), ex); |
| } catch (IOException ex) { |
| LOGGER.error("Unable to access " + configLocation.toString(), ex); |
| } |
| return null; |
| } |
| |
| protected InputSource getInputFromString(ClassLoader loader, String configFile) { |
| InputSource source; |
| try { |
| URL url = new URL(configFile); |
| source = new InputSource(url.openStream()); |
| source.setSystemId(configFile); |
| return source; |
| } catch (Exception ex) { |
| source = getInputFromResource(configFile, loader); |
| if (source == null) { |
| try { |
| InputStream is = new FileInputStream(configFile); |
| source = new InputSource(is); |
| source.setSystemId(configFile); |
| } catch (FileNotFoundException fnfe) { |
| // Ignore the exception |
| } |
| } |
| } |
| return source; |
| } |
| |
| protected InputSource getInputFromResource(String resource, ClassLoader loader) { |
| InputStream is = Loader.getResourceAsStream(resource, loader); |
| if (is == null) { |
| return null; |
| } |
| InputSource source = new InputSource(is); |
| source.setSystemId(resource); |
| return source; |
| } |
| |
| /** |
| * Factory that chooses a ConfigurationFactory based on weighting. |
| */ |
| private static class WeightedFactory implements Comparable<WeightedFactory> { |
| private int weight; |
| private Class<ConfigurationFactory> factoryClass; |
| |
| /** |
| * Constructor. |
| * @param weight The weight. |
| * @param clazz The class. |
| */ |
| public WeightedFactory(int weight, Class<ConfigurationFactory> clazz) { |
| this.weight = weight; |
| this.factoryClass = clazz; |
| } |
| |
| public int compareTo(WeightedFactory wf) { |
| int w = wf.weight; |
| if (weight == w) { |
| return 0; |
| } else if (weight > w) { |
| return -1; |
| } else { |
| return 1; |
| } |
| } |
| } |
| |
| /** |
| * Default Factory. |
| */ |
| private static class Factory extends ConfigurationFactory { |
| |
| /** |
| * Default Factory Constructor. |
| * @param name The configuration name. |
| * @param configLocation The configuration location. |
| * @return The Configuration. |
| */ |
| public Configuration getConfiguration(String name, URI configLocation) { |
| |
| if (configLocation == null) { |
| String config = System.getProperty(CONFIGURATION_FILE_PROPERTY); |
| if (config != null) { |
| ClassLoader loader = this.getClass().getClassLoader(); |
| InputSource source = getInputFromString(loader, config); |
| if (source != null) { |
| for (ConfigurationFactory factory : factories) { |
| String[] types = factory.getSupportedTypes(); |
| if (types != null) { |
| for (String type : types) { |
| if (type.equals("*") || config.endsWith(type)) { |
| Configuration c = factory.getConfiguration(source); |
| if (c != null) { |
| return c; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } else { |
| for (ConfigurationFactory factory : factories) { |
| Configuration config = factory.getConfiguration(name, configLocation); |
| if (config != null) { |
| return config; |
| } |
| } |
| } |
| |
| Configuration config = getConfiguration(true, name); |
| if (config == null) { |
| config = getConfiguration(true, null); |
| if (config == null) { |
| config = getConfiguration(false, name); |
| if (config == null) { |
| config = getConfiguration(false, null); |
| } |
| } |
| } |
| return config != null ? config : new DefaultConfiguration(); |
| } |
| |
| private Configuration getConfiguration(boolean isTest, String name) { |
| boolean named = (name != null && name.length() > 0); |
| ClassLoader loader = this.getClass().getClassLoader(); |
| for (ConfigurationFactory factory : factories) { |
| String configName; |
| String prefix = isTest ? TEST_PREFIX : DEFAULT_PREFIX; |
| String [] types = factory.getSupportedTypes(); |
| if (types == null) { |
| continue; |
| } |
| |
| for (String suffix : types) { |
| if (suffix.equals("*")) { |
| continue; |
| } |
| configName = named ? prefix + name + suffix : prefix + suffix; |
| |
| InputSource source = getInputFromResource(configName, loader); |
| if (source != null) { |
| return factory.getConfiguration(source); |
| } |
| } |
| } |
| return null; |
| } |
| |
| public String[] getSupportedTypes() { |
| return null; |
| } |
| |
| public Configuration getConfiguration(InputSource source) { |
| return null; |
| } |
| } |
| } |