Package org.hibernate.loader.criteria

Source Code of org.hibernate.loader.criteria.CriteriaJoinWalker

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
*
* 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.loader.criteria;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.AbstractEntityJoinWalker;
import org.hibernate.loader.PropertyPath;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinType;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;

/**
* A <tt>JoinWalker</tt> for <tt>Criteria</tt> queries.
*
* @see CriteriaLoader
* @author Gavin King
*/
public class CriteriaJoinWalker extends AbstractEntityJoinWalker {

  //TODO: add a CriteriaImplementor interface
  //      this class depends directly upon CriteriaImpl in the impl package...

  private final CriteriaQueryTranslator translator;
  private final Set querySpaces;
  private final Type[] resultTypes;
  private final boolean[] includeInResultRow;

  //the user visible aliases, which are unknown to the superclass,
  //these are not the actual "physical" SQL aliases
  private final String[] userAliases;
  private final List<String> userAliasList = new ArrayList<String>();
  private final List<Type> resultTypeList = new ArrayList<Type>();
  private final List<Boolean> includeInResultRowList = new ArrayList<Boolean>();

  public Type[] getResultTypes() {
    return resultTypes;
  }

  public String[] getUserAliases() {
    return userAliases;
  }

  public boolean[] includeInResultRow() {
    return includeInResultRow;
  }

  public CriteriaJoinWalker(
      final OuterJoinLoadable persister,
      final CriteriaQueryTranslator translator,
      final SessionFactoryImplementor factory,
      final CriteriaImpl criteria,
      final String rootEntityName,
      final LoadQueryInfluencers loadQueryInfluencers) {
    this( persister, translator, factory, criteria, rootEntityName, loadQueryInfluencers, null );
  }

  public CriteriaJoinWalker(
      final OuterJoinLoadable persister,
      final CriteriaQueryTranslator translator,
      final SessionFactoryImplementor factory,
      final CriteriaImpl criteria,
      final String rootEntityName,
      final LoadQueryInfluencers loadQueryInfluencers,
      final String alias) {
    super( persister, factory, loadQueryInfluencers, alias );

    this.translator = translator;

    querySpaces = translator.getQuerySpaces();

    if ( translator.hasProjection() ) {     
      initProjection(
          translator.getSelect(),
          translator.getWhereCondition(),
          translator.getOrderBy(),
          translator.getGroupBy(),
          LockOptions.NONE 
        );
      resultTypes = translator.getProjectedTypes();
      userAliases = translator.getProjectedAliases();
      includeInResultRow = new boolean[ resultTypes.length ];
      Arrays.fill( includeInResultRow, true );
    }
    else {
      initAll( translator.getWhereCondition(), translator.getOrderBy(), LockOptions.NONE );
      // root entity comes last
      userAliasList.add( criteria.getAlias() ); //root entity comes *last*
      resultTypeList.add( translator.getResultType( criteria ) );
      includeInResultRowList.add( true );
      userAliases = ArrayHelper.toStringArray( userAliasList );
      resultTypes = ArrayHelper.toTypeArray( resultTypeList );
      includeInResultRow = ArrayHelper.toBooleanArray( includeInResultRowList );
    }
  }
  @Override
  protected JoinType getJoinType(
      OuterJoinLoadable persister,
      final PropertyPath path,
      int propertyNumber,
      AssociationType associationType,
      FetchMode metadataFetchMode,
      CascadeStyle metadataCascadeStyle,
      String lhsTable,
      String[] lhsColumns,
      final boolean nullable,
      final int currentDepth) throws MappingException {
    final JoinType resolvedJoinType;
    if ( translator.isJoin( path.getFullPath() ) ) {
      resolvedJoinType = translator.getJoinType( path.getFullPath() );
    }
    else {
      if ( translator.hasProjection() ) {
        resolvedJoinType = JoinType.NONE;
      }
      else {
        FetchMode fetchMode = translator.getRootCriteria().getFetchMode( path.getFullPath() );
        if ( isDefaultFetchMode( fetchMode ) ) {
          if ( persister != null ) {
            if ( isJoinFetchEnabledByProfile( persister, path, propertyNumber ) ) {
              if ( isDuplicateAssociation( lhsTable, lhsColumns, associationType ) ) {
                resolvedJoinType = JoinType.NONE;
              }
              else if ( isTooDeep(currentDepth) || ( associationType.isCollectionType() && isTooManyCollections() ) ) {
                resolvedJoinType = JoinType.NONE;
              }
              else {
                resolvedJoinType = getJoinType( nullable, currentDepth );
              }
            }
            else {
              resolvedJoinType = super.getJoinType(
                  persister,
                  path,
                  propertyNumber,
                  associationType,
                  metadataFetchMode,
                  metadataCascadeStyle,
                  lhsTable,
                  lhsColumns,
                  nullable,
                  currentDepth
              );
            }
          }
          else {
            resolvedJoinType = super.getJoinType(
                associationType,
                metadataFetchMode,
                path,
                lhsTable,
                lhsColumns,
                nullable,
                currentDepth,
                metadataCascadeStyle
            );

          }
        }
        else {
          if ( fetchMode == FetchMode.JOIN ) {
            isDuplicateAssociation( lhsTable, lhsColumns, associationType ); //deliberately ignore return value!
            resolvedJoinType = getJoinType( nullable, currentDepth );
          }
          else {
            resolvedJoinType = JoinType.NONE;
          }
        }
      }
    }
    return resolvedJoinType;
  }
  @Override
  protected JoinType getJoinType(
      AssociationType associationType,
      FetchMode config,
      PropertyPath path,
      String lhsTable,
      String[] lhsColumns,
      boolean nullable,
      int currentDepth,
      CascadeStyle cascadeStyle) throws MappingException {
    return getJoinType(
        null,
        path,
        -1,
        associationType,
        config,
        cascadeStyle,
        lhsTable,
        lhsColumns,
        nullable,
        currentDepth
    );
  }

