Package net.sf.jasperreports.engine.xml

Source Code of net.sf.jasperreports.engine.xml.JRReportSaxParserFactory

/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2009 Jaspersoft Corporation. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports 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 3 of the License, or
* (at your option) any later version.
*
* JasperReports 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 JasperReports. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.jasperreports.engine.xml;

import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.component.ComponentsBundle;
import net.sf.jasperreports.engine.component.ComponentsEnvironment;
import net.sf.jasperreports.engine.component.ComponentsXmlParser;
import net.sf.jasperreports.engine.util.ClassUtils;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.engine.util.JRProperties;

import org.apache.commons.collections.ReferenceMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;

/**
* The default report SAX parser factory.
*
* <p>
* This factory creates a parser via the default SAX parser factory
* (<code>javax.xml.parsers.SAXParserFactory.newInstance()</code>).
*
* <p>
* JRXMLs are always validated using W3C XML schemas.  Reports that refer
* the JasperReports DTD (which has been deprecated) are validated using an
* internal XML schema equivalent to the DTD.
*
* <p>
* To improve performance, XML schemas can be cached when using a Xerces
* SAX parser.  See {@link #PROPERTY_CACHE_SCHEMAS}.
*
* @author Lucian Chirita (lucianc@users.sourceforge.net)
* @version $Id: JRReportSaxParserFactory.java 3657 2010-03-31 09:34:49Z teodord $
*/
public class JRReportSaxParserFactory implements JRSaxParserFactory
{
 
  private static final Log log = LogFactory.getLog(JRXmlDigesterFactory.class);
 
  /**
   * A property that determines whether XML schemas/grammars are to be cached
   * so that they are not read/initialized each time a report is compiled.
   *
   * <p>
   * Currently, setting this property is only effective when a Xerces XML
   * parser is used (either a stock one from Apache or one embedded into a
   * SUN JDK).
   */
  public static final String PROPERTY_CACHE_SCHEMAS = JRProperties.PROPERTY_PREFIX
    + "compiler.xml.parser.cache.schemas";

  protected static final String PACKAGE_PREFIX_XERCES = "org.apache.xerces";
  protected static final String POOL_CLASS_XERCES = "org.apache.xerces.util.XMLGrammarPoolImpl";
 
  protected static final String PACKAGE_PREFIX_SUN_XERCES = "com.sun.org.apache.xerces";
  protected static final String POOL_CLASS_SUN_XERCES = "com.sun.org.apache.xerces.internal.util.XMLGrammarPoolImpl";
 
  protected static final String XERCES_PARSER_PROPERTY_GRAMMAR_POOL =
    "http://apache.org/xml/properties/internal/grammar-pool";
 
  private final static Object GRAMMAR_POOL_CACHE_NULL_KEY = "Null context classloader";
  private final static ThreadLocal GRAMMAR_POOL_CACHE = new ThreadLocal();
 
  public SAXParser createParser()
  {
    try
    {
      SAXParserFactory parserFactory = createSAXParserFactory();
      SAXParser parser = parserFactory.newSAXParser();
      configureParser(parser);
      return parser;
    }
    catch (SAXException e)
    {
      throw new JRRuntimeException("Error creating SAX parser", e);
    }
    catch (ParserConfigurationException e)
    {
      throw new JRRuntimeException("Error creating SAX parser", e);
    }
  }

  protected SAXParserFactory createSAXParserFactory()
      throws ParserConfigurationException, SAXException
  {
    SAXParserFactory parserFactory = SAXParserFactory.newInstance();
   
    if (log.isDebugEnabled())
    {
      log.debug("Instantiated SAX parser factory of type "
          + parserFactory.getClass().getName());
    }
   
    parserFactory.setNamespaceAware(true);

    boolean validating = JRProperties.getBooleanProperty(JRProperties.COMPILER_XML_VALIDATION);
    parserFactory.setValidating(validating);
    parserFactory.setFeature("http://xml.org/sax/features/validation", validating);
    return parserFactory;
  }

