1
14 package ch.qos.logback.core.joran.action;
15
16 import java.io.File;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.net.MalformedURLException;
20 import java.net.URI;
21 import java.net.URL;
22 import java.util.List;
23
24 import org.xml.sax.Attributes;
25
26 import ch.qos.logback.core.joran.event.SaxEvent;
27 import ch.qos.logback.core.joran.event.SaxEventRecorder;
28 import ch.qos.logback.core.joran.spi.ActionException;
29 import ch.qos.logback.core.joran.spi.InterpretationContext;
30 import ch.qos.logback.core.joran.spi.JoranException;
31 import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
32 import ch.qos.logback.core.util.Loader;
33 import ch.qos.logback.core.util.OptionHelper;
34
35 public class IncludeAction extends Action {
36
37 private static final String INCLUDED_TAG = "included";
38 private static final String FILE_ATTR = "file";
39 private static final String URL_ATTR = "url";
40 private static final String RESOURCE_ATTR = "resource";
41 private static final String OPTIONAL_ATTR = "optional";
42
43 private String attributeInUse;
44 private boolean optional;
45
46 @Override
47 public void begin(InterpretationContext ec, String name, Attributes attributes) throws ActionException {
48
49 SaxEventRecorder recorder = new SaxEventRecorder(context);
50
51 this.attributeInUse = null;
52 this.optional = OptionHelper.toBoolean(attributes.getValue(OPTIONAL_ATTR), false);
53
54 if (!checkAttributes(attributes)) {
55 return;
56 }
57
58 InputStream in = getInputStream(ec, attributes);
59
60 try {
61 if (in != null) {
62 parseAndRecord(in, recorder);
63
64 trimHeadAndTail(recorder);
65
66
67 ec.getJoranInterpreter().getEventPlayer().addEventsDynamically(recorder.saxEventList, 2);
68 }
69 } catch (JoranException e) {
70 addError("Error while parsing " + attributeInUse, e);
71 } finally {
72 close(in);
73 }
74
75 }
76
77 void close(InputStream in) {
78 if (in != null) {
79 try {
80 in.close();
81 } catch (IOException e) {
82 }
83 }
84 }
85
86 private boolean checkAttributes(Attributes attributes) {
87 String fileAttribute = attributes.getValue(FILE_ATTR);
88 String urlAttribute = attributes.getValue(URL_ATTR);
89 String resourceAttribute = attributes.getValue(RESOURCE_ATTR);
90
91 int count = 0;
92
93 if (!OptionHelper.isEmpty(fileAttribute)) {
94 count++;
95 }
96 if (!OptionHelper.isEmpty(urlAttribute)) {
97 count++;
98 }
99 if (!OptionHelper.isEmpty(resourceAttribute)) {
100 count++;
101 }
102
103 if (count == 0) {
104 addError("One of \"path\", \"resource\" or \"url\" attributes must be set.");
105 return false;
106 } else if (count > 1) {
107 addError("Only one of \"file\", \"url\" or \"resource\" attributes should be set.");
108 return false;
109 } else if (count == 1) {
110 return true;
111 }
112 throw new IllegalStateException("Count value [" + count + "] is not expected");
113 }
114
115 URL attributeToURL(String urlAttribute) {
116 try {
117 return new URL(urlAttribute);
118 } catch (MalformedURLException mue) {
119 String errMsg = "URL [" + urlAttribute + "] is not well formed.";
120 addError(errMsg, mue);
121 return null;
122 }
123 }
124
125 InputStream openURL(URL url) {
126 try {
127 return url.openStream();
128 } catch (IOException e) {
129 optionalWarning("Failed to open [" + url.toString() + "]");
130 return null;
131 }
132 }
133
134 URL resourceAsURL(String resourceAttribute) {
135 URL url = Loader.getResourceBySelfClassLoader(resourceAttribute);
136 if (url == null) {
137 optionalWarning("Could not find resource corresponding to [" + resourceAttribute + "]");
138 return null;
139 } else
140 return url;
141 }
142
143 private void optionalWarning(String msg) {
144 if (!optional) {
145 addWarn(msg);
146 }
147 }
148
149 URL filePathAsURL(String path) {
150 URI uri = new File(path).toURI();
151 try {
152 return uri.toURL();
153 } catch (MalformedURLException e) {
154
155 e.printStackTrace();
156 return null;
157 }
158 }
159
160 URL getInputURL(InterpretationContext ec, Attributes attributes) {
161 String fileAttribute = attributes.getValue(FILE_ATTR);
162 String urlAttribute = attributes.getValue(URL_ATTR);
163 String resourceAttribute = attributes.getValue(RESOURCE_ATTR);
164
165 if (!OptionHelper.isEmpty(fileAttribute)) {
166 this.attributeInUse = ec.subst(fileAttribute);
167 return filePathAsURL(attributeInUse);
168 }
169
170 if (!OptionHelper.isEmpty(urlAttribute)) {
171 this.attributeInUse = ec.subst(urlAttribute);
172 return attributeToURL(attributeInUse);
173 }
174
175 if (!OptionHelper.isEmpty(resourceAttribute)) {
176 this.attributeInUse = ec.subst(resourceAttribute);
177 return resourceAsURL(attributeInUse);
178 }
179
180 throw new IllegalStateException("A URL stream should have been returned");
181
182 }
183
184 InputStream getInputStream(InterpretationContext ec, Attributes attributes) {
185 URL inputURL = getInputURL(ec, attributes);
186 if (inputURL == null)
187 return null;
188
189 ConfigurationWatchListUtil.addToWatchList(context, inputURL);
190 return openURL(inputURL);
191 }
192
193 private void trimHeadAndTail(SaxEventRecorder recorder) {
194
195
196
197 List<SaxEvent> saxEventList = recorder.saxEventList;
198
199 if (saxEventList.size() == 0) {
200 return;
201 }
202
203 SaxEvent first = saxEventList.get(0);
204 if (first != null && first.qName.equalsIgnoreCase(INCLUDED_TAG)) {
205 saxEventList.remove(0);
206 }
207
208 SaxEvent last = saxEventList.get(recorder.saxEventList.size() - 1);
209 if (last != null && last.qName.equalsIgnoreCase(INCLUDED_TAG)) {
210 saxEventList.remove(recorder.saxEventList.size() - 1);
211 }
212 }
213
214 private void parseAndRecord(InputStream inputSource, SaxEventRecorder recorder) throws JoranException {
215 recorder.setContext(context);
216 recorder.recordEvents(inputSource);
217 }
218
219 @Override
220 public void end(InterpretationContext ec, String name) throws ActionException {
221
222 }
223
224 }
225