Package org.hibernate.util

Source Code of org.hibernate.util.XMLHelper

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.hibernate.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.StringReader;
import java.net.URL;
import java.util.List;
import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.dom4j.Document;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.DOMReader;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import org.hibernate.HibernateException;
import org.hibernate.InvalidMappingException;

/**
* Small helper class that lazy loads DOM and SAX reader and keep them for fast use afterwards.
*/
public final class XMLHelper {
  public static final String ORM_1_SCHEMA_NAME = "org/hibernate/ejb/orm_1_0.xsd";
  public static final String ORM_2_SCHEMA_NAME = "org/hibernate/ejb/orm_2_0.xsd";

  private static final Logger log = LoggerFactory.getLogger(XMLHelper.class);
  public static final EntityResolver DEFAULT_DTD_RESOLVER = new DTDEntityResolver();

  private DOMReader domReader;
  private SAXReader saxReader;

  /**
   * Create a dom4j SAXReader which will append all validation errors
   * to errorList
   */
  public SAXReader createSAXReader(String file, List errorsList, EntityResolver entityResolver) {
    SAXReader saxReader = resolveSAXReader();
    saxReader.setEntityResolver(entityResolver);
    saxReader.setErrorHandler( new ErrorLogger(file, errorsList) );
    return saxReader;
  }

  private SAXReader resolveSAXReader() {
    if ( saxReader == null ) {
      saxReader = new SAXReader();
      saxReader.setMergeAdjacentText(true);
      saxReader.setValidation(true);
    }
    return saxReader;
  }

  /**
   * Create a dom4j DOMReader
   */
  public DOMReader createDOMReader() {
    if (domReader==null) domReader = new DOMReader();
    return domReader;
  }

  public static class ErrorLogger implements ErrorHandler {
    private String file;
    private List<SAXParseException> errors;

    private ErrorLogger(String file, List errors) {
      this.file=file;
      this.errors = errors;
    }
    public void error(SAXParseException error) {
      log.error( "Error parsing XML: " + file + '(' + error.getLineNumber() + ") " + error.getMessage() );
      errors.add(error);
    }
    public void fatalError(SAXParseException error) {
      error(error);
    }
    public void warning(SAXParseException warn) {
      log.warn( "Warning parsing XML: " + file + '(' + warn.getLineNumber() + ") " + warn.getMessage() );
    }
  }

  public static Element generateDom4jElement(String elementName) {
    return DocumentFactory.getInstance().createElement( elementName );
  }

  public static void dump(Element element) {
    try {
      // try to "pretty print" it
      OutputFormat outformat = OutputFormat.createPrettyPrint();
      XMLWriter writer = new XMLWriter( System.out, outformat );
      writer.write( element );
      writer.flush();
      System.out.println( "" );
    }
    catch( Throwable t ) {
      // otherwise, just dump it
      System.out.println( element.asXML() );
    }

  }

  public static interface MetadataXmlSource {
    public static interface Origin {
      public String getType();
      public String getName();
    }
    public Origin getOrigin();
    public InputSource getInputSource();
  }

  public static interface MetadataXml extends Serializable {
    public boolean isOrmXml();
    public Document getXmlDocument();
    public String getOriginType();
    public String getOriginName();
  }

  private static class MetadataXmlImpl implements MetadataXml, Serializable {
    private final Document xmlDocument;
    private final boolean isOrmXml;
    private final String originType;
    private final String originName;

    private MetadataXmlImpl(Document xmlDocument, String originType, String originName) {
      this.xmlDocument = xmlDocument;
      this.originType = originType;
      this.originName = originName;
      this.isOrmXml = "entity-mappings".equals( xmlDocument.getRootElement().getName() );
    }

    public Document getXmlDocument() {
      return xmlDocument;
    }

    public boolean isOrmXml() {
      return isOrmXml;
    }

    public String getOriginType() {
      return originType;
    }

    public String getOriginName() {
      return originName;
    }
  }

  public MetadataXml buildMetadataXml(Document xmlDocument, String originType, String originName) {
    return new MetadataXmlImpl( xmlDocument, originType, originName );
  }

  public MetadataXml readMappingDocument(EntityResolver entityResolver, MetadataXmlSource source) {
    // IMPL NOTE : this is the legacy logic as pulled from the old AnnotationConfiguration code

    Exception failure;
    ErrorLogger2 errorHandler = new ErrorLogger2();

    SAXReader saxReader = new SAXReader();
    saxReader.setEntityResolver( entityResolver );
    saxReader.setErrorHandler( errorHandler );
    saxReader.setMergeAdjacentText( true );
    saxReader.setValidation( true );

    Document document = null;
    try {
      // first try with orm 2.0 xsd validation
      setValidationFor( saxReader, "orm_2_0.xsd" );
      document = saxReader.read( source.getInputSource() );
      if ( errorHandler.error != null ) {
        throw errorHandler.error;
      }
      return buildMetadataXml( document, source.getOrigin().getType(), source.getOrigin().getName() );
    }
    catch ( Exception orm2Problem ) {
      log.debug( "Problem parsing XML using orm 2 xsd : {}", orm2Problem.getMessage() );
      failure = orm2Problem;
      errorHandler.error = null;

      if ( document != null ) {
        // next try with orm 1.0 xsd validation
        try {
          setValidationFor( saxReader, "orm_1_0.xsd" );
          document = saxReader.readnew StringReader( document.asXML() ) );
          if ( errorHandler.error != null ) {
            throw errorHandler.error;
          }
          return buildMetadataXml( document, source.getOrigin().getType(), source.getOrigin().getName() );
        }
        catch ( Exception orm1Problem ) {
          log.debug( "Problem parsing XML using orm 1 xsd : {}", orm1Problem.getMessage() );
          errorHandler.error = null;
        }
      }
    }
    throw new InvalidMappingException( "Unable to read XML", source.getOrigin().getType(), source.getOrigin().getName(), failure );

  }

  private void setValidationFor(SAXReader saxReader, String xsd) {
    try {
      saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true );
      //saxReader.setFeature( "http://apache.org/xml/features/validation/dynamic", true );
      //set the default schema locators
      saxReader.setProperty(
          "http://apache.org/xml/properties/schema/external-schemaLocation",
          "http://java.sun.com/xml/ns/persistence/orm " + xsd
      );
    }
    catch ( SAXException e ) {
      saxReader.setValidation( false );
    }
  }

