Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Sa Okt 21 2006 08:24:31 CEST
file stats: LOC: 343   Methods: 17
NCLOC: 165   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SaxDefaultHandler.java 87,5% 73,8% 82,4% 76,9%
coverage coverage
 1    /* $Id: SaxDefaultHandler.java,v 1.20 2006/10/20 20:23:04 m31 Exp $
 2    *
 3    * This file is part of the project "Hilbert II" - http://www.qedeq.org
 4    *
 5    * Copyright 2000-2006, 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.net.URL;
 20    import java.util.Stack;
 21   
 22    import org.qedeq.kernel.log.Trace;
 23    import org.qedeq.kernel.xml.tracker.SourcePosition;
 24    import org.xml.sax.Attributes;
 25    import org.xml.sax.Locator;
 26    import org.xml.sax.SAXException;
 27    import org.xml.sax.SAXParseException;
 28    import org.xml.sax.helpers.DefaultHandler;
 29   
 30   
 31    /**
 32    * Default SAX handler. Delegates SAX events to a
 33    * {@link org.qedeq.kernel.xml.parser.AbstractSimpleHandler}
 34    * which could also delegate events to other
 35    * {@link org.qedeq.kernel.xml.parser.AbstractSimpleHandler}s.
 36    * <p>
 37    * Before anything is parsed the method {@link #setExceptionList(ExceptionList)} must be
 38    * called.
 39    *
 40    * @version $Revision: 1.20 $
 41    * @author Michael Meyling
 42    */
 43    public final class SaxDefaultHandler extends DefaultHandler {
 44   
 45    /** Delegate currently to this handler. */
 46    private AbstractSimpleHandler currentHandler;
 47   
 48    /** Stack of previous {@link AbstractSimpleHandler}s. */
 49    private Stack handlerStack = new Stack();
 50   
 51    /** Top level handler. This handler is activated after the begin of the document. */
 52    private AbstractSimpleHandler basisHandler;
 53   
 54    /** Collect errors in this object. */
 55    private ExceptionList errorList;
 56   
 57    /** Buffer for combining character events. */
 58    private StringBuffer buffer = new StringBuffer(2000);
 59   
 60    /** Locator for current row and column information. */
 61    private Locator locator;
 62   
 63    /** Tag level for current handler. */
 64    private int level;
 65   
 66    /** Tag level for previous handlers. */
 67    private Stack levelStack = new Stack();
 68   
 69    /** Current tag name. Could be <code>null</code>. */
 70    private String currentElementName;
 71   
 72    /** File that is parsed. */
 73    private URL url;
 74   
 75   
 76    /**
 77    * Constructor.
 78    */
 79  108 public SaxDefaultHandler() {
 80  108 super();
 81    }
 82   
 83    /**
 84    * Set parse exception list. This list collects occurring parsing errors.
 85    *
 86    * @param errorList Collect errors here.
 87    */
 88  106 public final void setExceptionList(final ExceptionList errorList) {
 89  106 this.errorList = errorList;
 90    }
 91   
 92    /**
 93    * Receive a Locator object for document events.
 94    * Store the locator for use with other document events.
 95    *
 96    * @param locator A locator for all SAX document events.
 97    * @see org.xml.sax.ContentHandler#setDocumentLocator
 98    * @see org.xml.sax.Locator
 99    */
 100  106 public final void setDocumentLocator(final Locator locator) {
 101  106 this.locator = locator;
 102    }
 103   
 104    /**
 105    * Set basis handler for documents.
 106    *
 107    * @param handler Basis handler for documents. This handler might also pass control to
 108    * another handler via the
 109    * {@link AbstractSimpleHandler#changeHandler(AbstractSimpleHandler, String, SimpleAttributes)}
 110    * method.
 111    */
 112  108 public final void setBasisDocumentHandler(final AbstractSimpleHandler handler) {
 113  108 basisHandler = handler;
 114  108 currentHandler = handler;
 115  108 handlerStack.clear();
 116  108 level = 0;
 117    }
 118   
 119    /* (non-Javadoc)
 120    * @see org.xml.sax.helpers.DefaultHandler#startDocument()
 121    */
 122  106 public final void startDocument() throws SAXException {
 123  106 sendCharacters();
 124  106 currentHandler = basisHandler;
 125  106 handlerStack.clear();
 126  106 level = 0;
 127  106 currentElementName = null;
 128    }
 129   
 130    /* (non-Javadoc)
 131    * @see org.xml.sax.helpers.DefaultHandler#endDocument()
 132    */
 133  106 public final void endDocument() throws SAXException {
 134  106 sendCharacters();
 135  106 currentElementName = null;
 136    }
 137   
 138    /* (non-Javadoc)
 139    * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
 140    * java.lang.String, org.xml.sax.Attributes)
 141    */
 142  12383 public final void startElement(final String uri, final String localName, final String qName,
 143    final Attributes amap) throws SAXException {
 144  12383 final String method = "startElement";
 145  12383 try {
 146  12383 Trace.traceParam(this, method, "currentHandler", currentHandler.getClass().getName());
 147  12383 if (handlerStack.empty() && level == 0) {
 148  106 currentHandler.init();
 149    }
 150  12383 level++;
 151  12383 sendCharacters();
 152  12383 currentElementName = localName;
 153  12383 final SimpleAttributes attributes = new SimpleAttributes();
 154  12383 for (int i = 0; i < amap.getLength(); i++) {
 155  13946 attributes.add(amap.getQName(i), amap.getValue(i));
 156    }
 157  12383 Trace.traceParam(this, method, "localName", localName);
 158  12383 Trace.traceParam(this, method, "attributes", attributes);
 159  12383 currentHandler.startElement(localName, attributes);
 160    } catch (SyntaxException e) {
 161  0 Trace.trace(this, method, e);
 162  0 errorList.add(e);
 163    } catch (RuntimeException e) {
 164  0 Trace.trace(this, method, e);
 165  0 errorList.add(new SAXParseException(qName, locator, e));
 166    }
 167    }
 168   
 169    /* (non-Javadoc)
 170    * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
 171    * java.lang.String)
 172    */
 173  12383 public final void endElement(final String uri, final String localName, final String qName)
 174    throws SAXException {
 175  12383 sendCharacters();
 176  12383 final String method = "endElement";
 177  12383 try {
 178  12383 Trace.traceParam(this, method, "currentHandler", currentHandler.getClass().getName());
 179  12383 Trace.traceParam(this, method, "localName", localName);
 180  12383 currentHandler.endElement(localName);
 181    } catch (SyntaxException e) {
 182  0 Trace.trace(this, method, e);
 183  0 setLocationInformation(e);
 184  0 errorList.add(e);
 185    } catch (RuntimeException e) {
 186  0 Trace.trace(this, method, e);
 187  0 errorList.add(new SAXParseException(qName, locator, e));
 188    }
 189  12383 try {
 190  12383 currentElementName = null;
 191  12383 level--;
 192  12383 if (level <= 0) {
 193  3605 restoreHandler(localName);
 194    }
 195    } catch (SyntaxException e) {
 196  0 Trace.trace(this, method, e);
 197  0 errorList.add(e);
 198    } catch (RuntimeException e) {
 199  0 Trace.trace(this, method, e);
 200  0 errorList.add(new SAXParseException(qName, locator, e));
 201    }
 202    }
 203   
 204    /* (non-Javadoc)
 205    * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
 206    */
 207  29729 public final void characters(final char[] ch, final int start, final int length) {
 208  29729 buffer.append(ch, start, length);
 209    }
 210   
 211    /**
 212    * Sends <code>characters</code> event to current handler.
 213    *
 214    * @throws SAXException Caused by overrun of {@link ExceptionList}.
 215    */
 216  24978 private void sendCharacters() throws SAXException {
 217  24978 try {
 218  24978 if (buffer.length() > 0) {
 219  20808 final String str = buffer.toString().trim();
 220  20808 buffer.setLength(0);
 221  20808 if (str.length() > 0) {
 222  2678 currentHandler.characters(currentElementName, str);
 223    }
 224    }
 225    } catch (SyntaxException e) {
 226  0 setLocationInformation(e);
 227  0 Trace.trace(this, "startElement", e);
 228  0 errorList.add(e);
 229    } catch (RuntimeException e) {
 230  0 Trace.trace(this, "startElement", e);
 231  0 errorList.add(new SAXParseException(null, locator, e));
 232    }
 233    }
 234   
 235    /**
 236    * Change current handler to new one. The new handler is initialized by calling
 237    * {@link AbstractSimpleHandler#init()}.
 238    * The new handler also gets a {@link AbstractSimpleHandler#startElement(String,
 239    * SimpleAttributes)} event.
 240    * The current handler is stacked. After the new handler gets the appropriate endElement
 241    * event, the control is switched back to the old handler.
 242    * <p>
 243    * The switch back is also done, if the tag level gets back to the same number. That means
 244    * if for example the new handler starts with the <code>&lt;banana&gt;</code> tag, the
 245    * old handler is restored when the misspelled <code>&lt;/bnana&gt</code> tag occurs:
 246    * <p>
 247    * <pre>
 248    * &lt;banana&gt;
 249    * &lt;one /&gt;
 250    * &lt;two &gt;
 251    * &lt;one /&gt;
 252    * &lt;one /&gt;
 253    * &lt;/two &gt;
 254    * &lt;/bnana&gt
 255    * </pre>
 256    *
 257    * @param newHandler This handler gets the new events.
 258    * @param elementName Element name.
 259    * @param attributes Element attributes.
 260    * @throws SyntaxException New Handler detected a semantic problem.
 261    */
 262  3552 public final void changeHandler(final AbstractSimpleHandler newHandler,
 263    final String elementName, final SimpleAttributes attributes)
 264    throws SyntaxException {
 265  3552 handlerStack.push(currentHandler);
 266  3552 levelStack.push(new Integer(level));
 267  3552 currentHandler = newHandler;
 268  3552 level = 0;
 269  3552 level++;
 270  3552 currentHandler.init();
 271  3552 currentHandler.startElement(elementName, attributes);
 272    }
 273   
 274    /**
 275    * Restore previous handler if there is any. An endElement event is also send to the restored
 276    * handler.
 277    *
 278    * @param elementName
 279    * @throws SyntaxException
 280    */
 281  3605 private final void restoreHandler(final String elementName) throws SyntaxException {
 282  3605 while (level <= 0 && !handlerStack.empty()) {
 283  3552 currentHandler = (AbstractSimpleHandler) handlerStack.pop();
 284  3552 level = ((Integer) levelStack.pop()).intValue();
 285  3552 currentHandler.endElement(elementName);
 286  3552 level--;
 287    }
 288  3605 if (handlerStack.empty()) {
 289    // TODO mime 20050205: is this occurrence an error???
 290  217 Trace.trace(this, "restoreHandler", "no handler to restore");
 291    }
 292    }
 293   
 294    /**
 295    * Get current level.
 296    *
 297    * @return Current level.
 298    */
 299  942 public final int getLevel() {
 300  942 return level;
 301    }
 302   
 303    /**
 304    * Wraps exception in new {@link SAXParseException} including parsing position information.
 305    *
 306    * @param e Exception to wrap.
 307    * @return Exception to throw.
 308    */
 309  0 public final SAXParseException createSAXParseException(final Exception e) {
 310  0 return new SAXParseException(null, locator, e);
 311    }
 312   
 313    /**
 314    * Creates new {@link SAXParseException} including parsing position information.
 315    *
 316    * @param message Problem description.
 317    * @return Exception to throw.
 318    */
 319  0 public final SAXParseException createSAXParseException(final String message) {
 320  0 return new SAXParseException(message, locator);
 321    }
 322   
 323    /**
 324    * Set current location information within an {@link SyntaxException}.
 325    *
 326    * @param e Set location information within this exception.
 327    */
 328  0 private final void setLocationInformation(final SyntaxException e) {
 329  0 if (locator != null && url != null) {
 330  0 e.setErrorPosition(new SourcePosition(url, locator.getLineNumber(),
 331    locator.getColumnNumber()));
 332    }
 333    }
 334   
 335    /**
 336    * Set file that is parsed.
 337    *
 338    * @param url This file is parsed.
 339    */
 340  106 public final void setUrl(final URL url) {
 341  106 this.url = url;
 342    }
 343    }