Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Do Jan 11 2007 09:03:50 CET
file stats: LOC: 343   Methods: 17
NCLOC: 165   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SaxDefaultHandler.java 87,5% 74,1% 82,4% 77,1%
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.xml.sax.Attributes;
 24    import org.xml.sax.Locator;
 25    import org.xml.sax.SAXException;
 26    import org.xml.sax.SAXParseException;
 27    import org.xml.sax.helpers.DefaultHandler;
 28   
 29   
 30    /**
 31    * Default SAX handler. Delegates SAX events to a
 32    * {@link org.qedeq.kernel.xml.parser.AbstractSimpleHandler}
 33    * which could also delegate events to other
 34    * {@link org.qedeq.kernel.xml.parser.AbstractSimpleHandler}s.
 35    * <p>
 36    * Before anything is parsed the method {@link #setExceptionList(ExceptionList)} must be
 37    * called.
 38    *
 39    * @version $Revision: 1.20 $
 40    * @author Michael Meyling
 41    */
 42    public final class SaxDefaultHandler extends DefaultHandler {
 43   
 44    /** Delegate currently to this handler. */
 45    private AbstractSimpleHandler currentHandler;
 46   
 47    /** Stack of previous {@link AbstractSimpleHandler}s. */
 48    private Stack handlerStack = new Stack();
 49   
 50    /** Top level handler. This handler is activated after the begin of the document. */
 51    private AbstractSimpleHandler basisHandler;
 52   
 53    /** Collect errors in this object. */
 54    private ExceptionList errorList;
 55   
 56    /** Buffer for combining character events. */
 57    private StringBuffer buffer = new StringBuffer(2000);
 58   
 59    /** Locator for current row and column information. */
 60    private Locator locator;
 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    /** File that is parsed. */
 72    private URL url;
 73   
 74   
 75    /**
 76    * Constructor.
 77    */
 78  250 public SaxDefaultHandler() {
 79  250 super();
 80    }
 81   
 82    /**
 83    * Set parse exception list. This list collects occurring parsing errors.
 84    *
 85    * @param errorList Collect errors here.
 86    */
 87  248 public final void setExceptionList(final ExceptionList errorList) {
 88  248 this.errorList = errorList;
 89    }
 90   
 91    /**
 92    * Receive a Locator object for document events.
 93    * Store the locator for use with other document events.
 94    *
 95    * @param locator A locator for all SAX document events.
 96    * @see org.xml.sax.ContentHandler#setDocumentLocator
 97    * @see org.xml.sax.Locator
 98    */
 99  248 public final void setDocumentLocator(final Locator locator) {
 100  248 this.locator = locator;
 101    }
 102   
 103    /**
 104    * Set basis handler for documents.
 105    *
 106    * @param handler Basis handler for documents. This handler might also pass control to
 107    * another handler via the
 108    * {@link AbstractSimpleHandler#changeHandler(AbstractSimpleHandler, String, SimpleAttributes)}
 109    * method.
 110    */
 111  250 public final void setBasisDocumentHandler(final AbstractSimpleHandler handler) {
 112  250 basisHandler = handler;
 113  250 currentHandler = handler;
 114  250 handlerStack.clear();
 115  250 level = 0;
 116    }
 117   
 118    /* (non-Javadoc)
 119    * @see org.xml.sax.helpers.DefaultHandler#startDocument()
 120    */
 121  248 public final void startDocument() throws SAXException {
 122  248 sendCharacters();
 123  248 currentHandler = basisHandler;
 124  248 handlerStack.clear();
 125  248 level = 0;
 126  248 currentElementName = null;
 127    }
 128   
 129    /* (non-Javadoc)
 130    * @see org.xml.sax.helpers.DefaultHandler#endDocument()
 131    */
 132  248 public final void endDocument() throws SAXException {
 133  248 sendCharacters();
 134  248 currentElementName = null;
 135    }
 136   
 137    /* (non-Javadoc)
 138    * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
 139    * java.lang.String, org.xml.sax.Attributes)
 140    */
 141  13352 public final void startElement(final String uri, final String localName, final String qName,
 142    final Attributes amap) throws SAXException {
 143  13352 final String method = "startElement";
 144  13352 try {
 145  13352 Trace.param(this, method, "currentHandler", currentHandler.getClass().getName());
 146  13352 Trace.param(this, method, "localName", localName);
 147  13352 Trace.param(this, method, "qName", qName);
 148  13352 if (handlerStack.empty() && level == 0) {
 149  248 currentHandler.init();
 150    }
 151  13352 level++;
 152  13352 sendCharacters();
 153  13352 currentElementName = localName;
 154  13352 final SimpleAttributes attributes = new SimpleAttributes();
 155  13352 for (int i = 0; i < amap.getLength(); i++) {
 156  14493 attributes.add(amap.getQName(i), amap.getValue(i));
 157    }
 158  13352 Trace.param(this, method, "attributes", attributes);
 159  13352 currentHandler.startElement(qName, 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  13352 public final void endElement(final String uri, final String localName, final String qName)
 174    throws SAXException {
 175  13352 sendCharacters();
 176  13352 final String method = "endElement";
 177  13352 try {
 178  13352 Trace.param(this, method, "currentHandler", currentHandler.getClass().getName());
 179  13352 Trace.param(this, method, "localName", localName);
 180  13352 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  13352 try {
 190  13352 currentElementName = null;
 191  13352 level--;
 192  13352 if (level <= 0) {
 193  3861 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  31595 public final void characters(final char[] ch, final int start, final int length) {
 208  31595 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  27200 private void sendCharacters() throws SAXException {
 217  27200 try {
 218  27200 if (buffer.length() > 0) {
 219  21847 final String str = buffer.toString().trim();
 220  21847 buffer.setLength(0);
 221  21847 if (str.length() > 0) {
 222  2748 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  3666 public final void changeHandler(final AbstractSimpleHandler newHandler,
 263    final String elementName, final SimpleAttributes attributes)
 264    throws SyntaxException {
 265  3666 handlerStack.push(currentHandler);
 266  3666 levelStack.push(new Integer(level));
 267  3666 currentHandler = newHandler;
 268  3666 level = 0;
 269  3666 level++;
 270  3666 currentHandler.init();
 271  3666 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  3861 private final void restoreHandler(final String elementName) throws SyntaxException {
 282  3861 while (level <= 0 && !handlerStack.empty()) {
 283  3666 currentHandler = (AbstractSimpleHandler) handlerStack.pop();
 284  3666 level = ((Integer) levelStack.pop()).intValue();
 285  3666 currentHandler.endElement(elementName);
 286  3666 level--;
 287    }
 288  3861 if (handlerStack.empty()) {
 289    // TODO mime 20050205: is this occurrence an error???
 290  365 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  248 public final void setUrl(final URL url) {
 341  248 this.url = url;
 342    }
 343    }