Clover Coverage Report
Coverage timestamp: Sa Aug 2 2008 13:56:27 CEST
../../../../../img/srcFileCovDistChart7.png 62% of files have more coverage
103   357   37   6,44
18   193   0,36   16
16     2,31  
1    
 
  SaxDefaultHandler       Line # 44 103 37 67,2% 0.67153287
 
  (134)
 
1    /* $Id: SaxDefaultHandler.java,v 1.1 2008/07/26 08:00:50 m31 Exp $
2    *
3    * This file is part of the project "Hilbert II" - http://www.qedeq.org
4    *
5    * Copyright 2000-2008, Michael Meyling <mime@qedeq.org>.
6    *
7    * "Hilbert II" is free software; you can redistribute
8    * it and/or modify it under the terms of the GNU General Public
9    * License as published by the Free Software Foundation; either
10    * version 2 of the License, or (at your option) any later version.
11    *
12    * This program is distributed in the hope that it will be useful,
13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15    * GNU General Public License for more details.
16    */
17    package org.qedeq.kernel.xml.parser;
18   
19    import java.util.Stack;
20   
21    import org.qedeq.base.trace.Trace;
22    import org.qedeq.kernel.common.DefaultSourceFileExceptionList;
23    import org.qedeq.kernel.common.SourceArea;
24    import org.qedeq.kernel.common.SourceFileException;
25    import org.qedeq.kernel.common.SourcePosition;
26    import org.qedeq.kernel.xml.common.XmlSyntaxException;
27    import org.xml.sax.Attributes;
28    import org.xml.sax.SAXException;
29    import org.xml.sax.SAXParseException;
30   
31   
32    /**
33    * Default SAX handler. Delegates SAX events to a
34    * {@link org.qedeq.kernel.xml.parser.AbstractSimpleHandler}
35    * which could also delegate events to other
36    * {@link org.qedeq.kernel.xml.parser.AbstractSimpleHandler}s.
37    * <p>
38    * Before anything is parsed the method {@link #setExceptionList(DefaultSourceFileExceptionList)}
39    * must be called.
40    *
41    * @version $Revision: 1.1 $
42    * @author Michael Meyling
43    */
 