  protected void configureParser(SAXParser parser)
      throws SAXException
  {
    List schemaLocations = getSchemaLocations();
    parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
      "http://www.w3.org/2001/XMLSchema");
    parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource",
      schemaLocations.toArray(new String[schemaLocations.size()]));
   
    boolean cache = JRProperties.getBooleanProperty(PROPERTY_CACHE_SCHEMAS);
    if (cache)
    {
      enableSchemaCaching(parser);
    }
  }

  protected List getSchemaLocations()
  {
    List schemas = new ArrayList();
    schemas.add(getResourceURI(JRXmlConstants.JASPERREPORT_XSD_RESOURCE));
    schemas.add(getResourceURI(JRXmlConstants.JASPERREPORT_XSD_DTD_COMPAT_RESOURCE));
   
    Collection components = ComponentsEnvironment.getComponentBundles();
    for (Iterator it = components.iterator(); it.hasNext();)
    {
      ComponentsBundle componentManager = (ComponentsBundle) it.next();
      ComponentsXmlParser xmlParser = componentManager.getXmlParser();
     
      String schemaURI;
      String schemaResource = xmlParser.getInternalSchemaResource();
      if (schemaResource != null)
      {
        schemaURI = getResourceURI(schemaResource);
      }
      else
      {
        schemaURI = xmlParser.getPublicSchemaLocation();
      }

      if (log.isDebugEnabled())
      {
        log.debug("Adding components schema at " + schemaURI);
      }
     
      schemas.add(schemaURI);
    }
    return schemas;
  }

  protected String getResourceURI(String resource)
  {
    URL location = JRLoader.getResource(resource);
    if (location == null)
    {
      throw new JRRuntimeException("Could not find resource " + resource);
    }
    return location.toExternalForm();
  }

  protected void enableSchemaCaching(SAXParser parser)
  {
    String parserType = parser.getClass().getName();
    if (parserType.startsWith(PACKAGE_PREFIX_XERCES))
    {
      setGrammarPoolProperty(parser, POOL_CLASS_XERCES);
    }
    else if (parserType.startsWith(PACKAGE_PREFIX_SUN_XERCES))
    {
      setGrammarPoolProperty(parser, POOL_CLASS_SUN_XERCES);
    }
    else
    {
      if (log.isDebugEnabled())
      {
        log.debug("Schema caching only works with Xerces parsers");
      }
    }
  }
 
  protected void setGrammarPoolProperty(SAXParser parser, String poolClassName)
  {
    try
    {
      Object cacheKey = getGrammarPoolCacheKey();
     
      // we're using thread local caches to avoid thread safety problems
      ReferenceMap cacheMap = (ReferenceMap) GRAMMAR_POOL_CACHE.get();
      if (cacheMap == null)
      {
        cacheMap = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.SOFT);
        GRAMMAR_POOL_CACHE.set(cacheMap);
      }
     
      Object grammarPool = cacheMap.get(cacheKey);
      if (grammarPool == null)
      {
        if (log.isDebugEnabled())
        {
          log.debug("Instantiating grammar pool of type " + poolClassName
              + " for cache key " + cacheKey);
        }

        grammarPool = ClassUtils.instantiateClass(poolClassName, Object.class);
        cacheMap.put(cacheKey, grammarPool);
      }
     
      parser.setProperty(XERCES_PARSER_PROPERTY_GRAMMAR_POOL, grammarPool);
    }
    catch (Exception e)
    {
      if (log.isDebugEnabled())
      {
        log.debug("Error setting Xerces grammar pool of type " + poolClassName, e);
      }
    }
  }

  protected Object getGrammarPoolCacheKey()
  {
    Object key = Thread.currentThread().getContextClassLoader();
    if (key == null)
    {
      key = GRAMMAR_POOL_CACHE_NULL_KEY;
    }
    return key;
  }

}
TOP

Related Classes of net.sf.jasperreports.engine.xml.JRReportSaxParserFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.