001/* 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2026, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v2.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014 015package ch.qos.logback.classic.util; 016 017import ch.qos.logback.classic.ClassicConstants; 018import ch.qos.logback.classic.LoggerContext; 019import ch.qos.logback.classic.joran.JoranConfigurator; 020import ch.qos.logback.classic.spi.ConfiguratorRank; 021import ch.qos.logback.core.Context; 022import ch.qos.logback.core.LogbackException; 023import ch.qos.logback.core.joran.spi.JoranException; 024import ch.qos.logback.classic.spi.Configurator; 025import ch.qos.logback.core.spi.ContextAwareBase; 026import ch.qos.logback.core.status.InfoStatus; 027import ch.qos.logback.core.status.StatusManager; 028import ch.qos.logback.core.util.Loader; 029import ch.qos.logback.core.util.OptionHelper; 030 031import java.io.File; 032import java.io.IOException; 033import java.net.MalformedURLException; 034import java.net.URL; 035import java.util.Set; 036 037/** 038 * @since 1.3.0-beta1 039 */ 040// Note that DefaultJoranConfigurator is invoked via reflection 041@ConfiguratorRank(value = ConfiguratorRank.NOMINAL) 042public class DefaultJoranConfigurator extends ContextAwareBase implements Configurator { 043 044 @Override 045 public ExecutionStatus configure(LoggerContext context) { 046 URL url = performMultiStepConfigurationFileSearch(true); 047 if (url != null) { 048 try { 049 configureByResource(url); 050 } catch (JoranException e) { 051 e.printStackTrace(); 052 } 053 // You tried and that counts Mary. 054 return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY; 055 } else { 056 return ExecutionStatus.INVOKE_NEXT_IF_ANY; 057 } 058 } 059 060 private URL performMultiStepConfigurationFileSearch(boolean updateStatus) { 061 ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this); 062 URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus); 063 if (url != null) { 064 return url; 065 } 066 067 url = getResource(ClassicConstants.TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus); 068 if (url != null) { 069 return url; 070 } 071 072 return getResource(ClassicConstants.AUTOCONFIG_FILE, myClassLoader, updateStatus); 073 } 074 public void configureByResource(URL url) throws JoranException { 075 if (url == null) { 076 throw new IllegalArgumentException("URL argument cannot be null"); 077 } 078 final String urlString = url.toString(); 079 if (urlString.endsWith("xml")) { 080 JoranConfigurator configurator = new JoranConfigurator(); 081 configurator.setContext(context); 082 configurator.doConfigure(url); 083 } else { 084 throw new LogbackException( 085 "Unexpected filename extension of file [" + url.toString() + "]. Should be .xml"); 086 } 087 } 088 089 090 /** 091 * Perform multi-search for configuration file 092 * @param updateStatus 093 * @return 094 * 095 * @deprecated with no replacement 096 */ 097 public URL findURLOfDefaultConfigurationFile(boolean updateStatus) { 098 return performMultiStepConfigurationFileSearch(updateStatus); 099 } 100 101 private URL findConfigFileURLFromSystemProperties(ClassLoader classLoader, boolean updateStatus) { 102 String logbackConfigFile = OptionHelper.getSystemProperty(ClassicConstants.CONFIG_FILE_PROPERTY); 103 if (logbackConfigFile != null) { 104 URL result = null; 105 try { 106 result = new URL(logbackConfigFile); 107 return result; 108 } catch (MalformedURLException e) { 109 // so, resource is not a URL: 110 // attempt to get the resource from the class path 111 result = Loader.getResource(logbackConfigFile, classLoader); 112 if (result != null) { 113 return result; 114 } 115 // if the above fails, try to find as a file 116 File f = new File(logbackConfigFile); 117 if (f.exists() && f.isFile()) { 118 try { 119 result = f.toURI().toURL(); 120 return result; 121 } catch (MalformedURLException e1) { 122 } 123 } 124 } finally { 125 if (updateStatus) { 126 statusOnResourceSearch(logbackConfigFile, classLoader, result); 127 } 128 } 129 } 130 return null; 131 } 132 133 private URL getResource(String filename, ClassLoader myClassLoader, boolean updateStatus) { 134 URL url = Loader.getResource(filename, myClassLoader); 135 if (updateStatus) { 136 statusOnResourceSearch(filename, myClassLoader, url); 137 } 138 return url; 139 } 140 141 private void statusOnResourceSearch(String resourceName, ClassLoader classLoader, URL url) { 142 StatusManager sm = context.getStatusManager(); 143 if (url == null) { 144 sm.add(new InfoStatus("Could NOT find resource [" + resourceName + "]", context)); 145 } else { 146 sm.add(new InfoStatus("Found resource [" + resourceName + "] at [" + url.toString() + "]", context)); 147 multiplicityWarning(resourceName, classLoader); 148 } 149 } 150 151 private void multiplicityWarning(String resourceName, ClassLoader classLoader) { 152 Set<URL> urlSet = null; 153 try { 154 urlSet = Loader.getResources(resourceName, classLoader); 155 } catch (IOException e) { 156 addError("Failed to get url list for resource [" + resourceName + "]", e); 157 } 158 if (urlSet != null && urlSet.size() > 1) { 159 addWarn("Resource [" + resourceName + "] occurs multiple times on the classpath."); 160 for (URL url : urlSet) { 161 addWarn("Resource [" + resourceName + "] occurs at [" + url.toString() + "]"); 162 } 163 } 164 } 165}