1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package ch.qos.logback.classic.joran;
16
17 import ch.qos.logback.classic.ClassicConstants;
18 import ch.qos.logback.classic.LoggerContext;
19 import ch.qos.logback.classic.joran.serializedModel.HardenedModelInputStream;
20 import ch.qos.logback.classic.model.processor.LogbackClassicDefaultNestedComponentRules;
21 import ch.qos.logback.classic.spi.ConfiguratorRank;
22 import ch.qos.logback.core.Context;
23 import ch.qos.logback.core.LogbackException;
24 import ch.qos.logback.core.model.Model;
25 import ch.qos.logback.core.model.ModelUtil;
26 import ch.qos.logback.core.model.processor.DefaultProcessor;
27 import ch.qos.logback.core.model.processor.ModelInterpretationContext;
28 import ch.qos.logback.classic.spi.Configurator;
29 import ch.qos.logback.core.spi.ContextAwareBase;
30 import ch.qos.logback.core.status.InfoStatus;
31 import ch.qos.logback.core.status.StatusManager;
32 import ch.qos.logback.core.util.Loader;
33 import ch.qos.logback.core.util.OptionHelper;
34
35 import java.io.File;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.net.MalformedURLException;
39 import java.net.URL;
40 import java.util.concurrent.locks.ReentrantLock;
41
42 import static ch.qos.logback.core.CoreConstants.MODEL_CONFIG_FILE_EXTENSION;
43
44
45
46
47
48
49 @ConfiguratorRank(value = ConfiguratorRank.SERIALIZED_MODEL)
50 public class SerializedModelConfigurator extends ContextAwareBase implements Configurator {
51
52 final public static String AUTOCONFIG_MODEL_FILE = "logback"+ MODEL_CONFIG_FILE_EXTENSION;
53
54 final public static String TEST_AUTOCONFIG_MODEL_FILE = "logback-test"+ MODEL_CONFIG_FILE_EXTENSION;
55 protected ModelInterpretationContext modelInterpretationContext;
56
57 @Override
58 public ExecutionStatus configure(LoggerContext loggerContext) {
59
60 URL url = performMultiStepModelFileSearch(true);
61 if (url != null) {
62 configureByResource(url);
63 return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY;
64 } else {
65 return ExecutionStatus.INVOKE_NEXT_IF_ANY;
66 }
67 }
68
69 private void configureByResource(URL url) {
70 final String urlString = url.toString();
71 if (urlString.endsWith(MODEL_CONFIG_FILE_EXTENSION)) {
72 Model model = retrieveModel(url);
73 if(model == null) {
74 addWarn("Empty model. Abandoning.");
75 return;
76 }
77 ModelUtil.resetForReuse(model);
78 buildModelInterpretationContext(model);
79
80 DefaultProcessor defaultProcessor = new DefaultProcessor(context, this.modelInterpretationContext);
81 ModelClassToModelHandlerLinker mc2mhl = new ModelClassToModelHandlerLinker(context);
82 mc2mhl.link(defaultProcessor);
83
84
85 ReentrantLock configurationLock = context.getConfigurationLock();
86 try {
87 configurationLock.lock();
88 defaultProcessor.process(model);
89 } finally {
90 configurationLock.unlock();
91 }
92 } else {
93 throw new LogbackException(
94 "Unexpected filename extension of file [" + url.toString() + "]. Should be " + MODEL_CONFIG_FILE_EXTENSION);
95 }
96 }
97
98 private void buildModelInterpretationContext(Model topModel) {
99 this.modelInterpretationContext = new ModelInterpretationContext(context, this);
100 this.modelInterpretationContext.setTopModel(topModel);
101 LogbackClassicDefaultNestedComponentRules.addDefaultNestedComponentRegistryRules(
102 modelInterpretationContext.getDefaultNestedComponentRegistry());
103 this.modelInterpretationContext.createAppenderBags();
104 }
105
106 private Model retrieveModel(URL url) {
107 long start = System.currentTimeMillis();
108 try (InputStream is = url.openStream()) {
109 HardenedModelInputStream hmis = new HardenedModelInputStream(is);
110
111 Model model = (Model) hmis.readObject();
112 long diff = System.currentTimeMillis() - start;
113 addInfo("Model at ["+url+"] read in "+diff + " milliseconds");
114 return model;
115 } catch(IOException e) {
116 addError("Failed to open "+url, e);
117 } catch (ClassNotFoundException e) {
118 addError("Failed read model object in "+ url, e);
119 }
120 return null;
121 }
122
123 private URL performMultiStepModelFileSearch(boolean updateState) {
124 ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
125 URL url = findModelConfigFileURLFromSystemProperties(myClassLoader);
126 if (url != null) {
127 return url;
128 }
129
130 url = getResource(TEST_AUTOCONFIG_MODEL_FILE, myClassLoader, updateState);
131 if (url != null) {
132 return url;
133 }
134
135 url = getResource(AUTOCONFIG_MODEL_FILE, myClassLoader, updateState);
136 return url;
137 }
138
139 URL findModelConfigFileURLFromSystemProperties(ClassLoader classLoader) {
140 String logbackModelFile = OptionHelper.getSystemProperty(ClassicConstants.MODEL_CONFIG_FILE_PROPERTY);
141
142 if (logbackModelFile != null) {
143 URL result = null;
144 try {
145 result = new URL(logbackModelFile);
146 return result;
147 } catch (MalformedURLException e) {
148
149
150 result = Loader.getResource(logbackModelFile, classLoader);
151 if (result != null) {
152 return result;
153 }
154 File f = new File(logbackModelFile);
155 if (f.exists() && f.isFile()) {
156 try {
157 result = f.toURI().toURL();
158 return result;
159 } catch (MalformedURLException e1) {
160 }
161 }
162 } finally {
163 statusOnResourceSearch(logbackModelFile, result);
164 }
165 }
166 return null;
167 }
168
169
170 private URL getResource(String filename, ClassLoader classLoader, boolean updateStatus) {
171 URL url = Loader.getResource(filename, classLoader);
172 if (updateStatus) {
173 statusOnResourceSearch(filename, url);
174 }
175 return url;
176 }
177
178 private void statusOnResourceSearch(String resourceName, URL url) {
179 StatusManager sm = context.getStatusManager();
180 if (url == null) {
181 sm.add(new InfoStatus("Could NOT find resource [" + resourceName + "]", context));
182 } else {
183 sm.add(new InfoStatus("Found resource [" + resourceName + "] at [" + url.toString() + "]", context));
184 }
185 }
186 }