44    public class SaxDefaultHandler extends SimpleHandler {
45   
46    /** This class. */
47    private static final Class CLASS = SaxDefaultHandler.class;
48   
49    /** Delegate currently to this handler. */
50    private AbstractSimpleHandler currentHandler;
51   
52    /** Stack of previous {@link AbstractSimpleHandler}s. */
53    private Stack handlerStack = new Stack();
54   
55    /** Top level handler. This handler is activated after the begin of the document. */
56    private AbstractSimpleHandler basisHandler;
57   
58    /** Collect errors in this object. */
59    private DefaultSourceFileExceptionList errorList;
60   
61    /** Buffer for combining character events. */
62    private StringBuffer buffer = new StringBuffer(2000);
63   
64    /** Tag level for current handler. */
65    private int level;
66   
67    /** Tag level for previous handlers. */
68    private Stack levelStack = new Stack();
69   
70    /** Current tag name. Could be <code>null</code>. */
71    private String currentElementName;
72   
73    /**
74    * Constructor.
75    */
 
76  371 toggle public SaxDefaultHandler() {
77  371 super();
78    }
79   
80    /**
81    * Set parse exception list. This list collects occurring parsing errors.
82    *
83    * @param errorList Collect errors here.
84    */
 
85  363 toggle public void setExceptionList(final DefaultSourceFileExceptionList errorList) {
86  363 this.errorList = errorList;
87    }
88   
89    /**
90    * Set basis handler for documents.
91    *
92    * @param handler Basis handler for documents. This handler might also pass control to
93    * another handler via the
94    * {@link AbstractSimpleHandler#changeHandler(AbstractSimpleHandler, String, SimpleAttributes)}
95    * method.
96    */
 
97  371 toggle public final void setBasisDocumentHandler(final AbstractSimpleHandler handler) {
98  371 basisHandler = handler;
99  371 currentHandler = handler;
100  371 handlerStack.clear();
101  371 level = 0;
102    }
103   
104    /* (non-Javadoc)
105    * @see org.xml.sax.helpers.DefaultHandler#startDocument()
106    */
 
107  363 toggle public final void startDocument() throws SAXException {
108  363 sendCharacters();
109  363 currentHandler = basisHandler;
110  363 handlerStack.clear();
111  363 level = 0;
112  363 currentElementName = null;
113    }
114   
115    /* (non-Javadoc)
116    * @see org.xml.sax.helpers.DefaultHandler#endDocument()
117    */
 
118  363 toggle public final void endDocument() throws SAXException {
119  363 sendCharacters();
120  363 currentElementName = null;
121    }
122   
123    /* (non-Javadoc)
124    * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
125    * java.lang.String, org.xml.sax.Attributes)
126    */
 
127  42520 toggle public final void startElement(final String uri, final String localName, final String qName,
128    final Attributes amap) throws SAXException {
129  42520 final String method = "startElement";
130  42520 try {
131  42520 Trace.param(CLASS, this, method, "currentHandler", currentHandler.getClass().getName());
132  42520 Trace.param(CLASS, this, method, "localName", localName);
133  42520 Trace.param(CLASS, this, method, "qName", qName);
134  42520 if (handlerStack.empty() && level == 0) {
135  363 currentHandler.init();
136    }
137  42520 level++;
138  42520 Trace.param(CLASS, this, method, "level", level);
139  42520 sendCharacters();
140  42520 currentElementName = localName;
141  42520 final SimpleAttributes attributes = new SimpleAttributes();
142  77924 for (int i = 0; i < amap.getLength(); i++) {
143  35404 attributes.add(amap.getQName(i), amap.getValue(i));
144    }
145  42520 Trace.param(CLASS, this, method, "attributes", attributes);
146  42520 currentHandler.startElement(qName, attributes);
147    } catch (XmlSyntaxException e) {
148  0 Trace.trace(CLASS, this, method, e);
149  0 setLocationInformation(e);
150  0 errorList.add(new SourceFileException(e, createSourceArea(), null));
151    } catch (RuntimeException e) {
152  0 Trace.trace(CLASS, this, method, e);
153  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
154  0 setLocationInformation(ex);
155  0 final SourceFileException sfe = new SourceFileException(ex.getErrorCode(),
156    ex.getMessage(), ex,
157    createSourceArea(),
158    null);
159  0 errorList.add(sfe);
160    }
161    }
162   
163    /* (non-Javadoc)
164    * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
165    * java.lang.String)
166    */
 
167  42520 toggle public final void endElement(final String uri, final String localName, final String qName)
168    throws SAXException {
169  42520 sendCharacters();
170  42520 final String method = "endElement";
171  42520 try {
172  42520 Trace.param(CLASS, this, method, "currentHandler", currentHandler.getClass().getName());
173  42520 Trace.param(CLASS, this, method, "localName", localName);
174  42520 currentHandler.endElement(localName);
175    } catch (XmlSyntaxException e) {
176  0 Trace.trace(CLASS, this, method, e);
177  0 setLocationInformation(e);
178  0 errorList.add(new SourceFileException(e, createSourceArea(), null));
179    } catch (RuntimeException e) {
180  0 Trace.trace(CLASS, this, method, e);
181  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
182  0 setLocationInformation(ex);
183  0 errorList.add(new SourceFileException(ex, createSourceArea(), null));
184    }
185  42520 try {
186  42520 currentElementName = null;
187  42520 level--;
188  42520 Trace.param(CLASS, this, method, "level", level);
189  42520 if (level <= 0) {
190  12564 restoreHandler(localName);
191    }
192    } catch (XmlSyntaxException e) {
193  0 Trace.trace(CLASS, this, method, e);
194  0 setLocationInformation(e);
195  0 final SourceFileException sfe = new SourceFileException(e.getErrorCode(),
196    e.getMessage(), e,
197    createSourceArea(),
198    null);
199  0 errorList.add(sfe);
200    } catch (RuntimeException e) {
201  0 Trace.trace(CLASS, this, method, e);
202  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
203  0 setLocationInformation(ex);
204  0 errorList.add(new SourceFileException(ex, createSourceArea(), null));
205    }
206    }
207   
208    /* (non-Javadoc)
209    * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
210    */
 
211  102377 toggle public final void characters(final char[] ch, final int start, final int length) {
212  102377 buffer.append(ch, start, length);
213    }
214   
215    /**
216    * Sends <code>characters</code> event to current handler.
217    */
 
218  85766 toggle private void sendCharacters() {
219  85766 try {
220  85766 if (buffer.length() > 0) {
221  72544 final String str = buffer.toString().trim();
222  72544 buffer.setLength(0);
223  72544 if (str.length() > 0) {
224  9345 currentHandler.characters(currentElementName, str);
225    }
226    }
227    } catch (XmlSyntaxException e) {
228  0 Trace.trace(CLASS, this, "sendCharacters", e);
229  0 setLocationInformation(e);
230  0 errorList.add(new SourceFileException(e, createSourceArea(), null));
231    } catch (RuntimeException e) {
232  0 Trace.trace(CLASS, this, "sendCharacters", e);
233  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
234  0 setLocationInformation(ex);
235  0 errorList.add(new SourceFileException(ex, 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  12384 toggle public final void changeHandler(final AbstractSimpleHandler newHandler,
267    final String elementName, final SimpleAttributes attributes)
268    throws XmlSyntaxException {
269  12384 handlerStack.push(currentHandler);
270  12384 levelStack.push(new Integer(level));
271  12384 currentHandler = newHandler;
272  12384 level = 0;
273  12384 level++;
274  12384 Trace.param(CLASS, this, "changeHandler", "level", level);
275  12384 currentHandler.init();
276  12384 currentHandler.startElement(elementName, attributes);
277    }
278   
279    /**
280    * Restore previous handler if there is any. An endElement event is also send to the restored
281    * handler.
282    *
283    * @param elementName
284    * @throws XmlSyntaxException
285    */
 
286  12564 toggle private final void restoreHandler(final String elementName) throws XmlSyntaxException {
287  24948 while (level <= 0 && !handlerStack.empty()) {
288  12384 currentHandler = (AbstractSimpleHandler) handlerStack.pop();
289  12384 Trace.param(CLASS, this, "restoreHandler", "currentHandler", currentHandler);
290  12384 level = ((Integer) levelStack.pop()).intValue();
291  12384 currentHandler.endElement(elementName);
292  12384 level--;
293  12384 Trace.param(CLASS, this, "restoreHandler", "level", level);
294    }
295  12564 if (handlerStack.empty()) {
296  816 Trace.trace(CLASS, this, "restoreHandler", "no handler to restore");
297    }
298    }
299   
300    /**
301    * Get current level.
302    *
303    * @return Current level.
304    */
 
305  3028 toggle public final int getLevel() {
306  3028 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    * Set current location information within an {@link XmlSyntaxException}.
331    *
332    * @param e Set location information within this exception.
333    */
 
334  0 toggle private final void setLocationInformation(final XmlSyntaxException e) {
335  0 if (getLocator() != null && getUrl() != null) {
336  0 e.setErrorPosition(new SourcePosition(getUrl(), getLocator().getLineNumber(),
337    getLocator().getColumnNumber()));
338    }
339    }
340   
341    /**
342    * Create current source area.
343    *
344    * @return Current area.
345    */
 
346  0 toggle private final SourceArea createSourceArea() {
347  0 if (getLocator() != null && getUrl() != null) {
348  0 return new SourceArea(getUrl(), new SourcePosition(getUrl(),
349    getLocator().getLineNumber(), 1),
350    new SourcePosition(getUrl(), getLocator().getLineNumber(),
351    getLocator().getColumnNumber()));
352    }
353  0 return new SourceArea(getUrl(), new SourcePosition(getUrl(), 1 , 1),
354    new SourcePosition(getUrl(), 1 , 1));
355    }
356   
357    }