Clover Coverage Report
Coverage timestamp: Fri May 24 2013 13:47:27 UTC
../../../../../../img/srcFileCovDistChart9.png 45% of files have more coverage
95   351   37   5.59
18   179   0.39   17
17     2.18  
1    
 
  SaxDefaultHandler       Line # 42 95 37 81.5% 0.8153846
 
  (490)
 
1    /* This file is part of the project "Hilbert II" - http://www.qedeq.org
2    *
3    * Copyright 2000-2013, Michael Meyling <mime@qedeq.org>.
4    *
5    * "Hilbert II" is free software; you can redistribute
6    * it and/or modify it under the terms of the GNU General Public
7    * License as published by the Free Software Foundation; either
8    * version 2 of the License, or (at your option) any later version.
9    *
10    * This program is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13    * GNU General Public License for more details.
14    */
15    package org.qedeq.kernel.xml.handler.common;
16   
17    import java.util.Stack;
18   
19    import org.qedeq.base.io.SourceArea;
20    import org.qedeq.base.io.SourcePosition;
21    import org.qedeq.base.trace.Trace;
22    import org.qedeq.kernel.se.common.Plugin;
23    import org.qedeq.kernel.se.common.SourceFileException;
24    import org.qedeq.kernel.se.common.SourceFileExceptionList;
25    import org.qedeq.kernel.xml.common.XmlSyntaxException;
26    import org.xml.sax.Attributes;
27    import org.xml.sax.SAXException;
28    import org.xml.sax.SAXParseException;
29   
30   
31    /**
32    * Default SAX handler. Delegates SAX events to a
33    * {@link org.qedeq.kernel.xml.handler.common.AbstractSimpleHandler}
34    * which could also delegate events to other
35    * {@link org.qedeq.kernel.xml.handler.common.AbstractSimpleHandler}s.
36    * <p>
37    * Before anything is parsed the method {@link #setExceptionList(SourceFileExceptionList)}
38    * must be called.
39    *
40    * @author Michael Meyling
41    */
 
