View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
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.SAXParser;
24  import javax.xml.parsers.SAXParserFactory;
25  
26  import org.xml.sax.Attributes;
27  import org.xml.sax.InputSource;
28  import org.xml.sax.Locator;
29  import org.xml.sax.SAXException;
30  import org.xml.sax.SAXParseException;
31  import org.xml.sax.helpers.DefaultHandler;
32  
33  import ch.qos.logback.core.Context;
34  import ch.qos.logback.core.joran.spi.ElementPath;
35  import ch.qos.logback.core.joran.spi.JoranException;
36  import ch.qos.logback.core.spi.ContextAware;
37  import ch.qos.logback.core.spi.ContextAwareImpl;
38  import ch.qos.logback.core.status.Status;
39  
40  public class SaxEventRecorder extends DefaultHandler implements ContextAware {
41  
42      final ContextAwareImpl cai;
43  
44      public SaxEventRecorder(Context context) {
45          cai = new ContextAwareImpl(context, this);
46      }
47  
48      public List<SaxEvent> saxEventList = new ArrayList<SaxEvent>();
49      Locator locator;
50      ElementPath globalElementPath = new ElementPath();
51  
52      final public void recordEvents(InputStream inputStream) throws JoranException {
53          recordEvents(new InputSource(inputStream));
54      }
55  
56      public List<SaxEvent> recordEvents(InputSource inputSource) throws JoranException {
57          SAXParser saxParser = buildSaxParser();
58          try {
59              saxParser.parse(inputSource, this);
60              return saxEventList;
61          } catch (IOException ie) {
62              handleError("I/O error occurred while parsing xml file", ie);
63          } catch (SAXException se) {
64              // Exception added into StatusManager via Sax error handling. No need to add it again
65              throw new JoranException("Problem parsing XML document. See previously reported errors.", se);
66          } catch (Exception ex) {
67              handleError("Unexpected exception while parsing XML document.", ex);
68          }
69          throw new IllegalStateException("This point can never be reached");
70      }
71  
72      private void handleError(String errMsg, Throwable t) throws JoranException {
73          addError(errMsg, t);
74          throw new JoranException(errMsg, t);
75      }
76  
77      private SAXParser buildSaxParser() throws JoranException {
78          try {
79              SAXParserFactory spf = SAXParserFactory.newInstance();
80              spf.setValidating(false);
81              spf.setNamespaceAware(true);
82              return spf.newSAXParser();
83          } catch (Exception pce) {
84              String errMsg = "Parser configuration error occurred";
85              addError(errMsg, pce);
86              throw new JoranException(errMsg, pce);
87          }
88      }
89  
90      public void startDocument() {
91      }
92  
93      public Locator getLocator() {
94          return locator;
95      }
96  
97      public void setDocumentLocator(Locator l) {
98          locator = l;
99      }
100 
101     public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {
102 
103         String tagName = getTagName(localName, qName);
104         globalElementPath.push(tagName);
105         ElementPath current = globalElementPath.duplicate();
106         saxEventList.add(new StartEvent(current, namespaceURI, localName, qName, atts, getLocator()));
107     }
108 
109     public void characters(char[] ch, int start, int length) {
110         String bodyStr = new String(ch, start, length);
111         SaxEvent lastEvent = getLastEvent();
112         if (lastEvent instanceof BodyEvent) {
113             BodyEvent be = (BodyEvent) lastEvent;
114             be.append(bodyStr);
115         } else {
116             // ignore space only text if the previous event is not a BodyEvent
117             if (!isSpaceOnly(bodyStr)) {
118                 saxEventList.add(new BodyEvent(bodyStr, getLocator()));
119             }
120         }
121     }
122 
123     boolean isSpaceOnly(String bodyStr) {
124         String bodyTrimmed = bodyStr.trim();
125         return (bodyTrimmed.length() == 0);
126     }
127 
128     SaxEvent getLastEvent() {
129         if (saxEventList.isEmpty()) {
130             return null;
131         }
132         int size = saxEventList.size();
133         return saxEventList.get(size - 1);
134     }
135 
136     public void endElement(String namespaceURI, String localName, String qName) {
137         saxEventList.add(new EndEvent(namespaceURI, localName, qName, getLocator()));
138         globalElementPath.pop();
139     }
140 
141     String getTagName(String localName, String qName) {
142         String tagName = localName;
143         if ((tagName == null) || (tagName.length() < 1)) {
144             tagName = qName;
145         }
146         return tagName;
147     }
148 
149     public void error(SAXParseException spe) throws SAXException {
150         addError(XML_PARSING + " - Parsing error on line " + spe.getLineNumber() + " and column " + spe.getColumnNumber());
151         addError(spe.toString());
152         
153     }
154 
155     public void fatalError(SAXParseException spe) throws SAXException {
156         addError(XML_PARSING + " - Parsing fatal error on line " + spe.getLineNumber() + " and column " + spe.getColumnNumber());
157         addError(spe.toString());
158     }
159 
160     public void warning(SAXParseException spe) throws SAXException {
161         addWarn(XML_PARSING + " - Parsing warning on line " + spe.getLineNumber() + " and column " + spe.getColumnNumber(), spe);
162     }
163 
164     public void addError(String msg) {
165         cai.addError(msg);
166     }
167 
168     public void addError(String msg, Throwable ex) {
169         cai.addError(msg, ex);
170     }
171 
172     public void addInfo(String msg) {
173         cai.addInfo(msg);
174     }
175 
176     public void addInfo(String msg, Throwable ex) {
177         cai.addInfo(msg, ex);
178     }
179 
180     public void addStatus(Status status) {
181         cai.addStatus(status);
182     }
183 
184     public void addWarn(String msg) {
185         cai.addWarn(msg);
186     }
187 
188     public void addWarn(String msg, Throwable ex) {
189         cai.addWarn(msg, ex);
190     }
191 
192     public Context getContext() {
193         return cai.getContext();
194     }
195 
196     public void setContext(Context context) {
197         cai.setContext(context);
198     }
199 
200     public List<SaxEvent> getSaxEventList() {
201         return saxEventList;
202     }
203 
204 }