Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Sa Dez 22 2007 01:35:21 CET
file stats: LOC: 394   Methods: 20
NCLOC: 198   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SaxDefaultHandler.java 77,8% 65,7% 75% 68,5%
coverage coverage
 1    /* $Id: SaxDefaultHandler.java,v 1.28 2007/12/21 23:33:46 m31 Exp $
 2    *
 3    * This file is part of the project "Hilbert II" - http://www.qedeq.org
 4    *
 5    * Copyright 2000-2007, 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.common.SourceArea;
 23    import org.qedeq.kernel.common.SourceFileException;
 24    import org.qedeq.kernel.common.SourceFileExceptionList;
 25    import org.qedeq.kernel.common.SourcePosition;
 26    import org.qedeq.kernel.trace.Trace;
 27    import org.qedeq.kernel.xml.common.XmlSyntaxException;
 28    import org.xml.sax.Attributes;
 29    import org.xml.sax.Locator;
 30    import org.xml.sax.SAXException;
 31    import org.xml.sax.SAXParseException;
 32    import org.xml.sax.helpers.DefaultHandler;
 33   
 34   
 35    /**
 36    * Default SAX handler. Delegates SAX events to a
 37    * {@link org.qedeq.kernel.xml.parser.AbstractSimpleHandler}
 38    * which could also delegate events to other
 39    * {@link org.qedeq.kernel.xml.parser.AbstractSimpleHandler}s.
 40    * <p>
 41    * Before anything is parsed the method {@link #setExceptionList(DefaultSourceFileExceptionList)}
 42    * must be called.
 43    *
 44    * @version $Revision: 1.28 $
 45    * @author Michael Meyling
 46    */
 47    public class SaxDefaultHandler extends DefaultHandler {
 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    /** Locator for current row and column information. */
 65    private Locator locator;
 66   
 67    /** Tag level for current handler. */
 68    private int level;
 69   
 70    /** Tag level for previous handlers. */
 71    private Stack levelStack = new Stack();
 72   
 73    /** Current tag name. Could be <code>null</code>. */
 74    private String currentElementName;
 75   
 76    /** File that is parsed. */
 77    private URL url;
 78   
 79   
 80    /**
 81    * Constructor.
 82    */
 83  724 public SaxDefaultHandler() {
 84  724 super();
 85    }
 86   
 87    /**
 88    * Set parse exception list. This list collects occurring parsing errors.
 89    *
 90    * @param errorList Collect errors here.
 91    */
 92  702 public void setExceptionList(final DefaultSourceFileExceptionList errorList) {
 93  702 this.errorList = errorList;
 94    }
 95   
 96    /**
 97    * Get parse exception list. This list collects occurring parsing errors.
 98    *
 99    * @return Collected errors.
 100    */
 101  0 public SourceFileExceptionList getExceptionList() {
 102  0 return errorList;
 103    }
 104   
 105    /**
 106    * Receive a Locator object for document events.
 107    * Store the locator for use with other document events.
 108    *
 109    * @param locator A locator for all SAX document events.
 110    * @see org.xml.sax.ContentHandler#setDocumentLocator
 111    * @see org.xml.sax.Locator
 112    */
 113  702 public void setDocumentLocator(final Locator locator) {
 114  702 this.locator = locator;
 115    }
 116   
 117    /**
 118    * Set basis handler for documents.
 119    *
 120    * @param handler Basis handler for documents. This handler might also pass control to
 121    * another handler via the
 122    * {@link AbstractSimpleHandler#changeHandler(AbstractSimpleHandler, String, SimpleAttributes)}
 123    * method.
 124    */
 125  724 public final void setBasisDocumentHandler(final AbstractSimpleHandler handler) {
 126  724 basisHandler = handler;
 127  724 currentHandler = handler;
 128  724 handlerStack.clear();
 129  724 level = 0;
 130    }
 131   
 132    /* (non-Javadoc)
 133    * @see org.xml.sax.helpers.DefaultHandler#startDocument()
 134    */
 135  702 public final void startDocument() throws SAXException {
 136  702 sendCharacters();
 137  702 currentHandler = basisHandler;
 138  702 handlerStack.clear();
 139  702 level = 0;
 140  702 currentElementName = null;
 141    }
 142   
 143    /* (non-Javadoc)
 144    * @see org.xml.sax.helpers.DefaultHandler#endDocument()
 145    */
 146  702 public final void endDocument() throws SAXException {
 147  702 sendCharacters();
 148  702 currentElementName = null;
 149    }
 150   
 151    /* (non-Javadoc)
 152    * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
 153    * java.lang.String, org.xml.sax.Attributes)
 154    */
 155  65377 public final void startElement(final String uri, final String localName, final String qName,
 156    final Attributes amap) throws SAXException {
 157  65375 final String method = "startElement";
 158  65375 try {
 159  65375 Trace.param(this, method, "currentHandler", currentHandler.getClass().getName());
 160  65377 Trace.param(this, method, "localName", localName);
 161  65377 Trace.param(this, method, "qName", qName);
 162  65377 if (handlerStack.empty() && level == 0) {
 163  702 currentHandler.init();
 164    }
 165  65377 level++;
 166  65377 Trace.param(this, method, "level", level);
 167  65377 sendCharacters();
 168  65377 currentElementName = localName;
 169  65377 final SimpleAttributes attributes = new SimpleAttributes();
 170  65377 for (int i = 0; i < amap.getLength(); i++) {
 171  50637 attributes.add(amap.getQName(i), amap.getValue(i));
 172    }
 173  65377 Trace.param(this, method, "attributes", attributes);
 174  65377 currentHandler.startElement(qName, attributes);
 175    } catch (XmlSyntaxException e) {
 176  0 Trace.trace(this, method, e);
 177  0 setLocationInformation(e);
 178  0 errorList.add(new SourceFileException(e, createSourceArea(), null));
 179    } catch (RuntimeException e) {
 180  0 Trace.trace(this, method, e);
 181  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
 182  0 setLocationInformation(ex);
 183  0 errorList.add(ex);
 184    }
 185    }
 186   
 187    /* (non-Javadoc)
 188    * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
 189    * java.lang.String)
 190    */
 191  65377 public final void endElement(final String uri, final String localName, final String qName)
 192    throws SAXException {
 193  65376 sendCharacters();
 194  65376 final String method = "endElement";
 195  65375 try {
 196  65375 Trace.param(this, method, "currentHandler", currentHandler.getClass().getName());
 197  65377 Trace.param(this, method, "localName", localName);
 198  65377 currentHandler.endElement(localName);
 199    } catch (XmlSyntaxException e) {
 200  0 Trace.trace(this, method, e);
 201  0 setLocationInformation(e);
 202  0 errorList.add(new SourceFileException(e, createSourceArea(), null));
 203    } catch (RuntimeException e) {
 204  0 Trace.trace(this, method, e);
 205  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
 206  0 setLocationInformation(ex);
 207  0 errorList.add(new SourceFileException(ex, createSourceArea(), null));
 208    }
 209  65377 try {
 210  65377 currentElementName = null;
 211  65377 level--;
 212  65377 Trace.param(this, method, "level", level);
 213  65377 if (level <= 0) {
 214  20915 restoreHandler(localName);
 215    }
 216    } catch (XmlSyntaxException e) {
 217  0 Trace.trace(this, method, e);
 218  0 setLocationInformation(e);
 219  0 errorList.add(e);
 220    } catch (RuntimeException e) {
 221  0 Trace.trace(this, method, e);
 222  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
 223  0 setLocationInformation(ex);
 224  0 errorList.add(new SourceFileException(ex, createSourceArea(), null));
 225    }
 226    }
 227   
 228    /* (non-Javadoc)
 229    * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
 230    */
 231  161883 public final void characters(final char[] ch, final int start, final int length) {
 232  161882 buffer.append(ch, start, length);
 233    }
 234   
 235    /**
 236    * Sends <code>characters</code> event to current handler.
 237    */
 238  132149 private void sendCharacters() {
 239  132149 try {
 240  132149 if (buffer.length() > 0) {
 241  112752 final String str = buffer.toString().trim();
 242  112756 buffer.setLength(0);
 243  112755 if (str.length() > 0) {
 244  14119 currentHandler.characters(currentElementName, str);
 245    }
 246    }
 247    } catch (XmlSyntaxException e) {
 248  0 Trace.trace(this, "sendCharacters", e);
 249  0 setLocationInformation(e);
 250  0 errorList.add(new SourceFileException(e, createSourceArea(), null));
 251    } catch (RuntimeException e) {
 252  0 Trace.trace(this, "sendCharacters", e);
 253  0 final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
 254  0 setLocationInformation(ex);
 255  0 errorList.add(new SourceFileException(ex, createSourceArea(), null));
 256    }
 257    }
 258   
 259    /**
 260    * Change current handler to new one. The new handler is initialized by calling
 261    * {@link AbstractSimpleHandler#init()}.
 262    * The new handler also gets a {@link AbstractSimpleHandler#startElement(String,
 263    * SimpleAttributes)} event.
 264    * The current handler is stacked. After the new handler gets the appropriate endElement
 265    * event, the control is switched back to the old handler.
 266    * <p>
 267    * The switch back is also done, if the tag level gets back to the same number. That means
 268    * if for example the new handler starts with the <code>&lt;banana&gt;</code> tag, the
 269    * old handler is restored when the misspelled <code>&lt;/bnana&gt</code> tag occurs:
 270    * <p>
 271    * <pre>
 272    * &lt;banana&gt;
 273    * &lt;one /&gt;
 274    * &lt;two &gt;
 275    * &lt;one /&gt;
 276    * &lt;one /&gt;
 277    * &lt;/two &gt;
 278    * &lt;/bnana&gt
 279    * </pre>
 280    *
 281    * @param newHandler This handler gets the new events.
 282    * @param elementName Element name.
 283    * @param attributes Element attributes.
 284    * @throws XmlSyntaxException New Handler detected a semantic problem.
 285    */
 286  20450 public final void changeHandler(final AbstractSimpleHandler newHandler,
 287    final String elementName, final SimpleAttributes attributes)
 288    throws XmlSyntaxException {
 289  20450 handlerStack.push(currentHandler);
 290  20451 levelStack.push(new Integer(level));
 291  20451 currentHandler = newHandler;
 292  20451 level = 0;
 293  20451 level++;
 294  20451 Trace.param(this, "changeHandler", "level", level);
 295  20451 currentHandler.init();
 296  20451 currentHandler.startElement(elementName, attributes);
 297    }
 298   
 299    /**
 300    * Restore previous handler if there is any. An endElement event is also send to the restored
 301    * handler.
 302    *
 303    * @param elementName
 304    * @throws XmlSyntaxException
 305    */
 306  20915 private final void restoreHandler(final String elementName) throws XmlSyntaxException {
 307  20915 while (level <= 0 && !handlerStack.empty()) {
 308  20451 currentHandler = (AbstractSimpleHandler) handlerStack.pop();
 309  20451 Trace.param(this, "restoreHandler", "currentHandler", currentHandler);
 310  20451 level = ((Integer) levelStack.pop()).intValue();
 311  20451 currentHandler.endElement(elementName);
 312  20451 level--;
 313  20451 Trace.param(this, "restoreHandler", "level", level);
 314    }
 315  20915 if (handlerStack.empty()) {
 316  1938 Trace.trace(this, "restoreHandler", "no handler to restore");
 317    }
 318    }
 319   
 320    /**
 321    * Get current level.
 322    *
 323    * @return Current level.
 324    */
 325  4002 public final int getLevel() {
 326  4002 return level;
 327    }
 328   
 329    /**
 330    * Wraps exception in new {@link SAXParseException} including parsing position information.
 331    *
 332    * @param e Exception to wrap.
 333    * @return Exception to throw.
 334    */
 335  0 public final SAXParseException createSAXParseException(final Exception e) {
 336  0 return new SAXParseException(null, locator, e);
 337    }
 338   
 339    /**
 340    * Creates new {@link SAXParseException} including parsing position information.
 341    *
 342    * @param message Problem description.
 343    * @return Exception to throw.
 344    */
 345  1 public final SAXParseException createSAXParseException(final String message) {
 346  1 return new SAXParseException(message, locator);
 347    }
 348   
 349    /**
 350    * Set current location information within an {@link XmlSyntaxException}.
 351    *
 352    * @param e Set location information within this exception.
 353    */
 354  0 private final void setLocationInformation(final XmlSyntaxException e) {
 355  0 if (locator != null && url != null) {
 356  0 e.setErrorPosition(new SourcePosition(url, locator.getLineNumber(),
 357    locator.getColumnNumber()));
 358    }
 359    }
 360   
 361    /**
 362    * Get current source area.
 363    *
 364    * @return Current area.
 365    */
 366  0 private final SourceArea createSourceArea() {
 367  0 if (locator != null && url != null) {
 368  0 return new SourceArea(url, new SourcePosition(url, locator.getLineNumber(),
 369    locator.getColumnNumber()), null);
 370    }
 371  0 return new SourceArea(url, null, null);
 372    }
 373   
 374    /**
 375    * Set original file URL.
 376    *
 377    * @param url Data from this source is parsed. This URL is only for information. The
 378    * actual parsed data might be a local copy.
 379    */
 380  702 public final void setUrl(final URL url) {
 381  702 this.url = url;
 382    }
 383   
 384    /**
 385    * Get original file URL.
 386    *
 387    * @return Data from this source is parsed. This URL is only for information. The
 388    * actual parsed data might be a local copy.
 389    */
 390  0 public final URL getUrl() {
 391  0 return url;
 392    }
 393   
 394    }