EMMA Coverage Report (generated Fri Feb 14 08:28:31 UTC 2014)
[all classes][org.qedeq.kernel.xml.handler.common]

COVERAGE SUMMARY FOR SOURCE FILE [SaxDefaultHandler.java]

nameclass, %method, %block, %line, %
SaxDefaultHandler.java100% (1/1)83%  (15/18)81%  (401/494)77%  (91.1/119)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SaxDefaultHandler100% (1/1)83%  (15/18)81%  (401/494)77%  (91.1/119)
createSAXParseException (Exception): SAXParseException 0%   (0/1)0%   (0/8)0%   (0/1)
createSAXParseException (String): SAXParseException 0%   (0/1)0%   (0/7)0%   (0/1)
getPlugin (): ModuleService 0%   (0/1)0%   (0/3)0%   (0/1)
sendCharacters (): void 100% (1/1)52%  (24/46)44%  (6.1/14)
endElement (String, String, String): void 100% (1/1)63%  (58/92)56%  (15.1/27)
createSourceArea (): SourceArea 100% (1/1)82%  (28/34)67%  (2/3)
startElement (String, String, String, Attributes): void 100% (1/1)89%  (94/106)83%  (20/24)
<static initializer> 100% (1/1)90%  (9/10)90%  (0.9/1)
SaxDefaultHandler (ModuleService): void 100% (1/1)100% (22/22)100% (6/6)
addXmlSyntaxException (XmlSyntaxException): void 100% (1/1)100% (18/18)100% (3/3)
changeHandler (AbstractSimpleHandler, String, SimpleAttributes): void 100% (1/1)100% (43/43)100% (9/9)
characters (char [], int, int): void 100% (1/1)100% (8/8)100% (2/2)
endDocument (): void 100% (1/1)100% (6/6)100% (3/3)
getLevel (): int 100% (1/1)100% (3/3)100% (1/1)
restoreHandler (String): void 100% (1/1)100% (55/55)100% (10/10)
setBasisDocumentHandler (AbstractSimpleHandler): void 100% (1/1)100% (13/13)100% (5/5)
setExceptionList (SourceFileExceptionList): void 100% (1/1)100% (4/4)100% (2/2)
startDocument (): void 100% (1/1)100% (16/16)100% (6/6)

