Package net.xoetrope.optional.data.pojo

Source Code of net.xoetrope.optional.data.pojo.XHibernatePojoDataSource$XHibernateEntityResolver

package net.xoetrope.optional.data.pojo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.XmlSource;
import net.xoetrope.xml.jaxp.JaxpXmlParser;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.data.XModel;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;

/**
* <p>A data source for working with Hibernate POJOs. When the application is loaded the
* datasources are instantiated and in the case of a XPojoDataSource the
* XPojoRoot instance specified by the <code>root</code> element is
* instantiated and configured. The configuration project involves traversing
* the class hierarchy and setting up XPojoModel nodes or proxies for each class
* in the pojo hierarchy, applying Hibernate mapping configuration to the POJO adapters that
* are used in the application. The configuration can specify naming overrides if the
* names established by reflection are not suitable</p>
* <p>Copyright (c) Xoetrope Ltd., 2001-2007<br>
* License:      see license.txt
*/

public class XHibernatePojoDataSource extends XPersistentPojoDataSource
{
  // the names of the collections that can occur in Hibernate mapping files
  private static final String[] COLLECTION_TYPES =
                        { "bag", "idbag", "set", "list", "map" };   
 
  // the fetch types that specifie non-lazily initialized collections
  private static final String[] FETCH_TYPES =
                        { "join", "select", "subselect" };
 
  // stores the configuration of lazily initialized collections
  protected Hashtable hibernateConfiguration;

  // an xml parser used to parse Hibernate mapping files
  protected JaxpXmlParser xmlParser;
 
