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,
168: final int length) throws SAXException {
169: try {
170: peekFactory().characters(ch, start, length);
171: } catch (ParseException pe) {
172: throw pe;
173: } catch (Exception e) {
174: throw new ParseException(e, getLocator());
175: }
176: }
177:
178: /**
179: * Receive notification of the end of an element.
180: *
181: * <p>By default, do nothing. Application writers may override this
182: * method in a subclass to take specific actions at the end of
183: * each element (such as finalising a tree node or writing
184: * output to a file).</p>
185: *
186: * @param uri the URI.
187: * @param localName the element type name.
188: * @param qName the name.
189: *
190: * @exception SAXException Any SAX exception, possibly
191: * wrapping another exception.
192: * @see org.xml.sax.ContentHandler#endElement
193: */
194: public void endElement(final String uri, final String localName,
195: final String qName) throws SAXException {
196: try {
197: peekFactory().endElement(qName);
198: } catch (ParseException pe) {
199: throw pe;
200: } catch (Exception e) {
201: throw new ParseException(e, getLocator());
202: } finally {
203: getCommentHandler().clearComments();
204: }
205: }
206:
207: /**
208: * Receive notification of the start of an element.
209: *
210: * <p>By default, do nothing. Application writers may override this
211: * method in a subclass to take specific actions at the start of
212: * each element (such as allocating a new tree node or writing
213: * output to a file).</p>
214: *
215: * @param uri the URI.
216: * @param localName the element type name.
217: * @param qName the name.
218: * @param attributes the specified or defaulted attributes.
219: *
220: * @exception SAXException Any SAX exception, possibly
221: * wrapping another exception.
222: * @see org.xml.sax.ContentHandler#startElement
223: */
224: public void startElement(final String uri, final String localName,
225: final String qName, final Attributes attributes)
226: throws SAXException {
227: try {
228: peekFactory().startElement(qName, attributes);
229: } catch (ParseException pe) {
230: throw pe;
231: } catch (Exception e) {
232: throw new ParseException(e, getLocator());
233: } finally {
234: getCommentHandler().clearComments();
235: }
236: }
237:
238: /**
239: * Sets the initial handler.
240: *
241: * @param factory the initial handler.
242: */
243: public void setInitialFactory(final ElementDefinitionHandler factory) {
244: this .initialFactory = factory;
245: }
246:
247: /**
248: * Returns the initial handler.
249: *
250: * @return The initial handler.
251: */
252: public ElementDefinitionHandler getInitialFactory() {
253: return this .initialFactory;
254: }
255:
256: /**
257: * Sets a helper object.
258: *
259: * @param key the key.
260: * @param value the value.
261: */
262: public void setHelperObject(final String key, final Object value) {
263: if (value == null) {
264: this .parserHelperObjects.remove(key);
265: } else {
266: this .parserHelperObjects.put(key, value);
267: }
268: }
269:
270: /**
271: * Returns a helper object.
272: *
273: * @param key the key.
274: *
275: * @return The object.
276: */
277: public Object getHelperObject(final String key) {
278: return this .parserHelperObjects.get(key);
279: }
280:
281: /**
282: * Returns a new instance of the parser.
283: *
284: * @return a new instance of the parser.
285: */
286: public abstract Parser getInstance();
287:
288: public final FrontendDefaultHandler newInstance() {
289: return getInstance();
290: }
291:
292: /**
293: * Returns the parsed result object after the parsing is complete. Calling
294: * this function during the parsing is undefined and may result in an
295: * IllegalStateException.
296: *
297: * @return the parsed result.
298: */
299: public abstract Object getResult();
300: }
|