content: /* ========================================================================
   * JCommon : a free general purpose class library for the Java(tm) platform
   * ========================================================================
   *
   * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   * 
   * Project Info:  http://www.jfree.org/jcommon/index.html
   *
   * This library is free software; you can redistribute it and/or modify it 
   * under the terms of the GNU Lesser General Public License as published by 
   * the Free Software Foundation; either version 2.1 of the License, or 
   * (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful, but 
   * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
   * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
   * License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
   * USA.  
   *
   * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
   * in the United States and other countries.]
   * 
   * --------------------
   * ReportGenerator.java
   * --------------------
   * (C)opyright 2002-2005, by Thomas Morgner and Contributors.
   *
   * Original Author:  Thomas Morgner (taquera@sherito.org);
   * Contributor(s):   David Gilbert (for Object Refinery Limited);
   *
   * $Id: ParserFrontend.java,v 1.8 2005/11/14 10:58:19 mungady Exp $
   *
   * Changes
   * -------
   * 10-May-2002 : Initial version
   * 12-Dec-2002 : Fixed issues reported by Checkstyle (DG);
   * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon
   *
   */
  
  package org.jfree.xml;
  
  import java.io.BufferedInputStream;
  import java.io.IOException;
  import java.net.URL;
  import javax.xml.parsers.ParserConfigurationException;
  import javax.xml.parsers.SAXParser;
  import javax.xml.parsers.SAXParserFactory;
  
  import org.jfree.util.Log;
  import org.xml.sax.EntityResolver;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  import org.xml.sax.XMLReader;
  
  /**
   * The reportgenerator initializes the parser and provides an interface
   * the the default parser.
   *
   * To create a report from an URL, use
   * <code>
   * ReportGenerator.getInstance().parseReport (URL myURl, URL contentBase);
   * </code>
   *
   * @author Thomas Morgner
   */
  public class ParserFrontend {
  
      /** The report handler. */
      private FrontendDefaultHandler defaulthandler;
  
      /** The parser factory. */
      private SAXParserFactory factory;
  
      /** The DTD. */
      private EntityResolver entityResolver;
  
      /** A flag indicating whether to use a DTD to validate the xml input. */
      private boolean validateDTD;
  
      /**
       * Creates a new report generator. The generator uses the singleton pattern by default,
       * so use generator.getInstance() to get the generator.
       *
       * @param parser the parser that is used to coordinate the parsing process.
       */
      protected ParserFrontend(final FrontendDefaultHandler parser) {
          if (parser == null) {
              throw new NullPointerException();
          }
          this.defaulthandler = parser;
      }
  
      /**
       * Returns <code>true</code> if the report definition should be validated against the
       * DTD, and <code>false</code> otherwise.
       *
       * @return A boolean.
       */
      public boolean isValidateDTD() {
          return this.validateDTD;
      }
  
      /**
       * Sets a flag that controls whether or not the report definition is validated
       * against the DTD.
       *
       * @param validateDTD  the flag.
       */
      public void setValidateDTD(final boolean validateDTD) {
          this.validateDTD = validateDTD;
      }
  
      /**
       * Returns the entity resolver.
       *
       * @return The entity resolver.
       */
      public EntityResolver getEntityResolver() {
          return this.entityResolver;
      }
  
      /**
       * Sets the entity resolver.
       *
       * @param entityResolver  the entity resolver.
       */
      public void setEntityResolver(final EntityResolver entityResolver) {
          this.entityResolver = entityResolver;
      }
  
      /**
       * Returns a SAX parser.
       *
       * @return a SAXParser.
       *
       * @throws ParserConfigurationException if there is a problem configuring the parser.
       * @throws SAXException if there is a problem with the parser initialisation
       */
      protected SAXParser getParser() throws ParserConfigurationException, SAXException {
          if (this.factory == null) {
              this.factory = SAXParserFactory.newInstance();
              if (isValidateDTD()) {
                  try {
                      // dont touch the validating feature, if not needed ..
                      this.factory.setValidating(true);
                  }
                  catch (Exception ex) {
                      // the parser does not like the idea of validating ...
                      Log.debug("The parser will not validate the xml document.", ex);
                  }
              }
          }
          return this.factory.newSAXParser();
      }
  
      /**
       * Sets the default handler used for parsing reports. This handler is used to
       * initiate parsing.
       *
       * @param handler  the handler.
       */
      public void setDefaultHandler(final FrontendDefaultHandler handler) {
          if (handler == null) {
              throw new NullPointerException();
          }
          this.defaulthandler = handler;
      }
  
      /**
       * Returns the ElementDefinitionHandler used for parsing reports.
       *
       * @return the report handler.
       */
      public FrontendDefaultHandler getDefaultHandler() {
          return this.defaulthandler;
      }
  
      /**
       * Creates a new instance of the currently set default handler and sets the contentbase
       * for the handler to <code>contentBase</code>.
       *
       * @param contentBase  the content base.
       *
       * @return the report handler.
       */
      protected FrontendDefaultHandler createDefaultHandler(final URL contentBase) {
          final FrontendDefaultHandler handler = getDefaultHandler().newInstance();
          if (contentBase != null) {
              handler.setConfigProperty(Parser.CONTENTBASE_KEY, contentBase.toExternalForm());
          }
          return handler;
      }
  
      /**
       * Parses an XML report template file.
       *
       * @param input  the input source.
       * @param contentBase  the content base.
       *
       * @return the report.
       *
       * @throws ElementDefinitionException if an error occurred.
       */
      protected Object parse(final InputSource input, final URL contentBase)
          throws ElementDefinitionException {
          try {
              final SAXParser parser = getParser();
              final XMLReader reader = parser.getXMLReader();
  
              try {
                  reader.setFeature("http://xml.org/sax/features/validation", isValidateDTD());
              }
              catch (SAXException se) {
                  Log.debug("The XMLReader will not validate the xml document.", se);
              }
              final FrontendDefaultHandler handler = createDefaultHandler(contentBase);
              configureReader(reader, handler);
              try {
                  reader.setContentHandler(handler);
                  reader.setDTDHandler(handler);
                  if (getEntityResolver() != null) {
                      reader.setEntityResolver(getEntityResolver());
                  }
                  reader.setErrorHandler(handler);
                  reader.parse(input);
                  return handler.getResult();
              }
              catch (IOException e) {
                  throw new ElementDefinitionException(e);
              }
          }
          catch (ParserConfigurationException e) {
              throw new ElementDefinitionException(e);
          }
          catch (SAXException e) {
              throw new ElementDefinitionException(e);
          }
      }
  
      /**
       * Configures the xml reader. Use this to set features or properties
       * before the documents get parsed.
       *
       * @param handler the parser implementation that will handle the SAX-Callbacks.
       * @param reader the xml reader that should be configured.
       */
      protected void configureReader(final XMLReader reader, final FrontendDefaultHandler handler) {
          try {
              reader.setProperty
                  ("http://xml.org/sax/properties/lexical-handler", handler.getCommentHandler());
          }
          catch (SAXException se) {
              Log.debug("Comments are not supported by this SAX implementation.");
          }
      }
  
      /**
       * Parses an XML file which is loaded using the given URL. All
       * needed relative file- and resourcespecification are loaded
       * using the URL <code>contentBase</code> as base.
       * <p>
       * After the report is generated, the ReportDefinition-source and the contentbase are
       * stored as string in the reportproperties.
       *
       * @param file  the URL for the report template file.
       * @param contentBase  the URL for the report template content base.
       *
       * @return the parsed report.
       *
       * @throws IOException if an I/O error occurs.
       * @throws ElementDefinitionException if there is a problem parsing the report template.
       */
      public Object parse(final URL file, final URL contentBase)
          throws ElementDefinitionException, IOException {
          if (file == null) {
              throw new NullPointerException("File may not be null");
          }
  
          final BufferedInputStream bin = new BufferedInputStream(file.openStream());
          final InputSource in = new InputSource(bin);
          in.setSystemId(file.toString());
          final Object result = parse(in, contentBase);
          bin.close();
          return result;
      }
  
  }
  