//  public MetadataXml readMappingDocument(EntityResolver entityResolver, MetadataXmlSource source) {
//    Exception failure;
//    ErrorLogger2 errorHandler = new ErrorLogger2();
//
//    SAXReader saxReader = resolveSAXReader();
//    saxReader.setEntityResolver( entityResolver );
//    saxReader.setErrorHandler( errorHandler );
//
//    try {
//      Document document = saxReader.read( source.getInputSource() );
//      if ( errorHandler.error != null ) {
//        Exception problem = errorHandler.error;
//        errorHandler.error = null;
//        throw problem;
//      }
//    }
//    catch ( Exception parseError ) {
//      log.debug( "Problem parsing XML document : {}", parseError.getMessage() );
//    }
//    // first try with orm 2.0 xsd validation
//    try {
//      SAXReader saxReader = orm2SaxReader();
//      if ( errorHandler.error != null ) {
//        Exception problem = errorHandler.error;
//        errorHandler.error = null;
//        throw problem;
//      }
//      return buildMetadataXml( document, source.getOrigin().getType(), source.getOrigin().getName() );
//    }
//    catch ( Exception orm2Problem ) {
//      log.debug( "Problem parsing XML using orm 2 xsd : {}", orm2Problem.getMessage() );
//      failure = orm2Problem;
//
//      // next try with orm 1.0 xsd validation
//      try {
//        SAXReader saxReader = orm1SaxReader();
//        saxReader.setEntityResolver( entityResolver );
//        saxReader.setErrorHandler( errorHandler );
//        Document document = saxReader.read( source.getInputSource() );
//        if ( errorHandler.error != null ) {
//          Exception problem = errorHandler.error;
//          errorHandler.error = null;
//          throw problem;
//        }
//        return buildMetadataXml( document, source.getOrigin().getType(), source.getOrigin().getName() );
//      }
//      catch ( Exception orm1Problem ) {
//        log.debug( "Problem parsing XML using orm 1 xsd : {}", orm1Problem.getMessage() );
//      }
//    }
//    throw new InvalidMappingException( "Unable to read XML", source.getOrigin().getType(), source.getOrigin().getName(), failure );
//  }

  private static class ErrorLogger2 implements ErrorHandler {
    private SAXParseException error; // capture the initial error

    public void error(SAXParseException error) {
      log.error( "Error parsing XML (" + error.getLineNumber() + ") : " + error.getMessage() );
      if ( this.error == null ) {
        this.error = error;
      }
    }
    public void fatalError(SAXParseException error) {
      error( error );
    }
    public void warning(SAXParseException warn) {
      log.error( "Warning parsing XML (" + error.getLineNumber() + ") : " + error.getMessage() );
    }
  }

  private static SAXReader orm2SaxReader;

  private static SAXReader orm2SaxReader() throws IOException, SAXException {
    if ( orm2SaxReader == null ) {
      orm2SaxReader = buildReaderWithSchema( orm2Schema() );
    }
    return orm2SaxReader;
  }

  private static Schema orm2Schema;

  private static Schema orm2Schema() throws IOException, SAXException {
    if ( orm2Schema == null ) {
      orm2Schema = resolveLocalSchema( ORM_2_SCHEMA_NAME );
    }
    return orm2Schema;
  }

  private static Schema resolveLocalSchema(String schemaName) throws IOException, SAXException {
        URL url = ConfigHelper.findAsResource( schemaName );
        InputStream schemaStream = url.openStream();
        try {
            StreamSource source = new StreamSource(url.openStream());
            SchemaFactory schemaFactory = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
            return schemaFactory.newSchema(source);
        }
    finally {
            schemaStream.close();
        }
  }

  private static SAXReader buildReaderWithSchema(Schema schema) throws SAXException {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setSchema( schema );
    try {
      SAXReader saxReader = new SAXReader( factory.newSAXParser().getXMLReader() );
      saxReader.setMergeAdjacentText( true );
      saxReader.setValidation( true );
      return saxReader;
    }
    catch ( ParserConfigurationException e ) {
      throw new HibernateException( "Unable to build SAXReader with XSD support", e );
    }
  }

  private static SAXReader orm1SaxReader;

  private static SAXReader orm1SaxReader() throws IOException, SAXException {
    if ( orm1SaxReader == null ) {
      orm1SaxReader = buildReaderWithSchema( orm1Schema() );
    }
    return orm1SaxReader;
  }

  private static Schema orm1Schema;

  private static Schema orm1Schema() throws IOException, SAXException {
    if ( orm1Schema == null ) {
      orm1Schema = resolveLocalSchema( ORM_1_SCHEMA_NAME );
    }
    return orm1Schema;
  }
}
TOP

Related Classes of org.hibernate.util.XMLHelper

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.