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.9 2008/09/10 09:20:49 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 * Returns a new instance of {@link FrontendDefaultHandler}.
300 *
301 * @return A new instance.
302 */
303 public final FrontendDefaultHandler newInstance() {
304 return getInstance();
305 }
306
307 /**
308 * Returns the parsed result object after the parsing is complete. Calling
309 * this function during the parsing is undefined and may result in an
310 * IllegalStateException.
311 *
312 * @return the parsed result.
313 */
314 public abstract Object getResult();
315 }