View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, 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 java.io.IOException;
17  import java.io.InputStream;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import javax.xml.parsers.SAXParser;
22  import javax.xml.parsers.SAXParserFactory;
23  
24  import static ch.qos.logback.core.CoreConstants.XML_PARSING;
25  import org.xml.sax.Attributes;
26  import org.xml.sax.InputSource;
27  import org.xml.sax.Locator;
28  import org.xml.sax.SAXException;
29  import org.xml.sax.SAXParseException;
30  import org.xml.sax.helpers.DefaultHandler;
31  
32  import ch.qos.logback.core.Context;
33  import ch.qos.logback.core.joran.spi.JoranException;
34  import ch.qos.logback.core.joran.spi.Pattern;
35  import ch.qos.logback.core.spi.ContextAware;
36  import ch.qos.logback.core.spi.ContextAwareImpl;
37  import ch.qos.logback.core.status.Status;
38  
39  public class SaxEventRecorder extends DefaultHandler implements ContextAware {
40  
41    final ContextAwareImpl cai;
42  
43    public SaxEventRecorder() {
44      cai = new ContextAwareImpl(this);
45    }
46  
47    public List<SaxEvent> saxEventList = new ArrayList<SaxEvent>();
48    Locator locator;
49    Pattern globalPattern = new Pattern();
50  
51    final public void recordEvents(InputStream inputStream) throws JoranException {
52      recordEvents(new InputSource(inputStream));
53    }
54  
55    public List<SaxEvent> recordEvents(InputSource inputSource)
56        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,
102       Attributes atts) {
103 
104     String tagName = getTagName(localName, qName);
105     globalPattern.push(tagName);
106     Pattern current = (Pattern) globalPattern.clone();
107     saxEventList.add(new StartEvent(current, namespaceURI, localName, qName,
108         atts, getLocator()));
109   }
110 
111   public void characters(char[] ch, int start, int length) {
112     String bodyStr = new String(ch, start, length);
113     SaxEvent lastEvent = getLastEvent();
114     if (lastEvent instanceof BodyEvent) {
115       BodyEvent be = (BodyEvent) lastEvent;
116       be.append(bodyStr);
117     } else {
118       // ignore space only text if the previous event is not a BodyEvent
119       if (!isSpaceOnly(bodyStr)) {
120         saxEventList.add(new BodyEvent(bodyStr, getLocator()));
121       }
122     }
123   }
124 
125   boolean isSpaceOnly(String bodyStr) {
126     String bodyTrimmed = bodyStr.trim();
127     return (bodyTrimmed.length() == 0);
128   }
129 
130   SaxEvent getLastEvent() {
131     if (saxEventList.isEmpty()) {
132       return null;
133     }
134     int size = saxEventList.size();
135     return saxEventList.get(size - 1);
136   }
137 
138   public void endElement(String namespaceURI, String localName, String qName) {
139     saxEventList
140         .add(new EndEvent(namespaceURI, localName, qName, getLocator()));
141     globalPattern.pop();
142   }
143 
144   String getTagName(String localName, String qName) {
145     String tagName = localName;
146     if ((tagName == null) || (tagName.length() < 1)) {
147       tagName = qName;
148     }
149     return tagName;
150   }
151 
152   public void error(SAXParseException spe) throws SAXException {
153     addError(XML_PARSING +" - Parsing error on line " + spe.getLineNumber() + " and column "
154         + spe.getColumnNumber(), spe);
155   }
156 
157   public void fatalError(SAXParseException spe) throws SAXException {
158     addError(XML_PARSING +" - Parsing fatal error on line " + spe.getLineNumber()
159         + " and column " + spe.getColumnNumber(), spe);
160   }
161 
162   public void warning(SAXParseException spe) throws SAXException {
163     addWarn(XML_PARSING +" - Parsing warning on line " + spe.getLineNumber() + " and column "
164         + spe.getColumnNumber(), spe);
165   }
166 
167   public void addError(String msg) {
168     cai.addError(msg);
169   }
170 
171   public void addError(String msg, Throwable ex) {
172     cai.addError(msg, ex);
173   }
174 
175   public void addInfo(String msg) {
176     cai.addInfo(msg);
177   }
178 
179   public void addInfo(String msg, Throwable ex) {
180     cai.addInfo(msg, ex);
181   }
182 
183   public void addStatus(Status status) {
184     cai.addStatus(status);
185   }
186 
187   public void addWarn(String msg) {
188     cai.addWarn(msg);
189   }
190 
191   public void addWarn(String msg, Throwable ex) {
192     cai.addWarn(msg, ex);
193   }
194 
195   public Context getContext() {
196     return cai.getContext();
197   }
198 
199   public void setContext(Context context) {
200     cai.setContext(context);
201   }
202 
203   public List<SaxEvent> getSaxEventList() {
204     return saxEventList;
205   }
206 
207 }