Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Do Mai 10 2007 03:16:40 CEST
file stats: LOC: 356   Methods: 17
NCLOC: 178   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SaxDefaultHandler.java 87,5% 66,3% 82,4% 71,1%
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  267 public SaxDefaultHandler() {
 82  267 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 final void setExceptionList(final SyntaxExceptionList errorList) {
 91  261 this.errorList = errorList;
 92    }
 93   
 94    /**
 95    * Receive a Locator object for document events.
 96    * Store the locator for use with other document events.
 97    *
 98    * @param locator A locator for all SAX document events.
 99    * @see org.xml.sax.ContentHandler#setDocumentLocator
 100    * @see org.xml.sax.Locator
 101    */
 102  261 public final void setDocumentLocator(final Locator locator) {
 103  261 this.locator = locator;
 104    }
 105   
 106    /**
 107    * Set basis handler for documents.
 108    *
 109    * @param handler Basis handler for documents. This handler might also pass control to
 110    * another handler via the
 111    * {@link AbstractSimpleHandler#changeHandler(AbstractSimpleHandler, String, SimpleAttributes)}
 112    * method.
 113    */
 114  267 public final void setBasisDocumentHandler(final AbstractSimpleHandler handler) {
 115  267 basisHandler = handler;
 116  267 currentHandler = handler;
 117  267 handlerStack.clear();
 118  267 level = 0;
 119    }
 120   
 121    /* (non-Javadoc)
 122    * @see org.xml.sax.helpers.DefaultHandler#startDocument()
 123    */
 124  261 public final void startDocument() throws SAXException {
 125  261 sendCharacters();
 126  261 currentHandler = basisHandler;
 127  261 handlerStack.clear();
 128  261 level = 0;
 129  261 currentElementName = null;
 130    }
 131   
 132    /* (non-Javadoc)
 133    * @see org.xml.sax.helpers.DefaultHandler#endDocument()
 134    */
 135  261 public final void endDocument() throws SAXException {
 136  261 sendCharacters();
 137  261 currentElementName = null;
 138    }
 139   
 140    /* (non-Javadoc)
 141    * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
 142    * java.lang.String, org.xml.sax.Attributes)
 143    */
 144  26109 public final void startElement(final String uri, final String localName, final String qName,
 145    final Attributes amap) throws SAXException {
 146  26109 final String method = "startElement";
 147  26109 try {
 148  26109 Trace.param(this, method, "currentHandler", currentHandler.getClass().getName());
 149  26109 Trace.param(this, method, "localName", localName);
 150  26109 Trace.param(this, method, "qName", qName);
 151  26109 if (handlerStack.empty() && level == 0) {
 152  261 currentHandler.init();
 153    }
 154  26109 level++;
 155  26109 sendCharacters();
 156  26109 currentElementName = localName;
 157  26109 final SimpleAttributes attributes = new SimpleAttributes();
 158  26109 for (int i = 0; i < amap.getLength(); i++) {
 159  23822 attributes.add(amap.getQName(i), amap.getValue(i));
 160    }
 161  26109 Trace.param(this, method, "attributes", attributes);
 162  26109 currentHandler.startElement(qName, attributes);
 163    } catch (SyntaxException e) {
 164  0 Trace.trace(this, method, e);
 165  0 setLocationInformation(e);
 166  0 errorList.add(e);
 167    } catch (RuntimeException e) {
 168  0 Trace.trace(this, method, e);
 169  0 final SyntaxException ex = SyntaxException.createByRuntimeException(e);
 170  0 setLocationInformation(ex);
 171  0 errorList.add(ex);
 172    }
 173    }
 174   
 175    /* (non-Javadoc)
 176    * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
 177    * java.lang.String)
 178    */
 179  26109 public final void endElement(final String uri, final String localName, final String qName)
 180    throws SAXException {
 181  26109 sendCharacters();
 182  26109 final String method = "endElement";
 183  26109 try {
 184  26109 Trace.param(this, method, "currentHandler", currentHandler.getClass().getName());
 185  26109 Trace.param(this, method, "localName", localName);
 186  26109 currentHandler.endElement(localName);
 187    } catch (SyntaxException e) {
 188  0 Trace.trace(this, method, e);
 189  0 setLocationInformation(e);
 190  0 errorList.add(e);
 191    } catch (RuntimeException e) {
 192  0 Trace.trace(this, method, e);
 193  0 final SyntaxException ex = SyntaxException.createByRuntimeException(e);
 194  0 setLocationInformation(ex);
 195  0 errorList.add(ex);
 196    }
 197  26109 try {
 198  26109 currentElementName = null;
 199  26109 level--;
 200  26109 if (level <= 0) {
 201  7425 restoreHandler(localName);
 202    }
 203    } catch (SyntaxException e) {
 204  0 Trace.trace(this, method, e);
 205  0 setLocationInformation(e);
 206  0 errorList.add(e);
 207    } catch (RuntimeException e) {
 208  0 Trace.trace(this, method, e);
 209  0 final SyntaxException ex = SyntaxException.createByRuntimeException(e);
 210  0 setLocationInformation(ex);
 211  0 errorList.add(ex);
 212    }
 213    }
 214   
 215    /* (non-Javadoc)
 216    * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
 217    */
 218  62780 public final void characters(final char[] ch, final int start, final int length) {
 219  62780 buffer.append(ch, start, length);
 220    }
 221   
 222    /**
 223    * Sends <code>characters</code> event to current handler.
 224    *
 225    * @throws SAXException Caused by overrun of {@link SyntaxExceptionList}.
 226    */
 227  52740 private void sendCharacters() throws SAXException {
 228  52740 try {
 229  52740 if (buffer.length() > 0) {
 230  43840 final String str = buffer.toString().trim();
 231  43840 buffer.setLength(0);
 232  43840 if (str.length() > 0) {
 233  5429 currentHandler.characters(currentElementName, str);
 234    }
 235    }
 236    } catch (SyntaxException e) {
 237  0 Trace.trace(this, "startElement", e);
 238  0 setLocationInformation(e);
 239  0 errorList.add(e);
 240    } catch (RuntimeException e) {
 241  0 Trace.trace(this, "startElement", e);
 242  0 final SyntaxException ex = SyntaxException.createByRuntimeException(e);
 243  0 setLocationInformation(ex);
 244  0 errorList.add(ex);
 245    }
 246    }
 247   
 248    /**
 249    * Change current handler to new one. The new handler is initialized by calling
 250    * {@link AbstractSimpleHandler#init()}.
 251    * The new handler also gets a {@link AbstractSimpleHandler#startElement(String,
 252    * SimpleAttributes)} event.
 253    * The current handler is stacked. After the new handler gets the appropriate endElement
 254    * event, the control is switched back to the old handler.
 255    * <p>
 256    * The switch back is also done, if the tag level gets back to the same number. That means
 257    * if for example the new handler starts with the <code>&lt;banana&gt;</code> tag, the
 258    * old handler is restored when the misspelled <code>&lt;/bnana&gt</code> tag occurs:
 259    * <p>
 260    * <pre>
 261    * &lt;banana&gt;
 262    * &lt;one /&gt;
 263    * &lt;two &gt;
 264    * &lt;one /&gt;
 265    * &lt;one /&gt;
 266    * &lt;/two &gt;
 267    * &lt;/bnana&gt
 268    * </pre>
 269    *
 270    * @param newHandler This handler gets the new events.
 271    * @param elementName Element name.
 272    * @param attributes Element attributes.
 273    * @throws SyntaxException New Handler detected a semantic problem.
 274    */
 275  7254 public final void changeHandler(final AbstractSimpleHandler newHandler,
 276    final String elementName, final SimpleAttributes attributes)
 277    throws SyntaxException {
 278  7254 handlerStack.push(currentHandler);
 279  7254 levelStack.push(new Integer(level));
 280  7254 currentHandler = newHandler;
 281  7254 level = 0;
 282  7254 level++;
 283  7254 currentHandler.init();
 284  7254 currentHandler.startElement(elementName, attributes);
 285    }
 286   
 287    /**
 288    * Restore previous handler if there is any. An endElement event is also send to the restored
 289    * handler.
 290    *
 291    * @param elementName
 292    * @throws SyntaxException
 293    */
 294  7425 private final void restoreHandler(final String elementName) throws SyntaxException {
 295  7425 while (level <= 0 && !handlerStack.empty()) {
 296  7254 currentHandler = (AbstractSimpleHandler) handlerStack.pop();
 297  7254 level = ((Integer) levelStack.pop()).intValue();
 298  7254 currentHandler.endElement(elementName);
 299  7254 level--;
 300    }
 301  7425 if (handlerStack.empty()) {
 302    // TODO mime 20050205: is this occurrence an error???
 303  453 Trace.trace(this, "restoreHandler", "no handler to restore");
 304    }
 305    }
 306   
 307    /**
 308    * Get current level.
 309    *
 310    * @return Current level.
 311    */
 312  1962 public final int getLevel() {
 313  1962 return level;
 314    }
 315   
 316    /**
 317    * Wraps exception in new {@link SAXParseException} including parsing position information.
 318    *
 319    * @param e Exception to wrap.
 320    * @return Exception to throw.
 321    */
 322  0 public final SAXParseException createSAXParseException(final Exception e) {
 323  0 return new SAXParseException(null, locator, e);
 324    }
 325   
 326    /**
 327    * Creates new {@link SAXParseException} including parsing position information.
 328    *
 329    * @param message Problem description.
 330    * @return Exception to throw.
 331    */
 332  0 public final SAXParseException createSAXParseException(final String message) {
 333  0 return new SAXParseException(message, locator);
 334    }
 335   
 336    /**
 337    * Set current location information within an {@link SyntaxException}.
 338    *
 339    * @param e Set location information within this exception.
 340    */
 341  0 private final void setLocationInformation(final SyntaxException e) {
 342  0 if (locator != null && url != null) {
 343  0 e.setErrorPosition(new SourcePosition(url, locator.getLineNumber(),
 344    locator.getColumnNumber()));
 345    }
 346    }
 347   
 348    /**
 349    * Set file that is parsed.
 350    *
 351    * @param url This file is parsed.
 352    */
 353  261 public final void setUrl(final URL url) {
 354  261 this.url = url;
 355    }
 356    }