Open Source Repository

Home /hibernate/hibernate-3.2.7.ga | Repository Home



org/hibernate/loader/custom/sql/SQLQueryReturnProcessor.java
//$Id: SQLQueryReturnProcessor.java 7370 2005-07-04 11:17:33Z maxcsaucdk $
package org.hibernate.loader.custom.sql;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.loader.custom.Return;
import org.hibernate.loader.custom.ScalarReturn;
import org.hibernate.loader.custom.RootReturn;
import org.hibernate.loader.custom.CollectionReturn;
import org.hibernate.loader.custom.ColumnCollectionAliases;
import org.hibernate.loader.custom.FetchReturn;
import org.hibernate.loader.custom.CollectionFetchReturn;
import org.hibernate.loader.custom.NonScalarReturn;
import org.hibernate.loader.custom.EntityFetchReturn;
import org.hibernate.loader.BasicLoader;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.DefaultEntityAliases;
import org.hibernate.loader.ColumnEntityAliases;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.GeneratedCollectionAliases;
import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryCollectionReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryScalarReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryNonScalarReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryJoinReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.persister.collection.SQLLoadableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.SQLLoadable;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Responsible for processing the series of {@link org.hibernate.engine.query.sql.NativeSQLQueryReturn returns}
 * defined by a {@link org.hibernate.engine.query.sql.NativeSQLQuerySpecification} and
 * breaking them down into a series of {@link Return returns} for use within the
 {@link org.hibernate.loader.custom.CustomLoader}.
 *
 @author Gavin King
 @author Max Andersen
 @author Steve Ebersole
 */
public class SQLQueryReturnProcessor {

  public static final Log log = LogFactory.getLogSQLQueryReturnProcessor.class );

  private NativeSQLQueryReturn[] queryReturns;

//  private final List persisters = new ArrayList();

  private final Map alias2Return = new HashMap();
  private final Map alias2OwnerAlias = new HashMap();

  private final Map alias2Persister = new HashMap();
  private final Map alias2Suffix = new HashMap();

  private final Map alias2CollectionPersister = new HashMap();
  private final Map alias2CollectionSuffix = new HashMap();

  private final Map entityPropertyResultMaps = new HashMap();
  private final Map collectionPropertyResultMaps = new HashMap();

//  private final List scalarTypes = new ArrayList();
//  private final List scalarColumnAliases = new ArrayList();

  private final SessionFactoryImplementor factory;

