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