42    public class SaxDefaultHandler extends SimpleHandler {
43   
44    /** This class. */
45    private static final Class CLASS = SaxDefaultHandler.class;
46   
47    /** Delegate currently to this handler. */
48    private AbstractSimpleHandler currentHandler;
49   
50    /** Stack of previous {@link AbstractSimpleHandler}s. */
51    private Stack handlerStack = new Stack();
52   
53    /** Top level handler. This handler is activated after the begin of the document. */
54    private AbstractSimpleHandler basisHandler;
55   
56    /** Collect errors in this object. */
57    private SourceFileExceptionList errorList;
58   
59    /** Buffer for combining character events. */
60    private StringBuffer buffer = new StringBuffer(2000);
61   
62    /** Tag level for current handler. */
63    private int level;
64   
65    /** Tag level for previous handlers. */
66    private Stack levelStack = new Stack();
67   
68    /** Current tag name. Could be <code>null</code>. */
69    private String currentElementName;
70   
71    /** The plugin we work for. */
72    private final Plugin plugin;
73   
74    /**
75    * Constructor.
76    *
77    * @param plugin The plugin we work for.
78    */
 
79  1162 toggle public SaxDefaultHandler(final Plugin plugin) {
80  1162 super();
81  1162 this.plugin = plugin;
82    }
83   
84    /**
85    * Set parse exception list. This list collects occurring parsing errors.
86    *
87    * @param errorList Collect errors here.
88    */
 
89  1145 toggle public void setExceptionList(final SourceFileExceptionList errorList) {
90  1145 this.errorList = errorList;
91    }
92   
93    /**
94    * Set basis handler for documents.
95    *
96    * @param handler Basis handler for documents. This handler might also pass control to
97    * another handler via the
98    * {@link AbstractSimpleHandler#changeHandler(AbstractSimpleHandler, String, SimpleAttributes)}
99    * method.
100    */
 
101  1162 toggle public final void setBasisDocumentHandler(final AbstractSimpleHandler handler) {
102  1162 basisHandler = handler;
103  1162 currentHandler = handler;
104  1162 handlerStack.clear();
105  1162 level = 0;
106    }
107   
108    /* (non-Javadoc)
109    * @see org.xml.sax.helpers.DefaultHandler#startDocument()
110    */
 
111  1145 toggle public final void startDocument() throws SAXException {
112  1145 sendCharacters();
113  1145 currentHandler = basisHandler;
114  1145 handlerStack.clear();
115  1145 level = 0;
116  1145 currentElementName = null;
117    }
118   
119    /* (non-Javadoc)
120    * @see org.xml.sax.helpers.DefaultHandler#endDocument()
121    */
 
122  1145 toggle public final void endDocument() throws SAXException {
123  1145 sendCharacters();
124  1145 currentElementName = null;
125    }
126   
127    /* (non-Javadoc)
128    * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
129    * java.lang.String, org.xml.sax.Attributes)
130    */
 
131  667514 toggle public final void startElement(final String uri, final String localName, final String qName,
132    final Attributes amap) throws SAXException {
133  667514 final String method = "startElement";
134  667514 try {
135  667514 Trace.param(CLASS, this, method, "currentHandler", currentHandler.getClass().getName());
136  667514 Trace.param(CLASS, this, method, "localName", localName);
137  667514 Trace.param(CLASS, this, method, "qName", qName);
138  667514 if (handlerStack.empty() && level == 0) {
139  1145 currentHandler.init();
140    }
141  667514 level++;
142  667514 Trace.param(CLASS, this, method, "level", level);
143  667514 sendCharacters();
144  667514 currentElementName = localName;
145  667514 final SimpleAttributes attributes = new SimpleAttributes();
146  1156446 for (int i = 0; i < amap.getLength(); i++) {
147  488932 attributes.add(amap.getQName(i), amap.getValue(i));
148    }
149  667514 Trace.param(CLASS, this, method, "attributes", attributes);
150  667514 currentHandler.startElement(qName, attributes);
151    } catch (XmlSyntaxException e) {
152  60 Trace.trace(CLASS, this, method, e);
153  60 addXmlSyntaxException(e);
154    } catch (RuntimeException e) {
155  0 Trace.trace(CLASS, this, method, e);
156  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
157  0 addXmlSyntaxException(ex);
158    }
159    }
160   
161    /* (non-Javadoc)
162    * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
163    * java.lang.String)
164    */
 
165  667514 toggle public final void endElement(final String uri, final String localName, final String qName)
166    throws SAXException {
167  667514 sendCharacters();
168  667514 final String method = "endElement";
169  667514 try {
170  667514 Trace.param(CLASS, this, method, "currentHandler", currentHandler.getClass().getName());
171  667514 Trace.param(CLASS, this, method, "qName", qName);
172  667514 currentHandler.endElement(qName);
173    } catch (XmlSyntaxException e) {
174  60 Trace.trace(CLASS, this, method, e);
175  60 addXmlSyntaxException(e);
176    } catch (RuntimeException e) {
177  0 Trace.trace(CLASS, this, method, e);
178  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
179  0 addXmlSyntaxException(ex);
180    }
181  667514 try {
182  667514 currentElementName = null;
183  667514 level--;
184  667514 Trace.param(CLASS, this, method, "level", level);
185  667514 if (level <= 0) {
186  180222 restoreHandler(localName);
187    }
188    } catch (XmlSyntaxException e) {
189  0 Trace.trace(CLASS, this, method, e);
190  0 addXmlSyntaxException(e);
191    } catch (RuntimeException e) {
192  0 Trace.trace(CLASS, this, method, e);
193  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
194  0 addXmlSyntaxException(ex);
195    }
196    }
197   
198    /* (non-Javadoc)
199    * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
200    */
 
201  1586270 toggle public final void characters(final char[] ch, final int start, final int length) {
202  1586270 buffer.append(ch, start, length);
203    }
204   
205    /**
206    * Sends <code>characters</code> event to current handler. Whitespace is preserved.
207    * It fires only, if there is something beside whitespace.
208    */
 
209  1337318 toggle private void sendCharacters() {
210  1337318 try {
211  1337318 if (buffer.length() > 0) {
212  1136440 final String str = buffer.toString();
213  1136440 buffer.setLength(0);
214  1136440 if (str.trim().length() > 0) { // anything there beside whitespace?
215  122351 currentHandler.characters(currentElementName, str);
216    }
217    }
218    } catch (XmlSyntaxException e) {
219  0 Trace.trace(CLASS, this, "sendCharacters", e);
220  0 addXmlSyntaxException(e);
221    } catch (RuntimeException e) {
222  0 Trace.trace(CLASS, this, "sendCharacters", e);
223  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
224  0 addXmlSyntaxException(ex);
225    }
226    }
227   
228    /**
229    * Add exception to exception list if we have only than 20 exceptions yet.
230    *
231    * @param exception Add this exception.
232    */
 
233  120 toggle private void addXmlSyntaxException(final XmlSyntaxException exception) {
234  120 if (errorList.size() < 20) {
235  104 errorList.add(new SourceFileException(plugin, exception, createSourceArea(), null));
236    }
237    }
238   
239    /**
240    * Change current handler to new one. The new handler is initialized by calling
241    * {@link AbstractSimpleHandler#init()}.
242    * The new handler also gets a {@link AbstractSimpleHandler#startElement(String,
243    * SimpleAttributes)} event.
244    * The current handler is stacked. After the new handler gets the appropriate endElement
245    * event, the control is switched back to the old handler.
246    * <p>
247    * The switch back is also done, if the tag level gets back to the same number. That means
248    * if for example the new handler starts with the <code>&lt;banana&gt;</code> tag, the
249    * old handler is restored when the misspelled <code>&lt;/bnana&gt</code> tag occurs:
250    * <p>
251    * <pre>
252    * &lt;banana&gt;
253    * &lt;one /&gt;
254    * &lt;two &gt;
255    * &lt;one /&gt;
256    * &lt;one /&gt;
257    * &lt;/two &gt;
258    * &lt;/bnana&gt
259    * </pre>
260    *
261    * @param newHandler This handler gets the new events.
262    * @param elementName Element name.
263    * @param attributes Element attributes.
264    * @throws XmlSyntaxException New Handler detected a semantic problem.
265    */
 
266  183088 toggle public final void changeHandler(final AbstractSimpleHandler newHandler,
267    final String elementName, final SimpleAttributes attributes)
268    throws XmlSyntaxException {
269  183088 handlerStack.push(currentHandler);
270  183088 levelStack.push(new Integer(level));
271  183088 currentHandler = newHandler;
272  183088 level = 0;
273  183088 level++;
274  183088 Trace.param(CLASS, this, "changeHandler", "level", level);
275  183088 currentHandler.init();
276  183088 currentHandler.startElement(elementName, attributes);
277    }
278   
279    /**
280    * Restore previous handler if there is any. An {@link #endElement} event is also send to the restored
281    * handler.
282    *
283    * @param elementName Current element.
284    * @throws XmlSyntaxException Handler dosen't like this event.
285    */
 
286  180222 toggle private final void restoreHandler(final String elementName) throws XmlSyntaxException {
287  363310 while (level <= 0 && !handlerStack.empty()) {
288  183088 currentHandler = (AbstractSimpleHandler) handlerStack.pop();
289  183088 Trace.param(CLASS, this, "restoreHandler", "currentHandler", currentHandler);
290  183088 level = ((Integer) levelStack.pop()).intValue();
291  183088 currentHandler.endElement(elementName);
292  183088 level--;
293  183088 Trace.param(CLASS, this, "restoreHandler", "level", level);
294    }
295  180222 if (handlerStack.empty()) {
296  4777 Trace.trace(CLASS, this, "restoreHandler", "no handler to restore");
297    }
298    }
299   
300    /**
301    * Get current level.
302    *
303    * @return Current level.
304    */
 
305  52124 toggle public final int getLevel() {
306  52124 return level;
307    }
308   
309    /**
310    * Wraps exception in new {@link SAXParseException} including parsing position information.
311    *
312    * @param e Exception to wrap.
313    * @return Exception to throw.
314    */
 
315  0 toggle public final SAXParseException createSAXParseException(final Exception e) {
316  0 return new SAXParseException(null, getLocator(), e);
317    }
318   
319    /**
320    * Creates new {@link SAXParseException} including parsing position information.
321    *
322    * @param message Problem description.
323    * @return Exception to throw.
324    */
 
325  0 toggle public final SAXParseException createSAXParseException(final String message) {
326  0 return new SAXParseException(message, getLocator());
327    }
328   
329    /**
330    * Create current source area.
331    *
332    * @return Current area.
333    */
 
334  104 toggle public final SourceArea createSourceArea() {
335  104 if (getLocator() != null && getUrl() != null) {
336  104 return new SourceArea(getUrl(), new SourcePosition(getLocator().getLineNumber(), 1),
337    new SourcePosition(getLocator().getLineNumber(), getLocator().getColumnNumber()));
338    }
339  0 return new SourceArea(getUrl());
340    }
341   
342    /**
343    * Get plugin we work for.
344    *
345    * @return Plugin.
346    */
 
347  0 toggle public Plugin getPlugin() {
348  0 return plugin;
349    }
350   
351    }