1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core.joran.event;
15
16 import static ch.qos.logback.core.CoreConstants.XML_PARSING;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import javax.xml.parsers.ParserConfigurationException;
24 import javax.xml.parsers.SAXParser;
25 import javax.xml.parsers.SAXParserFactory;
26
27 import org.xml.sax.Attributes;
28 import org.xml.sax.InputSource;
29 import org.xml.sax.Locator;
30 import org.xml.sax.SAXException;
31 import org.xml.sax.SAXParseException;
32 import org.xml.sax.helpers.DefaultHandler;
33
34 import ch.qos.logback.core.Context;
35 import ch.qos.logback.core.joran.spi.ElementPath;
36 import ch.qos.logback.core.joran.spi.JoranException;
37 import ch.qos.logback.core.spi.ContextAware;
38 import ch.qos.logback.core.spi.ContextAwareImpl;
39 import ch.qos.logback.core.status.Status;
40
41 public class SaxEventRecorder extends DefaultHandler implements ContextAware {
42
43 final ContextAwareImpl contextAwareImpl;
44 final ElementPath elementPath;
45 List<SaxEvent> saxEventList = new ArrayList<SaxEvent>();
46 Locator locator;
47
48 public SaxEventRecorder(Context context) {
49 this(context, new ElementPath());
50 }
51
52 public SaxEventRecorder(Context context, ElementPath elementPath) {
53 contextAwareImpl = new ContextAwareImpl(context, this);
54 this.elementPath = elementPath;
55 }
56
57 final public void recordEvents(InputStream inputStream) throws JoranException {
58 recordEvents(new InputSource(inputStream));
59 }
60
61 public void recordEvents(InputSource inputSource) throws JoranException {
62 SAXParser saxParser = buildSaxParser();
63 try {
64 saxParser.parse(inputSource, this);
65 return;
66 } catch (IOException ie) {
67 handleError("I/O error occurred while parsing xml file", ie);
68 } catch (SAXException se) {
69
70 throw new JoranException("Problem parsing XML document. See previously reported errors.", se);
71 } catch (Exception ex) {
72 handleError("Unexpected exception while parsing XML document.", ex);
73 }
74 throw new IllegalStateException("This point can never be reached");
75 }
76
77 private void handleError(String errMsg, Throwable t) throws JoranException {
78 addError(errMsg, t);
79 throw new JoranException(errMsg, t);
80 }
81
82 private SAXParser buildSaxParser() throws JoranException {
83 try {
84 SAXParserFactory spf = SAXParserFactory.newInstance();
85 spf.setValidating(false);
86
87
88 spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
89 spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
90 spf.setNamespaceAware(true);
91 return spf.newSAXParser();
92 } catch (ParserConfigurationException pce) {
93 String errMsg = "Error during SAX paser configuration. See https://logback.qos.ch/codes.html#saxParserConfiguration";
94 addError(errMsg, pce);
95 throw new JoranException(errMsg, pce);
96 } catch (SAXException pce) {
97 String errMsg = "Error during parser creation or parser configuration";
98 addError(errMsg, pce);
99 throw new JoranException(errMsg, pce);
100 }
101 }
102
103 public void startDocument() {
104 }
105
106 public Locator getLocator() {
107 return locator;
108 }
109
110 public void setDocumentLocator(Locator l) {
111 locator = l;
112 }
113
114 protected boolean shouldIgnoreForElementPath(String tagName) {
115 return false;
116 }
117
118 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {
119
120 String tagName = getTagName(localName, qName);
121 if (!shouldIgnoreForElementPath(tagName)) {
122 elementPath.push(tagName);
123 }
124 ElementPath current = elementPath.duplicate();
125 saxEventList.add(new StartEvent(current, namespaceURI, localName, qName, atts, getLocator()));
126 }
127
128 public void characters(char[] ch, int start, int length) {
129 String bodyStr = new String(ch, start, length);
130 SaxEvent lastEvent = getLastEvent();
131 if (lastEvent instanceof BodyEvent) {
132 BodyEvent be = (BodyEvent) lastEvent;
133 be.append(bodyStr);
134 } else {
135
136 if (!isSpaceOnly(bodyStr)) {
137 saxEventList.add(new BodyEvent(bodyStr, getLocator()));
138 }
139 }
140 }
141
142 boolean isSpaceOnly(String bodyStr) {
143 String bodyTrimmed = bodyStr.trim();
144 return (bodyTrimmed.length() == 0);
145 }
146
147 SaxEvent getLastEvent() {
148 if (saxEventList.isEmpty()) {
149 return null;
150 }
151 int size = saxEventList.size();
152 return saxEventList.get(size - 1);
153 }
154
155 public void endElement(String namespaceURI, String localName, String qName) {
156 saxEventList.add(new EndEvent(namespaceURI, localName, qName, getLocator()));
157 String tagName = getTagName(localName, qName);
158 if (!shouldIgnoreForElementPath(tagName)) {
159 elementPath.pop();
160 }
161 }
162
163 String getTagName(String localName, String qName) {
164 String tagName = localName;
165 if ((tagName == null) || (tagName.length() < 1)) {
166 tagName = qName;
167 }
168 return tagName;
169 }
170
171 public void error(SAXParseException spe) throws SAXException {
172 addError(XML_PARSING + " - Parsing error on line " + spe.getLineNumber() + " and column "
173 + spe.getColumnNumber());
174 addError(spe.toString());
175 }
176
177 public void fatalError(SAXParseException spe) throws SAXException {
178 addError(XML_PARSING + " - Parsing fatal error on line " + spe.getLineNumber() + " and column "
179 + spe.getColumnNumber());
180 addError(spe.toString());
181 }
182
183 public void warning(SAXParseException spe) throws SAXException {
184 addWarn(XML_PARSING + " - Parsing warning on line " + spe.getLineNumber() + " and column "
185 + spe.getColumnNumber(), spe);
186 }
187
188 public void addError(String msg) {
189 contextAwareImpl.addError(msg);
190 }
191
192 public void addError(String msg, Throwable ex) {
193 contextAwareImpl.addError(msg, ex);
194 }
195
196 public void addInfo(String msg) {
197 contextAwareImpl.addInfo(msg);
198 }
199
200 public void addInfo(String msg, Throwable ex) {
201 contextAwareImpl.addInfo(msg, ex);
202 }
203
204 public void addStatus(Status status) {
205 contextAwareImpl.addStatus(status);
206 }
207
208 public void addWarn(String msg) {
209 contextAwareImpl.addWarn(msg);
210 }
211
212 public void addWarn(String msg, Throwable ex) {
213 contextAwareImpl.addWarn(msg, ex);
214 }
215
216 public Context getContext() {
217 return contextAwareImpl.getContext();
218 }
219
220 public void setContext(Context context) {
221 contextAwareImpl.setContext(context);
222 }
223
224 public List<SaxEvent> getSaxEventList() {
225 return saxEventList;
226 }
227
228 }