//  private List collectionOwnerAliases = new ArrayList();
//  private List collectionAliases = new ArrayList();
//  private List collectionPersisters = new ArrayList();
//  private List collectionResults = new ArrayList();

  private int entitySuffixSeed = 0;
  private int collectionSuffixSeed = 0;


  public SQLQueryReturnProcessor(NativeSQLQueryReturn[] queryReturns, SessionFactoryImplementor factory) {
    this.queryReturns = queryReturns;
    this.factory = factory;
  }

  /*package*/ class ResultAliasContext {
    public SQLLoadable getEntityPersister(String alias) {
      return SQLLoadable alias2Persister.getalias );
    }

    public SQLLoadableCollection getCollectionPersister(String alias) {
      return SQLLoadableCollection alias2CollectionPersister.getalias );
    }

    public String getEntitySuffix(String alias) {
      return String alias2Suffix.getalias );
    }

    public String getCollectionSuffix(String alias) {
      return String alias2CollectionSuffix.get alias );
    }

    public String getOwnerAlias(String alias) {
      return String alias2OwnerAlias.getalias );
    }

    public Map getPropertyResultsMap(String alias) {
      return internalGetPropertyResultsMapalias );
    }
  }

  private Map internalGetPropertyResultsMap(String alias) {
    NativeSQLQueryReturn rtn = NativeSQLQueryReturn alias2Return.getalias );
    if rtn instanceof NativeSQLQueryNonScalarReturn ) {
      return ( ( NativeSQLQueryNonScalarReturn rtn ).getPropertyResultsMap();
    }
    else {
      return null;
    }
  }

  private boolean hasPropertyResultMap(String alias) {
    Map propertyMaps = internalGetPropertyResultsMapalias );
    return propertyMaps != null && ! propertyMaps.isEmpty();
  }

  public ResultAliasContext process() {
    // first, break down the returns into maps keyed by alias
    // so that role returns can be more easily resolved to their owners
    for int i = 0; i < queryReturns.length; i++ ) {
      if queryReturns[iinstanceof NativeSQLQueryNonScalarReturn ) {
        NativeSQLQueryNonScalarReturn rtn = NativeSQLQueryNonScalarReturn queryReturns[i];
        alias2Return.putrtn.getAlias(), rtn );
        if rtn instanceof NativeSQLQueryJoinReturn ) {
          NativeSQLQueryJoinReturn fetchReturn = NativeSQLQueryJoinReturn rtn;
          alias2OwnerAlias.putfetchReturn.getAlias(), fetchReturn.getOwnerAlias() );
        }
      }
    }

    // Now, process the returns
    for int i = 0; i < queryReturns.length; i++ ) {
      processReturnqueryReturns[i] );
    }

    return new ResultAliasContext();
  }

  public List generateCustomReturns(boolean queryHadAliases) {
    List customReturns = new ArrayList();
    Map customReturnsByAlias = new HashMap();
    for int i = 0; i < queryReturns.length; i++ ) {
      if queryReturns[iinstanceof NativeSQLQueryScalarReturn ) {
        NativeSQLQueryScalarReturn rtn = NativeSQLQueryScalarReturn queryReturns[i];
        customReturns.addnew ScalarReturnrtn.getType(), rtn.getColumnAlias() ) );
      }
      else if queryReturns[iinstanceof NativeSQLQueryRootReturn ) {
        NativeSQLQueryRootReturn rtn = NativeSQLQueryRootReturn queryReturns[i];
        String alias = rtn.getAlias();
        EntityAliases entityAliases;
        if queryHadAliases || hasPropertyResultMapalias ) ) {
          entityAliases = new DefaultEntityAliases(
              Map entityPropertyResultMaps.getalias ),
              SQLLoadable alias2Persister.getalias ),
              String alias2Suffix.getalias )
          );
        }
        else {
          entityAliases = new ColumnEntityAliases(
              Map entityPropertyResultMaps.getalias ),
              SQLLoadable alias2Persister.getalias ),
              String alias2Suffix.getalias )
          );
        }
        RootReturn customReturn = new RootReturn(
            alias,
            rtn.getReturnEntityName(),
            entityAliases,
            rtn.getLockMode()
        );
        customReturns.addcustomReturn );
        customReturnsByAlias.putrtn.getAlias(), customReturn );
      }
      else if queryReturns[iinstanceof NativeSQLQueryCollectionReturn ) {
        NativeSQLQueryCollectionReturn rtn = NativeSQLQueryCollectionReturn queryReturns[i];
        String alias = rtn.getAlias();
        SQLLoadableCollection persister = SQLLoadableCollection alias2CollectionPersister.getalias );
        boolean isEntityElements = persister.getElementType().isEntityType();
        CollectionAliases collectionAliases;
        EntityAliases elementEntityAliases = null;
        if queryHadAliases || hasPropertyResultMapalias ) ) {
          collectionAliases = new GeneratedCollectionAliases(
              Map collectionPropertyResultMaps.getalias ),
              SQLLoadableCollection alias2CollectionPersister.getalias ),
              String alias2CollectionSuffix.getalias )
          );
          if isEntityElements ) {
            elementEntityAliases = new DefaultEntityAliases(
                Map entityPropertyResultMaps.getalias ),
                SQLLoadable alias2Persister.getalias ),
                String alias2Suffix.getalias )
            );
          }
        }
        else {
          collectionAliases = new ColumnCollectionAliases(
              Map collectionPropertyResultMaps.getalias ),
              SQLLoadableCollection alias2CollectionPersister.getalias )
          );
          if isEntityElements ) {
            elementEntityAliases = new ColumnEntityAliases(
                Map entityPropertyResultMaps.getalias ),
                SQLLoadable alias2Persister.getalias ),
                String alias2Suffix.getalias )
            );
          }
        }
        CollectionReturn customReturn = new CollectionReturn(
            alias,
            rtn.getOwnerEntityName(),
            rtn.getOwnerProperty(),
            collectionAliases,
                elementEntityAliases,
            rtn.getLockMode()
        );
        customReturns.addcustomReturn );
        customReturnsByAlias.putrtn.getAlias(), customReturn );
      }
      else if queryReturns[iinstanceof NativeSQLQueryJoinReturn ) {
        NativeSQLQueryJoinReturn rtn = NativeSQLQueryJoinReturn queryReturns[i];
        String alias = rtn.getAlias();
        FetchReturn customReturn;
        NonScalarReturn ownerCustomReturn = NonScalarReturn customReturnsByAlias.getrtn.getOwnerAlias() );
        if alias2CollectionPersister.containsKeyalias ) ) {
          SQLLoadableCollection persister = SQLLoadableCollection alias2CollectionPersister.getalias );
          boolean isEntityElements = persister.getElementType().isEntityType();
          CollectionAliases collectionAliases;
          EntityAliases elementEntityAliases = null;
          if queryHadAliases || hasPropertyResultMapalias ) ) {
            collectionAliases = new GeneratedCollectionAliases(
                Map collectionPropertyResultMaps.getalias ),
                persister,
                String alias2CollectionSuffix.getalias )
            );
            if isEntityElements ) {
              elementEntityAliases = new DefaultEntityAliases(
                  Map entityPropertyResultMaps.getalias ),
                  SQLLoadable alias2Persister.getalias ),
                  String alias2Suffix.getalias )
              );
            }
          }
          else {
            collectionAliases = new ColumnCollectionAliases(
                Map collectionPropertyResultMaps.getalias ),
                persister
            );
            if isEntityElements ) {
              elementEntityAliases = new ColumnEntityAliases(
                  Map entityPropertyResultMaps.getalias ),
                  SQLLoadable alias2Persister.getalias ),
                  String alias2Suffix.getalias )
              );
            }
          }
          customReturn = new CollectionFetchReturn(
              alias,
              ownerCustomReturn,
              rtn.getOwnerProperty(),
              collectionAliases,
                  elementEntityAliases,
              rtn.getLockMode()
          );
        }
        else {
          EntityAliases entityAliases;
          if queryHadAliases || hasPropertyResultMapalias ) ) {
            entityAliases = new DefaultEntityAliases(
                Map entityPropertyResultMaps.getalias ),
                SQLLoadable alias2Persister.getalias ),
                String alias2Suffix.getalias )
            );
          }
          else {
            entityAliases = new ColumnEntityAliases(
                Map entityPropertyResultMaps.getalias ),
                SQLLoadable alias2Persister.getalias ),
                String alias2Suffix.getalias )
            );
          }
          customReturn = new EntityFetchReturn(
              alias,
              entityAliases,
              ownerCustomReturn,
              rtn.getOwnerProperty(),
              rtn.getLockMode()
          );
        }
        customReturns.addcustomReturn );
        customReturnsByAlias.putalias, customReturn );
      }
    }
    return customReturns;
  }

  private SQLLoadable getSQLLoadable(String entityNamethrows MappingException {
    EntityPersister persister = factory.getEntityPersisterentityName );
    if !(persister instanceof SQLLoadable) ) {
      throw new MappingException"class persister is not SQLLoadable: " + entityName );
    }
    return (SQLLoadablepersister;
  }

  private String generateEntitySuffix() {
    return BasicLoader.generateSuffixesentitySuffixSeed++, )[0];
  }

  private String generateCollectionSuffix() {
    return collectionSuffixSeed++ + "__";
  }

  private void processReturn(NativeSQLQueryReturn rtn) {
    if rtn instanceof NativeSQLQueryScalarReturn ) {
      processScalarReturn( ( NativeSQLQueryScalarReturn rtn );
    }
    else if rtn instanceof NativeSQLQueryRootReturn ) {
      processRootReturn( ( NativeSQLQueryRootReturn rtn );
    }
    else if rtn instanceof NativeSQLQueryCollectionReturn ) {
      processCollectionReturn( ( NativeSQLQueryCollectionReturn rtn );
    }
    else {
      processJoinReturn( ( NativeSQLQueryJoinReturn rtn );
    }
  }

  private void processScalarReturn(NativeSQLQueryScalarReturn typeReturn) {
//    scalarColumnAliases.add( typeReturn.getColumnAlias() );
//    scalarTypes.add( typeReturn.getType() );
  }

  private void processRootReturn(NativeSQLQueryRootReturn rootReturn) {
    if alias2Persister.containsKeyrootReturn.getAlias() ) ) {
      // already been processed...
      return;
    }

    SQLLoadable persister = getSQLLoadablerootReturn.getReturnEntityName() );
    addPersisterrootReturn.getAlias(), rootReturn.getPropertyResultsMap(), persister );
  }

  /**
   @param propertyResult
   @param persister
   */
  private void addPersister(String alias, Map propertyResult, SQLLoadable persister) {
    alias2Persister.putalias, persister );
    String suffix = generateEntitySuffix();
    log.trace"mapping alias [" + alias + "] to entity-suffix [" + suffix + "]" );
    alias2Suffix.putalias, suffix );
    entityPropertyResultMaps.putalias, propertyResult );
  }

  private void addCollection(String role, String alias, Map propertyResults) {
    SQLLoadableCollection collectionPersister = SQLLoadableCollection factory.getCollectionPersisterrole );
    alias2CollectionPersister.putalias, collectionPersister );
    String suffix = generateCollectionSuffix();
    log.trace"mapping alias [" + alias + "] to collection-suffix [" + suffix + "]" );
    alias2CollectionSuffix.putalias, suffix );
    collectionPropertyResultMaps.putalias, propertyResults );

    if collectionPersister.isOneToMany() || collectionPersister.isManyToMany() ) {
      SQLLoadable persister = SQLLoadable collectionPersister.getElementPersister();
      addPersisteralias, filterpropertyResults ), persister );
    }
  }

  private Map filter(Map propertyResults) {
    Map result = new HashMappropertyResults.size() );

    String keyPrefix = "element.";

    Iterator iter = propertyResults.entrySet().iterator();
    while iter.hasNext() ) {
      Map.Entry element = Map.Entry iter.next();
      String path = String element.getKey();
      if path.startsWithkeyPrefix ) ) {
        result.putpath.substringkeyPrefix.length() ), element.getValue() );
      }
    }

    return result;
  }

  private void processCollectionReturn(NativeSQLQueryCollectionReturn collectionReturn) {
    // we are initializing an owned collection
    //collectionOwners.add( new Integer(-1) );
//    collectionOwnerAliases.add( null );
    String role = collectionReturn.getOwnerEntityName() '.' + collectionReturn.getOwnerProperty();
    addCollection(
        role,
        collectionReturn.getAlias(),
        collectionReturn.getPropertyResultsMap()
    );
  }

  private void processJoinReturn(NativeSQLQueryJoinReturn fetchReturn) {
    String alias = fetchReturn.getAlias();
//    if ( alias2Persister.containsKey( alias ) || collectionAliases.contains( alias ) ) {
    if alias2Persister.containsKeyalias || alias2CollectionPersister.containsKeyalias ) ) {
      // already been processed...
      return;
    }

    String ownerAlias = fetchReturn.getOwnerAlias();

    // Make sure the owner alias is known...
    if !alias2Return.containsKeyownerAlias ) ) {
      throw new HibernateException"Owner alias [" + ownerAlias + "] is unknown for alias [" + alias + "]" );
    }

    // If this return's alias has not been processed yet, do so b4 further processing of this return
    if !alias2Persister.containsKeyownerAlias ) ) {
      NativeSQLQueryNonScalarReturn ownerReturn = NativeSQLQueryNonScalarReturn alias2Return.get(ownerAlias);
      processReturnownerReturn );
    }

    SQLLoadable ownerPersister = SQLLoadable alias2Persister.getownerAlias );
    Type returnType = ownerPersister.getPropertyTypefetchReturn.getOwnerProperty() );

    if returnType.isCollectionType() ) {
      String role = ownerPersister.getEntityName() '.' + fetchReturn.getOwnerProperty();
      addCollectionrole, alias, fetchReturn.getPropertyResultsMap() );
