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