Package org.hibernate.ejb.packaging

Source Code of org.hibernate.ejb.packaging.PersistenceXmlLoader

/*
* 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.ejb.packaging;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.persistence.PersistenceException;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.hibernate.ejb.AvailableSettings;
import org.hibernate.ejb.internal.EntityManagerMessageLogger;
import org.hibernate.ejb.util.ConfigurationHelper;
import org.hibernate.internal.util.StringHelper;
import org.jboss.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;

/**
* Handler for persistence.xml files.
*
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
* @author Emmanuel Bernard
*/
public final class PersistenceXmlLoader {

    private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
                                                                           PersistenceXmlLoader.class.getName());

  private PersistenceXmlLoader() {
  }

  private static Document loadURL(URL configURL, EntityResolver resolver) throws Exception {
    /*
     * try and parse the document:
     *  - try and validate the document with persistence_2_0.xsd
      * - if it fails because of the version attribute mismatch, try and validate the document with persistence_1_0.xsd
     */
    InputStream is = null;
    if (configURL != null) {
      URLConnection conn = configURL.openConnection();
      conn.setUseCaches( false ); //avoid JAR locking on Windows and Tomcat
      is = conn.getInputStream();
    }
    if ( is == null ) {
      throw new IOException( "Failed to obtain InputStream while reading persistence.xml file: " + configURL );
    }

    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    docBuilderFactory.setNamespaceAware( true );
    final Schema v2Schema = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI )
        .newSchema( new StreamSource( getStreamFromClasspath( "persistence_2_0.xsd" ) ) );
    final Validator v2Validator = v2Schema.newValidator();
    final Schema v1Schema = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI )
        .newSchema( new StreamSource( getStreamFromClasspath( "persistence_1_0.xsd" ) ) );
    final Validator v1Validator = v1Schema.newValidator();

    InputSource source = new InputSource( is );
    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
    docBuilder.setEntityResolver( resolver );
    List<SAXParseException> errors = new ArrayList<SAXParseException>();
    Document doc = null;

    //first sparse document and collect syntaxic errors
    try {
      doc = docBuilder.parse( source );
    }
    catch ( SAXParseException e ) {
      errors.add( e );
    }

    if (errors.size() == 0) {
      v2Validator.setErrorHandler( new ErrorLogger( errors ) );
            LOG.trace("Validate with persistence_2_0.xsd schema on file " + configURL);
      v2Validator.validate( new DOMSource( doc ) );
      boolean isV1Schema = false;
      if ( errors.size() != 0 ) {
        //v2 fails, it could be because the file is v1.
                LOG.trace("Found error with persistence_2_0.xsd schema on file " + configURL);
        SAXParseException exception = errors.get( 0 );
        final String errorMessage = exception.getMessage();
        //is it a validation error due to a v1 schema validated by a v2
        isV1Schema = errorMessage.contains("1.0")
            && errorMessage.contains("2.0")
            && errorMessage.contains("version");

      }
      if (isV1Schema) {
                LOG.trace("Validate with persistence_1_0.xsd schema on file " + configURL);
        errors.clear();
        v1Validator.setErrorHandler( new ErrorLogger( errors ) );
        v1Validator.validate( new DOMSource( doc ) );
      }
    }
    if ( errors.size() != 0 ) {
      //report all errors in the exception
      StringBuilder errorMessage = new StringBuilder( );
      for (SAXParseException error : errors) {
        errorMessage.append("Error parsing XML (line")
              .append(error.getLineNumber())
              .append(" : column ")
              .append(error.getColumnNumber())
              .append("): ")
              .append(error.getMessage())
              .append("\n");
      }
      throw new PersistenceException( "Invalid persistence.xml.\n" + errorMessage.toString() );
    }
    return doc;
  }

  private static InputStream getStreamFromClasspath(String fileName) {
    String path = "org/hibernate/ejb/" + fileName;
    InputStream dtdStream = PersistenceXmlLoader.class.getClassLoader().getResourceAsStream( path );
    return dtdStream;
  }

  /**
     * Method used by JBoss AS 4.0.5 for parsing
     */
  public static List<PersistenceMetadata> deploy(URL url, Map overrides, EntityResolver resolver) throws Exception {
        return deploy(url, overrides, resolver, PersistenceUnitTransactionType.JTA);
    }

  /**
   * Method used by JBoss EJB3 (4.2 and above) for parsing
   * Object used by Hibernate OGM as well, consider this some kind of exposed service at the SPI level
   */
    public static List<PersistenceMetadata> deploy(URL url, Map overrides, EntityResolver resolver,
                           PersistenceUnitTransactionType defaultTransactionType) throws Exception {
    Document doc = loadURL( url, resolver );
    Element top = doc.getDocumentElement();
    //version is mandatory
    final String version = top.getAttribute( "version" );

    NodeList children = top.getChildNodes();
    ArrayList<PersistenceMetadata> units = new ArrayList<PersistenceMetadata>();
    for ( int i = 0; i < children.getLength() ; i++ ) {
      if ( children.item( i ).getNodeType() == Node.ELEMENT_NODE ) {
        Element element = (Element) children.item( i );
        String tag = element.getTagName();
        if ( tag.equals( "persistence-unit" ) ) {
          PersistenceMetadata metadata = parsePersistenceUnit( element );
          metadata.setVersion(version);
          //override properties of metadata if needed
          if ( overrides.containsKey( AvailableSettings.PROVIDER ) ) {
            String provider = (String) overrides.get( AvailableSettings.PROVIDER );
            metadata.setProvider( provider );
          }
          if ( overrides.containsKey( AvailableSettings.TRANSACTION_TYPE ) ) {
            String transactionType = (String) overrides.get( AvailableSettings.TRANSACTION_TYPE );
            metadata.setTransactionType( PersistenceXmlLoader.getTransactionType( transactionType ) );
          }
          if ( overrides.containsKey( AvailableSettings.JTA_DATASOURCE ) ) {
            String dataSource = (String) overrides.get( AvailableSettings.JTA_DATASOURCE );
            metadata.setJtaDatasource( dataSource );
          }
          if ( overrides.containsKey( AvailableSettings.NON_JTA_DATASOURCE ) ) {
            String dataSource = (String) overrides.get( AvailableSettings.NON_JTA_DATASOURCE );
            metadata.setNonJtaDatasource( dataSource );
          }
          /*
           * if explicit => use it
           * if JTA DS => JTA transaction
           * if non JTA DA => RESOURCE_LOCAL transaction
           * else default JavaSE => RESOURCE_LOCAL
           */
          PersistenceUnitTransactionType transactionType = metadata.getTransactionType();
          Boolean isJTA = null;
          if ( StringHelper.isNotEmpty( metadata.getJtaDatasource() ) ) {
            isJTA = Boolean.TRUE;
          }
          else if ( StringHelper.isNotEmpty( metadata.getNonJtaDatasource() ) ) {
            isJTA = Boolean.FALSE;
          }
          if (transactionType == null) {
            if (isJTA == Boolean.TRUE) {
              transactionType = PersistenceUnitTransactionType.JTA;
            }
            else if (isJTA == Boolean.FALSE) {
              transactionType = PersistenceUnitTransactionType.RESOURCE_LOCAL;
            }
            else {
              transactionType = defaultTransactionType;
            }
          }
          metadata.setTransactionType( transactionType );
          Properties properties = metadata.getProps();
          ConfigurationHelper.overrideProperties( properties, overrides );
          units.add( metadata );
        }
      }
    }
    return units;
  }

  private static PersistenceMetadata parsePersistenceUnit(Element top)
      throws Exception {
    PersistenceMetadata metadata = new PersistenceMetadata();
    String puName = top.getAttribute( "name" );
    if ( StringHelper.isNotEmpty( puName ) ) {
            LOG.trace("Persistent Unit name from persistence.xml: " + puName);
      metadata.setName( puName );
    }
    NodeList children = top.getChildNodes();
    for ( int i = 0; i < children.getLength() ; i++ ) {
      if ( children.item( i ).getNodeType() == Node.ELEMENT_NODE ) {
        Element element = (Element) children.item( i );
        String tag = element.getTagName();
//        if ( tag.equals( "name" ) ) {
//          String puName = XmlHelper.getElementContent( element );
//          log.trace( "FOUND PU NAME: " + puName );
//          metadata.setName( puName );
//        }
//        else
        if ( tag.equals( "non-jta-data-source" ) ) {
          metadata.setNonJtaDatasource( XmlHelper.getElementContent( element ) );
        }
        else if ( tag.equals( "jta-data-source" ) ) {
          metadata.setJtaDatasource( XmlHelper.getElementContent( element ) );
        }
        else if ( tag.equals( "provider" ) ) {
          metadata.setProvider( XmlHelper.getElementContent( element ) );
        }
        else if ( tag.equals( "class" ) ) {
          metadata.getClasses().add( XmlHelper.getElementContent( element ) );
        }
        else if ( tag.equals( "mapping-file" ) ) {
          metadata.getMappingFiles().add( XmlHelper.getElementContent( element ) );
        }
        else if ( tag.equals( "jar-file" ) ) {
          metadata.getJarFiles().add( XmlHelper.getElementContent( element ) );
        }
        else if ( tag.equals( "exclude-unlisted-classes" ) ) {
          metadata.setExcludeUnlistedClasses( true );
        }
        else if ( tag.equals( "delimited-identifiers" ) ) {
          metadata.setUseQuotedIdentifiers( true );
        }
        else if ( tag.equals( "validation-mode" ) ) {
          metadata.setValidationMode( XmlHelper.getElementContent( element ) );
        }
        else if ( tag.equals( "shared-cache-mode" ) ) {
          metadata.setSharedCacheMode( XmlHelper.getElementContent( element ) );
        }
        else if ( tag.equals( "properties" ) ) {
          NodeList props = element.getChildNodes();
          for ( int j = 0; j < props.getLength() ; j++ ) {
            if ( props.item( j ).getNodeType() == Node.ELEMENT_NODE ) {
              Element propElement = (Element) props.item( j );
              if ( !"property".equals( propElement.getTagName() ) ) continue;
              String propName = propElement.getAttribute( "name" ).trim();
              String propValue = propElement.getAttribute( "value" ).trim();
              if ( StringHelper.isEmpty( propValue ) ) {
                //fall back to the natural (Hibernate) way of description
                propValue = XmlHelper.getElementContent( propElement, "" );
              }
              metadata.getProps().put( propName, propValue );
            }
          }

        }
      }
    }
    PersistenceUnitTransactionType transactionType = getTransactionType( top.getAttribute( "transaction-type" ) );
    if (transactionType != null) metadata.setTransactionType( transactionType );

    return metadata;
  }

  public static PersistenceUnitTransactionType getTransactionType(String elementContent) {
    if ( StringHelper.isEmpty( elementContent ) ) {
      return null; //PersistenceUnitTransactionType.JTA;
    }
    else if ( elementContent.equalsIgnoreCase( "JTA" ) ) {
      return PersistenceUnitTransactionType.JTA;
    }
    else if ( elementContent.equalsIgnoreCase( "RESOURCE_LOCAL" ) ) {
      return PersistenceUnitTransactionType.RESOURCE_LOCAL;
    }
    else {
      throw new PersistenceException( "Unknown TransactionType: " + elementContent );
    }
  }

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

    ErrorLogger(List<SAXParseException> errors) {
      this.errors = errors;
    }

    public void error(SAXParseException error) {
      //what was this commented code about?
//      if ( resolver instanceof EJB3DTDEntityResolver ) {
//        if ( ( (EJB3DTDEntityResolver) resolver ).isResolved() == false ) return;
//      }
      errors.add( error );
    }

    public void fatalError(SAXParseException error) {
      errors.add( error );
    }

    public void warning(SAXParseException warn) {
    }
  }

}
TOP

Related Classes of org.hibernate.ejb.packaging.PersistenceXmlLoader

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.