//      collectionOwnerAliases.add( ownerAlias );
    }
    else if returnType.isEntityType() ) {
      EntityType eType = EntityType returnType;
      String returnEntityName = eType.getAssociatedEntityName();
      SQLLoadable persister = getSQLLoadablereturnEntityName );
      addPersisteralias, fetchReturn.getPropertyResultsMap(), persister );
    }

  }

//  public List getCollectionAliases() {
//    return collectionAliases;
//  }
//
//  /*public List getCollectionOwners() {
//    return collectionOwners;
//  }*/
//
//  public List getCollectionOwnerAliases() {
//    return collectionOwnerAliases;
//  }
//
//  public List getCollectionPersisters() {
//    return collectionPersisters;
//  }
//
//  public Map getAlias2Persister() {
//    return alias2Persister;
//  }
//
//  /*public boolean isCollectionInitializer() {
//    return isCollectionInitializer;
//  }*/
//
////  public List getPersisters() {
////    return persisters;
////  }
//
//  public Map getAlias2OwnerAlias() {
//    return alias2OwnerAlias;
//  }
//
//  public List getScalarTypes() {
//    return scalarTypes;
//  }
//  public List getScalarColumnAliases() {
//    return scalarColumnAliases;
//  }
//
//  public List getPropertyResults() {
//    return propertyResults;
//  }
//
//  public List getCollectionPropertyResults() {
//    return collectionResults;
//  }
//
//
//  public Map getAlias2Return() {
//    return alias2Return;
//  }

}