Source for org.jfree.xml.Parser

   1: /* ========================================================================
   2:  * JCommon : a free general purpose class library for the Java(tm) platform
   3:  * ========================================================================
   4:  *
   5:  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   6:  * 
   7:  * Project Info:  http://www.jfree.org/jcommon/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  * 
  27:  * -----------
  28:  * Parser.java
  29:  * -----------
  30:  * (C)opyright 2003-2005, by Thomas Morgner and Contributors.
  31:  *
  32:  * Original Author:  Thomas Morgner (taquera@sherito.org);
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *
  35:  * $Id: Parser.java,v 1.8 2005/11/14 10:58:02 mungady Exp $
  36:  *
  37:  * Changes
  38:  * -------
  39:  * 09-Jan-2003 : Initial version.
  40:  * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon
  41:  * 14-Jul-2003 : More help with the error location given by catching all exceptions.
  42:  * 
  43:  */
  44:  
  45: package org.jfree.xml;
  46: 
  47: import java.util.HashMap;
  48: import java.util.Stack;
  49: 
  50: import org.xml.sax.Attributes;
  51: import org.xml.sax.SAXException;
  52: 
  53: /**
  54:  * The Parser handles the SAXEvents and forwards the event call to the currently
  55:  * active ElementDefinitionHandler. Contains methods to manage and
  56:  * configure the parsing process.
  57:  * <p>
  58:  * An initial report definition handler must be set before the parser can be used.
  59:  *
  60:  * @author Thomas Morgner
  61:  */
  62: public abstract class Parser extends FrontendDefaultHandler {
  63: 
  64:     /** A key for the content base. */
  65:     public static final String CONTENTBASE_KEY = "content-base";
  66: 
  67:     /** A stack for the active factories. */
  68:     private Stack activeFactories;
  69: 
  70:     /** The initial factory. */
  71:     private ElementDefinitionHandler initialFactory;
  72: 
  73:     /** Storage for temporary objects and factories used during the parsing process. */
  74:     private HashMap parserHelperObjects;
  75: 
  76:     /**
  77:      * Creates a new parser.
  78:      */
  79:     public Parser() {
  80:         this.activeFactories = new Stack();
  81:         this.parserHelperObjects = new HashMap();
  82:     }
  83: 
  84:     /**
  85:      * Returns the currently collected comments.
  86:      * @return the comments.
  87:      */
  88:     public String[] getComments() {
  89:         return getCommentHandler().getComments();
  90:     }
  91: 
  92:     /**
  93:      * Pushes a handler onto the stack.
  94:      *
  95:      * @param factory  the handler.
  96:      */
  97:     public void pushFactory(final ElementDefinitionHandler factory) {
  98:         this.activeFactories.push(factory);
  99:     }
 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: }