  private static boolean isDefaultFetchMode(FetchMode fetchMode) {
    return fetchMode==null || fetchMode==FetchMode.DEFAULT;
  }

  /**
   * Use the discriminator, to narrow the select to instances
   * of the queried subclass, also applying any filters.
   */
  @Override
  protected String getWhereFragment() throws MappingException {
    return super.getWhereFragment() +
      ( (Queryable) getPersister() ).filterFragment( getAlias(), getLoadQueryInfluencers().getEnabledFilters() );
  }
  @Override
  protected String generateTableAlias(int n, PropertyPath path, Joinable joinable) {
    // TODO: deal with side-effects (changes to includeInResultRowList, userAliasList, resultTypeList)!!!

    // for collection-of-entity, we are called twice for given "path"
    // once for the collection Joinable, once for the entity Joinable.
    // the second call will/must "consume" the alias + perform side effects according to consumesEntityAlias()
    // for collection-of-other, however, there is only one call
    // it must "consume" the alias + perform side effects, despite what consumeEntityAlias() return says
    //
    // note: the logic for adding to the userAliasList is still strictly based on consumesEntityAlias return value
    boolean checkForSqlAlias = joinable.consumesEntityAlias();

    if ( !checkForSqlAlias && joinable.isCollection() ) {
      // is it a collection-of-other (component or value) ?
      CollectionPersister collectionPersister = (CollectionPersister)joinable;
      Type elementType = collectionPersister.getElementType();
      if ( elementType.isComponentType() || !elementType.isEntityType() ) {
        checkForSqlAlias = true;
       }
    }

    String sqlAlias = null;

    if ( checkForSqlAlias ) {
      final Criteria subcriteria = translator.getCriteria( path.getFullPath() );
      sqlAlias = subcriteria==null ? null : translator.getSQLAlias(subcriteria);
     
      if (joinable.consumesEntityAlias() && ! translator.hasProjection()) {
        includeInResultRowList.add( subcriteria != null && subcriteria.getAlias() != null );
        if (sqlAlias!=null) {
          if ( subcriteria.getAlias() != null ) {
            userAliasList.add( subcriteria.getAlias() );
            resultTypeList.add( translator.getResultType( subcriteria ) );
          }
        }
      }
    }

    if (sqlAlias == null) {
      sqlAlias = super.generateTableAlias( n + translator.getSQLAliasCount(), path, joinable );
    }

    return sqlAlias;
  }
  @Override
  protected String generateRootAlias(String tableName) {
    return CriteriaQueryTranslator.ROOT_SQL_ALIAS;
  }

  public Set getQuerySpaces() {
    return querySpaces;
  }
  @Override
  public String getComment() {
    return "criteria query";
  }
  @Override
  protected String getWithClause(PropertyPath path) {
    return translator.getWithClause( path.getFullPath() );
  }
  @Override
  protected boolean hasRestriction(PropertyPath path)  {
    return translator.hasRestriction( path.getFullPath() );
  }
}
TOP

Related Classes of org.hibernate.loader.criteria.CriteriaJoinWalker

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.