1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic.util;
15
16 import ch.qos.logback.classic.ClassicConstants;
17 import ch.qos.logback.classic.LoggerContext;
18 import ch.qos.logback.classic.spi.Configurator;
19 import ch.qos.logback.classic.spi.ConfiguratorRank;
20 import ch.qos.logback.core.LogbackException;
21 import ch.qos.logback.core.joran.spi.JoranException;
22 import ch.qos.logback.core.spi.ContextAware;
23 import ch.qos.logback.core.spi.ContextAwareImpl;
24 import ch.qos.logback.core.util.CoreVersionUtil;
25 import ch.qos.logback.core.util.Loader;
26 import ch.qos.logback.core.util.StatusListenerConfigHelper;
27 import ch.qos.logback.core.util.VersionUtil;
28
29 import java.util.Comparator;
30 import java.util.List;
31
32
33
34
35
36
37
38
39
40 public class ContextInitializer {
41
42
43
44
45 final public static String AUTOCONFIG_FILE = ClassicConstants.AUTOCONFIG_FILE;
46
47
48
49 final public static String TEST_AUTOCONFIG_FILE = ClassicConstants.TEST_AUTOCONFIG_FILE;
50
51
52
53 final public static String CONFIG_FILE_PROPERTY = ClassicConstants.CONFIG_FILE_PROPERTY;
54
55 String[] INTERNAL_CONFIGURATOR_CLASSNAME_LIST = {"ch.qos.logback.classic.util.DefaultJoranConfigurator", "ch.qos.logback.classic.BasicConfigurator"};
56
57 final LoggerContext loggerContext;
58
59 final ContextAware contextAware;
60
61 public ContextInitializer(LoggerContext loggerContext) {
62 this.loggerContext = loggerContext;
63 this.contextAware = new ContextAwareImpl(loggerContext, this);
64 }
65
66 public void autoConfig() throws JoranException {
67 autoConfig(Configurator.class.getClassLoader());
68 }
69
70
71 public void autoConfig(ClassLoader classLoader) throws JoranException {
72
73
74 classLoader = Loader.systemClassloaderIfNull(classLoader);
75
76 checkVersions();
77
78 StatusListenerConfigHelper.installIfAsked(loggerContext);
79
80
81
82 List<Configurator> configuratorList = ClassicEnvUtil.loadFromServiceLoader(Configurator.class, classLoader);
83 configuratorList.sort(rankComparator);
84 if (configuratorList.isEmpty()) {
85 contextAware.addInfo("No custom configurators were discovered as a service.");
86 } else {
87 printConfiguratorOrder(configuratorList);
88 }
89
90 int authConfiguratorCount = authConfiguratorCount(configuratorList);
91 if (authConfiguratorCount > 1) {
92 contextAware.addError("Multiple custom configurators of rank AUTHENTICATING were discovered as a service. This is not allowed.");
93 contextAware.addError("Ensure that at most one AUTHENTICATING configurator exists on the classpath.");
94 return;
95 }
96
97
98 for (Configurator c : configuratorList) {
99 if (invokeConfigure(c) == Configurator.ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY)
100 return;
101 }
102
103
104 for (String configuratorClassName : INTERNAL_CONFIGURATOR_CLASSNAME_LIST) {
105 contextAware.addInfo("Trying to configure with " + configuratorClassName);
106 Configurator c = instantiateConfiguratorByClassName(configuratorClassName, classLoader);
107 if (c == null)
108 continue;
109 if (invokeConfigure(c) == Configurator.ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY)
110 return;
111 }
112 }
113
114 private int authConfiguratorCount(List<Configurator> configuratorList) {
115 int count = 0;
116 for (Configurator c : configuratorList) {
117 if (c.getClass().getAnnotation(ConfiguratorRank.class) != null
118 && c.getClass().getAnnotation(ConfiguratorRank.class).value() == ConfiguratorRank.AUTHENTICATING) {
119 contextAware.addInfo("Configurator of rank AUTHENTICATING discovered: " + c.getClass().getName());
120 count++;
121
122 }
123 }
124 return count;
125
126 }
127
128 private void checkVersions() {
129 try {
130 String coreVersion = CoreVersionUtil.getCoreVersionBySelfDeclaredProperties();
131 String classicVersion = ClassicVersionUtil.getVersionBySelfDeclaredProperties();
132 VersionUtil.checkForVersionEquality(loggerContext, coreVersion, classicVersion, "logback-core", "logback-classic");
133 } catch (NoClassDefFoundError e) {
134 contextAware.addWarn("Missing ch.logback.core.util.VersionUtil class on classpath. The version of logback-core is probably older than 1.5.26.");
135 } catch (NoSuchMethodError e) {
136 contextAware.addWarn(e.toString());
137 contextAware.addWarn("The version of logback-core is probably older than 1.5.26.");
138 }
139 }
140
141 private Configurator instantiateConfiguratorByClassName(String configuratorClassName, ClassLoader classLoader) {
142 try {
143 Class<?> classObj = classLoader.loadClass(configuratorClassName);
144 return (Configurator) classObj.getConstructor().newInstance();
145 } catch (ReflectiveOperationException e) {
146 contextAware.addInfo("Instantiation failure: " + e.toString());
147 return null;
148 }
149 }
150
151
152
153
154
155
156 private Configurator.ExecutionStatus invokeConfigure(Configurator configurator) {
157 try {
158 long start = System.currentTimeMillis();
159 contextAware.addInfo("Constructed configurator of type " + configurator.getClass());
160 configurator.setContext(loggerContext);
161 Configurator.ExecutionStatus status = configurator.configure(loggerContext);
162 printDuration(start, configurator, status);
163 return status;
164
165 } catch (Exception e) {
166 throw new LogbackException(String.format("Failed to initialize or to run Configurator: %s",
167 configurator != null ? configurator.getClass().getCanonicalName() : "null"), e);
168 }
169 }
170
171 private void printConfiguratorOrder(List<Configurator> configuratorList) {
172 contextAware.addInfo("Here is a list of configurators discovered as a service, by rank: ");
173 for (Configurator c : configuratorList) {
174 contextAware.addInfo(" " + c.getClass().getName());
175 }
176 contextAware.addInfo("They will be invoked in order until ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY is returned.");
177 }
178
179 private void printDuration(long start, Configurator configurator, Configurator.ExecutionStatus executionStatus) {
180 long end = System.currentTimeMillis();
181 long diff = end - start;
182 contextAware.addInfo(configurator.getClass().getName() + ".configure() call lasted " + diff + " milliseconds. ExecutionStatus=" + executionStatus);
183 }
184
185 private Configurator.ExecutionStatus attemptConfigurationUsingJoranUsingReflexion(ClassLoader classLoader) {
186
187 try {
188 Class<?> djcClass = classLoader.loadClass("ch.qos.logback.classic.util.DefaultJoranConfigurator");
189 Configurator c = (Configurator) djcClass.newInstance();
190 c.setContext(loggerContext);
191 return c.configure(loggerContext);
192 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
193 contextAware.addError("unexpected exception while instantiating DefaultJoranConfigurator", e);
194 return Configurator.ExecutionStatus.INVOKE_NEXT_IF_ANY;
195 }
196
197 }
198
199 Comparator<Configurator> rankComparator = new Comparator<Configurator>() {
200 @Override
201 public int compare(Configurator c1, Configurator c2) {
202
203 ConfiguratorRank r1 = c1.getClass().getAnnotation(ConfiguratorRank.class);
204 ConfiguratorRank r2 = c2.getClass().getAnnotation(ConfiguratorRank.class);
205
206 int value1 = r1 == null ? ConfiguratorRank.DEFAULT : r1.value();
207 int value2 = r2 == null ? ConfiguratorRank.DEFAULT : r2.value();
208
209 int result = compareRankValue(value1, value2);
210
211 return (-result);
212 }
213 };
214
215 private int compareRankValue(int value1, int value2) {
216 if (value1 > value2)
217 return 1;
218 else if (value1 == value2)
219 return 0;
220 else return -1;
221
222 }
223 }