  /**  
   * Creates a new instance of XHibernatePojoDataSource  
   * @param project the owner project
   */
  public XHibernatePojoDataSource( XProject project
  {
    super( project );
    hibernateConfiguration = new Hashtable();   
    xmlParser = JaxpXmlParser.getInstance( project );
    xmlParser.setEntityResolver( new XHibernateEntityResolver() );
    readMappingFiles();
  }
    
  /**
   * Gets the xml element describing overrides of the class
   * being adapted by the specified adapter. The runtime class name
   * might be different from the one defined in the source code because
   * of the Hibernate proxy object.
   * @param adapter the adapter object
   * @return XmlElement object describing the overrides.
   */
  protected XmlElement getOverrideXml( XPojoAdapter adapter )
  {
    String className = getSourceClassName( adapter.getAdapterClassName() );
    return (XmlElement)overrides.get( className );
  }

  /**
   * Overrides the specified adapter, adds the information about
   * lazily initialized properties.
   * @param adapter the adapter to be overrided.
   */
  protected void overrideAdapter( XPojoAdapter adapter )
  {
    // get the original class name
    String className = getSourceClassName( adapter.getAdapterClassName() );
    // get the list of lazily loaded properties of the adapted class
    List properties = (List)hibernateConfiguration.get( className );
   
    if ( properties != null ) {
      XPersistentPojoAdapter ad = (XPersistentPojoAdapter)adapter;
      // iterate over the properties
      Iterator propertiesIter = properties.iterator();
      while ( propertiesIter.hasNext() ) {
        String propertyName = (String)propertiesIter.next();
        // mark that the collection should be accessed within an open persitence context
        ad.setGetterTransaction( propertyName, null );
      }
    }
    super.overrideAdapter( adapter );
  }   
 
  /**
   * Gets the class name as it was declared in the source code.
   * The passed className might be different because of the Hibernate
   * proxy object.
   * @param className the runtime class name
   * @return the original class name
   */
  private String getSourceClassName( String className )
  {
    int idx = className.indexOf( "$" );
    return ( idx > 0 ? className.substring( 0, idx ) : className );   
  }
 
  /**
   * Creates and returns a new instance of XHibernatePojoModel
   * @param parent the parent model of the model node
   * which is to be created
   * @param subpath String consisting of pojo properties,
   * must be in the format: propertyName(arguments...)[idx]
   * @return XPojoModel object
   */   
  protected XPojoModel createPojoModel( XModel parent, String subPath )
  {
    return ( new XHibernatePojoModel( parent, subPath, this ));
  }
 
  /**
   * Creates and returns a new instance of XHibernatePojoModel
   * @param parent the parent model node
   * @pojo the underlying POJO
   * @return XPojoModel object
   */
  protected XPojoModel createPojoModel( XModel parent, Object pojo
  {
    return ( new XHibernatePojoModel( parent, pojo, this ));
  }
 
  /**
   * Reads the hibernate mapping files and configures the adapters.
   */       
  private void readMappingFiles()
  {
    // read mapping file
    List mappingFiles = new ArrayList();
    try {     
      BufferedReader br = currentProject.getBufferedReader( "hibernate.cfg.xml" );
      XmlElement rootXml = XmlSource.read( br ).getFirstChildNamed( "session-factory" );
      if ( rootXml != null ) {
        Enumeration enumChildren = rootXml.getChildren().elements();
       
        // iterate through the children
        while ( enumChildren.hasMoreElements() ) {
          XmlElement childXml = (XmlElement)enumChildren.nextElement();         
          if ( !"mapping".equals( childXml.getName() ))
            continue;
         
          // store the name of the mapping file
          String fileName = childXml.getAttribute( "resource" );
          if ( fileName != null )
            mappingFiles.add( fileName );
        }
        br.close();
      }
    }
    catch( Exception ex ) {
        DebugLogger.logError( "failed to read Hibernate mapping file names" );
      ex.printStackTrace();
      return;
    }  
   
    // read the configuration from the mapping files
    Iterator fileIter = mappingFiles.iterator();
    while ( fileIter.hasNext() ) {
      String fileName = (String)fileIter.next();
      if ( fileName != null )
        readMappingFile( fileName );
    }
       
  }       
 
  /**
   * Configures the POJO adapters of the classes whose
   * mapping configuration is contained in the specified Hibernate mapping file.
   * @param fileName the name of the Hibernate mapping file.
   */
  private void readMappingFile( String fileName
  {
    try {
      BufferedReader br = currentProject.getBufferedReader( fileName );

      // get the mapping file content
      XmlElement rootXml = xmlParser.parse( br );
           
      // get the name of the package containing the mapped classes     
      String packageName = rootXml.getAttribute( "package" );
      if ( packageName == null )
        return;
     
      // read the entity definitions
      Enumeration enumClasses = rootXml.getChildren().elements();
      while ( enumClasses.hasMoreElements() ) {
       
        // read the configuration of a single class
        XmlElement classXml = (XmlElement)enumClasses.nextElement();
        if ( !"class".equals( classXml.getName() ))
          continue;       
        String className = ( packageName + "." + classXml.getAttribute( "name" ));
       
        // iterate over the properties of a class
        Enumeration enumProperties = classXml.getChildren().elements();
        while ( enumProperties.hasMoreElements() ) {
          // read the property configuration
          XmlElement propertyXml = (XmlElement)enumProperties.nextElement();         
         
          // check whether the xml node defines a "lazy" collection
          if ( isLazyCollection( propertyXml )) {           
            // mark that the collection is lazily initialized
            String propertyName = propertyXml.getAttribute( "name" );
            List properties = (List)hibernateConfiguration.get( className );                       
            if ( properties == null )
              hibernateConfiguration.put( className, properties = new ArrayList() );
            properties.add( propertyName );
          }
         
        }
      }
      br.close();
    }
    catch( Exception ex ) {
      DebugLogger.logError( "unable to read the file: " + fileName );
      ex.printStackTrace();
    }
  }

  /**
   * Indicates whether the specified xml node specifies a Hibernate lazily
   * initialized collection.
   * @param propertyXml xml node describing POJO property, it should belong
   * to a Hibernate entity mapping file.
   */
  private boolean isLazyCollection( XmlElement propertyXml )
  {
    if ( propertyXml == null )
      return false;
   
    // check if the given xml node specifies a collection   
    String propertyType = propertyXml.getName();
    boolean ic = false;
    for ( int i = 0; !ic && ( i < COLLECTION_TYPES.length ); i++ )
      ic = COLLECTION_TYPES[ i ].equalsIgnoreCase( propertyType );
    if ( !ic )
      return false; // the property is not a collection

    // check if the collection is lazily initialized
    String fetchType = propertyXml.getAttribute( "fetch" );           
       
    if ( fetchType == null )
      return true; // no "fetch" attribute, collection is lazy
   
    // check the value of the "fetch" attribute
    boolean il = true;
    for ( int i = 0; il && ( i < FETCH_TYPES.length ); i++ )
      il = !FETCH_TYPES[ i ].equalsIgnoreCase( fetchType );
   
    return il;
  }   
 
  /**
   * An entity resolver used to avoid loading remote DTD files when
   * reading Hibernate mapping files.
   */
  private class XHibernateEntityResolver implements EntityResolver
  {
    public InputSource resolveEntity( String publicID, String systemID )
    throws SAXException
    {
      InputSource inputSource = null;
      // don't load DTD files
      if ( systemID.endsWith( ".dtd" )) {     
        // create an empty InputStream object
        InputStream inputStream = ( new InputStream() {
          public int read() throws IOException { return -1; }
        });
        // create the data-less input source
        inputSource = new InputSource( inputStream );
      }
      return inputSource;
    }
  }
   
}
TOP

Related Classes of net.xoetrope.optional.data.pojo.XHibernatePojoDataSource$XHibernateEntityResolver

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.