1/* This file is part of the project "Hilbert II" - http://www.qedeq.org
2 *
3 * Copyright 2000-2014,  Michael Meyling <mime@qedeq.org>.
4 *
5 * "Hilbert II" is free software; you can redistribute
6 * it and/or modify it under the terms of the GNU General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15package org.qedeq.kernel.xml.handler.common;
16 
17import java.util.Stack;
18 
19import org.qedeq.base.io.SourceArea;
20import org.qedeq.base.io.SourcePosition;
21import org.qedeq.base.trace.Trace;
22import org.qedeq.kernel.se.common.ModuleService;
23import org.qedeq.kernel.se.common.SourceFileException;
24import org.qedeq.kernel.se.common.SourceFileExceptionList;
25import org.qedeq.kernel.xml.common.XmlSyntaxException;
26import org.xml.sax.Attributes;
27import org.xml.sax.SAXException;
28import org.xml.sax.SAXParseException;
29 
30 
31/**
32 * Default SAX handler. Delegates SAX events to a
33 * {@link org.qedeq.kernel.xml.handler.common.AbstractSimpleHandler}
34 * which could also delegate events to other
35 * {@link org.qedeq.kernel.xml.handler.common.AbstractSimpleHandler}s.
36 * <p>
37 * Before anything is parsed the method {@link #setExceptionList(SourceFileExceptionList)}
38 * must be called.
39 *
40 * @author  Michael Meyling
41 */
42public class SaxDefaultHandler extends SimpleHandler {
43 
44    /** This class. */
45    private static final Class CLASS = SaxDefaultHandler.class;
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 SourceFileExceptionList errorList;
58 
59    /** Buffer for combining character events. */
60    private StringBuffer buffer = new StringBuffer(2000);
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    /** The plugin we work for. */
72    private final ModuleService plugin;
73 
74    /**
75     * Constructor.
76     *
77     * @param   plugin  The plugin we work for.
78     */
79    public SaxDefaultHandler(final ModuleService plugin) {
80        super();
81        this.plugin = plugin;
82    }
83 
84    /**
85     * Set parse exception list. This list collects occurring parsing errors.
86     *
87     * @param   errorList  Collect errors here.
88     */
89    public void setExceptionList(final SourceFileExceptionList errorList) {
90        this.errorList = errorList;
91    }
92 
93    /**
94     * Set basis handler for documents.
95     *
96     * @param   handler Basis handler for documents. This handler might also pass control to
97     * another handler via the
98     * {@link AbstractSimpleHandler#changeHandler(AbstractSimpleHandler, String, SimpleAttributes)}
99     * method.
100     */
101    public final void setBasisDocumentHandler(final AbstractSimpleHandler handler) {
102        basisHandler = handler;
103        currentHandler = handler;
104        handlerStack.clear();
105        level = 0;
106    }
107 
108    /* (non-Javadoc)
109     * @see org.xml.sax.helpers.DefaultHandler#startDocument()
110     */
111    public final void startDocument() throws SAXException {
112        sendCharacters();
113        currentHandler = basisHandler;
114        handlerStack.clear();
115        level = 0;
116        currentElementName = null;
117    }
118 
119    /* (non-Javadoc)
120     * @see org.xml.sax.helpers.DefaultHandler#endDocument()
121     */
122    public final void endDocument() throws SAXException {
123        sendCharacters();
124        currentElementName = null;
125    }
126 
127    /* (non-Javadoc)
128     * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
129     * java.lang.String, org.xml.sax.Attributes)
130     */
131    public final void startElement(final String uri, final String localName, final String qName,
132            final Attributes amap) throws SAXException {
133        final String method = "startElement";
134        try {
135            Trace.param(CLASS, this, method, "currentHandler", currentHandler.getClass().getName());
136            Trace.param(CLASS, this, method, "localName", localName);
137            Trace.param(CLASS, this, method, "qName", qName);
138            if (handlerStack.empty() && level == 0) {
139                currentHandler.init();
140            }
141            level++;
142            Trace.param(CLASS, this, method, "level", level);
143            sendCharacters();
144            currentElementName = localName;
145            final SimpleAttributes attributes = new SimpleAttributes();
146            for (int i = 0; i < amap.getLength(); i++) {
147                attributes.add(amap.getQName(i), amap.getValue(i));
148            }
149            Trace.param(CLASS, this, method, "attributes", attributes);
150            currentHandler.startElement(qName, attributes);
151        } catch (XmlSyntaxException e) {
152            Trace.trace(CLASS, this, method, e);
153            addXmlSyntaxException(e);
154        } catch (RuntimeException e) {
155            Trace.trace(CLASS, this, method, e);
156            final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
157            addXmlSyntaxException(ex);
158        }
159    }
160 
161    /* (non-Javadoc)
162     * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
163     * java.lang.String)
164     */
165    public final void endElement(final String uri, final String localName, final String qName)
166            throws SAXException {
167        sendCharacters();
168        final String method = "endElement";
169        try {
170            Trace.param(CLASS, this, method, "currentHandler", currentHandler.getClass().getName());
171            Trace.param(CLASS, this, method, "qName", qName);
172            currentHandler.endElement(qName);
173        } catch (XmlSyntaxException e) {
174            Trace.trace(CLASS, this, method, e);
175            addXmlSyntaxException(e);
176        } catch (RuntimeException e) {
177            Trace.trace(CLASS, this, method, e);
178            final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
179            addXmlSyntaxException(ex);
180        }
181        try {
182            currentElementName = null;
183            level--;
184            Trace.param(CLASS, this, method, "level", level);
185            if (level <= 0) {
186                restoreHandler(localName);
187            }
188        } catch (XmlSyntaxException e) {
189            Trace.trace(CLASS, this, method, e);
190            addXmlSyntaxException(e);
191        } catch (RuntimeException e) {
192            Trace.trace(CLASS, this, method, e);
193            final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
194            addXmlSyntaxException(ex);
195        }
196    }
197 
198    /* (non-Javadoc)
199     * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
200     */
201    public final void characters(final char[] ch, final int start, final int length) {
202        buffer.append(ch, start, length);
203    }
204 
205    /**
206     * Sends <code>characters</code> event to current handler. Whitespace is preserved.
207     * It fires only, if there is something beside whitespace.
208     */
209    private void sendCharacters() {
210        try  {
211            if (buffer.length() > 0) {
212                final String str = buffer.toString();
213                buffer.setLength(0);
214                if (str.trim().length() > 0) {  // anything there beside whitespace?
215                    currentHandler.characters(currentElementName, str);
216                }
217            }
218        } catch (XmlSyntaxException e) {
219            Trace.trace(CLASS, this, "sendCharacters", e);
220            addXmlSyntaxException(e);
221        } catch (RuntimeException e) {
222            Trace.trace(CLASS, this, "sendCharacters", e);
223            final XmlSyntaxException ex = XmlSyntaxException.createByRuntimeException(e);
224            addXmlSyntaxException(ex);
225        }
226    }
227 
228    /**
229     * Add exception to exception list if we have only than 20 exceptions yet.
230     *
231     * @param   exception   Add this exception.
232     */
233    private void addXmlSyntaxException(final XmlSyntaxException exception) {
234        if (errorList.size() < 20) {
235            errorList.add(new SourceFileException(plugin, exception, createSourceArea(), null));
236        }
237    }
238 
239    /**
240     * Change current handler to new one. The new handler is initialized by calling
241     * {@link AbstractSimpleHandler#init()}.
242     * The new handler also gets a {@link AbstractSimpleHandler#startElement(String,
243     * SimpleAttributes)} event.
244     * The current handler is stacked. After the new handler gets the appropriate endElement
245     * event, the control is switched back to the old handler.
246     * <p>
247     * The switch back is also done, if the tag level gets back to the same number. That means
248     * if for example the new handler starts with the <code>&lt;banana&gt;</code> tag, the
249     * old handler is restored when the misspelled <code>&lt;/bnana&gt</code> tag occurs:
250     * <p>
251     * <pre>
252     * &lt;banana&gt;
253     *      &lt;one /&gt;
254     *      &lt;two &gt;
255     *          &lt;one /&gt;
256     *          &lt;one /&gt;
257     *      &lt;/two &gt;
258     * &lt;/bnana&gt
259     * </pre>
260     *
261     * @param  newHandler  This handler gets the new events.
262     * @param  elementName Element name.
263     * @param  attributes  Element attributes.
264     * @throws XmlSyntaxException   New Handler detected a semantic problem.
265     */
266    public final void changeHandler(final AbstractSimpleHandler newHandler,
267            final String elementName, final SimpleAttributes attributes)
268            throws XmlSyntaxException {
269        handlerStack.push(currentHandler);
270        levelStack.push(new Integer(level));
271        currentHandler = newHandler;
272        level = 0;
273        level++;
274        Trace.param(CLASS, this, "changeHandler", "level", level);
275        currentHandler.init();
276        currentHandler.startElement(elementName, attributes);
277    }
278 
279    /**
280     * Restore previous handler if there is any. An {@link #endElement} event is also send to the restored
281     * handler.
282     *
283     * @param   elementName Current element.
284     * @throws  XmlSyntaxException  Handler dosen't like this event.
285     */
286    private final void restoreHandler(final String elementName) throws XmlSyntaxException {
287        while (level <= 0 && !handlerStack.empty()) {
288            currentHandler = (AbstractSimpleHandler) handlerStack.pop();
289            Trace.param(CLASS, this, "restoreHandler", "currentHandler", currentHandler);
290            level = ((Integer) levelStack.pop()).intValue();
291            currentHandler.endElement(elementName);
292            level--;
293            Trace.param(CLASS, this, "restoreHandler", "level", level);
294        }
295        if (handlerStack.empty()) {
296            Trace.trace(CLASS, this, "restoreHandler", "no handler to restore");
297        }
298    }
299 
300    /**
301     * Get current level.
302     *
303     * @return  Current level.
304     */
305    public final int getLevel() {
306        return level;
307    }
308 
309    /**
310     * Wraps exception in new {@link SAXParseException} including parsing position information.
311     *
312     * @param   e   Exception to wrap.
313     * @return  Exception to throw.
314     */
315    public final SAXParseException createSAXParseException(final Exception e) {
316        return new SAXParseException(null, getLocator(), e);
317    }
318 
319    /**
320     * Creates new {@link SAXParseException} including parsing position information.
321     *
322     * @param   message Problem description.
323     * @return  Exception to throw.
324     */
325    public final SAXParseException createSAXParseException(final String message) {
326        return new SAXParseException(message, getLocator());
327    }
328 
329    /**
330     * Create current source area.
331     *
332     * @return  Current area.
333     */
334    public final SourceArea createSourceArea() {
335        if (getLocator() != null && getUrl() != null) {
336            return new SourceArea(getUrl(), new SourcePosition(getLocator().getLineNumber(), 1),
337                new SourcePosition(getLocator().getLineNumber(), getLocator().getColumnNumber()));
338        }
339        return new SourceArea(getUrl());
340    }
341 
342    /**
343     * Get plugin we work for.
344     *
345     * @return  Plugin.
346     */
347    public ModuleService getPlugin() {
348        return plugin;
349    }
350 
351}

[all classes][org.qedeq.kernel.xml.handler.common]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov