    001    /* ========================================================================
    002     * JCommon : a free general purpose class library for the Java(tm) platform
    003     * ========================================================================
    004     *
    005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006     *
    007     * Project Info:  http://www.jfree.org/jcommon/index.html
    008     *
    009     * This library is free software; you can redistribute it and/or modify it
    010     * under the terms of the GNU Lesser General Public License as published by
    011     * the Free Software Foundation; either version 2.1 of the License, or
    012     * (at your option) any later version.
    013     *
    014     * This library is distributed in the hope that it will be useful, but
    015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017     * License for more details.
    018     *
    019     * You should have received a copy of the GNU Lesser General Public
    020     * License along with this library; if not, write to the Free Software
    021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022     * USA.
    023     *
    024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025     * in the United States and other countries.]
    026     *
    027     * -----------
    028     * Parser.java
    029     * -----------
    030     * (C)opyright 2003-2005, by Thomas Morgner and Contributors.
    031     *
    032     * Original Author:  Thomas Morgner (taquera@sherito.org);
    033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
    034     *
    035     * $Id: Parser.java,v 1.8 2005/11/14 10:58:02 mungady Exp $
    036     *
    037     * Changes
    038     * -------
    039     * 09-Jan-2003 : Initial version.
    040     * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon
    041     * 14-Jul-2003 : More help with the error location given by catching all exceptions.
    042     *
    043     */
    044
    045    package org.jfree.xml;
    046
    047    import java.util.HashMap;
    048    import java.util.Stack;
    049
    050    import org.xml.sax.Attributes;
    051    import org.xml.sax.SAXException;
    052
    053    /**
    054     * The Parser handles the SAXEvents and forwards the event call to the currently
    055     * active ElementDefinitionHandler. Contains methods to manage and
    056     * configure the parsing process.
    057     * <p>
    058     * An initial report definition handler must be set before the parser can be used.
    059     *
    060     * @author Thomas Morgner
    061     */
    062    public abstract class Parser extends FrontendDefaultHandler {
    063
    064        /** A key for the content base. */
    065        public static final String CONTENTBASE_KEY = "content-base";
    066
    067        /** A stack for the active factories. */
    068        private Stack activeFactories;
    069
    070        /** The initial factory. */
    071        private ElementDefinitionHandler initialFactory;
    072
    073        /** Storage for temporary objects and factories used during the parsing process. */
    074        private HashMap parserHelperObjects;
    075
    076        /**
    077         * Creates a new parser.
    078         */
    079        public Parser() {
    080            this.activeFactories = new Stack();
    081            this.parserHelperObjects = new HashMap();
    082        }
    083
    084        /**
    085         * Returns the currently collected comments.
    086         * @return the comments.
    087         */
    088        public String[] getComments() {
    089            return getCommentHandler().getComments();
    090        }
    091
    092        /**
    093         * Pushes a handler onto the stack.
    094         *
    095         * @param factory  the handler.
    096         */
    097        public void pushFactory(final ElementDefinitionHandler factory) {
    098            this.activeFactories.push(factory);
    099        }
    100
    101        /**
    102         * Reads a handler off the stack without removing it.
    103         *
    104         * @return The handler.
    105         */
    106        public ElementDefinitionHandler peekFactory() {
    107            return (ElementDefinitionHandler) this.activeFactories.peek();
    108        }
    109
    110        /**
    111         * Pops a handler from the stack.
    112         *
    113         * @return The handler.
    114         */
    115        public ElementDefinitionHandler popFactory() {
    116            this.activeFactories.pop();
    117            return peekFactory();
    118        }
    119
    120        /**
    121         * Receive notification of the end of the document.
    122         *
    123         * <p>By default, do nothing.  Application writers may override this
    124         * method in a subclass to take specific actions at the end
    125         * of a document (such as finalising a tree or closing an output
    126         * file).</p>
    127         *
    128         * @exception SAXException Any SAX exception, possibly wrapping another exception.
    129         *
    130         * @see org.xml.sax.ContentHandler#endDocument
    131         */
    132        public void endDocument() throws SAXException {
    133            // ignored
    134        }
    135
    136        /**
    137         * Receive notification of the beginning of the document.
    138         *
    139         * <p>By default, do nothing.  Application writers may override this
    140         * method in a subclass to take specific actions at the beginning
    141         * of a document (such as allocating the root node of a tree or
    142         * creating an output file).</p>
    143         *
    144         * @exception SAXException Any SAX exception, possibly wrapping another exception.
    145         * @see org.xml.sax.ContentHandler#startDocument
    146         */
    147        public void startDocument() throws SAXException {
    148            this.activeFactories.clear();
    149            pushFactory(getInitialFactory());
    150        }
    151
    152        /**
    153         * Receive notification of character data inside an element.
    154         *
    155         * <p>By default, do nothing.  Application writers may override this
    156         * method to take specific actions for each chunk of character data
    157         * (such as adding the data to a node or buffer, or printing it to
    158         * a file).</p>
    159         *
    160         * @param ch  the characters.
    161         * @param start  the start position in the character array.
    162         * @param length  the number of characters to use from the character array.
    163         *
    164         * @exception SAXException Any SAX exception, possibly wrapping another exception.
    165         * @see org.xml.sax.ContentHandler#characters
    166         */
    167        public void characters(final char[] ch, final int start, final int length)
    168            throws SAXException {
    169            try {
    170                peekFactory().characters(ch, start, length);
    171            }
    172            catch (ParseException pe) {
    173                throw pe;
    174            }
    175            catch (Exception e) {
    176                throw new ParseException(e, getLocator());
    177            }
    178        }
    179
    180        /**
    181         * Receive notification of the end of an element.
    182         *
    183         * <p>By default, do nothing.  Application writers may override this
    184         * method in a subclass to take specific actions at the end of
    185         * each element (such as finalising a tree node or writing
    186         * output to a file).</p>
    187         *
    188         * @param uri  the URI.
    189         * @param localName  the element type name.
    190         * @param qName  the name.
    191         *
    192         * @exception SAXException Any SAX exception, possibly
    193         *            wrapping another exception.
    194         * @see org.xml.sax.ContentHandler#endElement
    195         */
    196        public void endElement(final String uri, final String localName, final String qName)
    197            throws SAXException {
    198            try {
    199                peekFactory().endElement(qName);
    200            }
    201            catch (ParseException pe) {
    202                throw pe;
    203            }
    204            catch (Exception e) {
    205                throw new ParseException(e, getLocator());
    206            }
    207            finally {
    208                getCommentHandler().clearComments();
    209            }
    210        }
    211
    212
    213        /**
    214         * Receive notification of the start of an element.
    215         *
    216         * <p>By default, do nothing.  Application writers may override this
    217         * method in a subclass to take specific actions at the start of
    218         * each element (such as allocating a new tree node or writing
    219         * output to a file).</p>
    220         *
    221         * @param uri  the URI.
    222         * @param localName  the element type name.
    223         * @param qName  the name.
    224         * @param attributes  the specified or defaulted attributes.
    225         *
    226         * @exception SAXException Any SAX exception, possibly
    227         *            wrapping another exception.
    228         * @see org.xml.sax.ContentHandler#startElement
    229         */
    230        public void startElement(final String uri, final String localName,
    231                                 final String qName, final Attributes attributes)
    232            throws SAXException {
    233            try {
    234                peekFactory().startElement(qName, attributes);
    235            }
    236            catch (ParseException pe) {
    237                throw pe;
    238            }
    239            catch (Exception e) {
    240                throw new ParseException(e, getLocator());
    241            }
    242            finally {
    243                getCommentHandler().clearComments();
    244            }
    245        }
    246
    247        /**
    248         * Sets the initial handler.
    249         *
    250         * @param factory  the initial handler.
    251         */
    252        public void setInitialFactory(final ElementDefinitionHandler factory) {
    253            this.initialFactory = factory;
    254        }
    255
    256        /**
    257         * Returns the initial handler.
    258         *
    259         * @return The initial handler.
    260         */
    261        public ElementDefinitionHandler getInitialFactory() {
    262            return this.initialFactory;
    263        }
    264
    265        /**
    266         * Sets a helper object.
    267         *
    268         * @param key  the key.
    269         * @param value  the value.
    270         */
    271        public void setHelperObject(final String key, final Object value) {
    272            if (value == null) {
    273                this.parserHelperObjects.remove(key);
    274            }
    275            else {
    276                this.parserHelperObjects.put(key, value);
    277            }
    278        }
    279
    280        /**
    281         * Returns a helper object.
    282         *
    283         * @param key  the key.
    284         *
    285         * @return The object.
    286         */
    287        public Object getHelperObject(final String key) {
    288            return this.parserHelperObjects.get(key);
    289        }
    290
    291        /**
    292         * Returns a new instance of the parser.
    293         *
    294         * @return a new instance of the parser.
    295         */
    296        public abstract Parser getInstance();
    297
    298
    299        public final FrontendDefaultHandler newInstance() {
    300            return getInstance();
    301        }
    302
    303        /**
    304         * Returns the parsed result object after the parsing is complete. Calling
    305         * this function during the parsing is undefined and may result in an
    306         * IllegalStateException.
    307         *
    308         * @return the parsed result.
    309         */
    310        public abstract Object getResult();
    311    }