Package org.hibernate.loader.plan.exec.internal

Source Code of org.hibernate.loader.plan.exec.internal.AliasResolutionContextImpl

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.loader.plan.exec.internal;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.jboss.logging.Logger;

import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.hql.internal.NameGenerator;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.DefaultEntityAliases;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.GeneratedCollectionAliases;
import org.hibernate.loader.plan.spi.BidirectionalEntityFetch;
import org.hibernate.loader.plan.exec.spi.AliasResolutionContext;
import org.hibernate.loader.plan.exec.spi.CollectionReferenceAliases;
import org.hibernate.loader.plan.exec.spi.EntityReferenceAliases;
import org.hibernate.loader.plan.spi.AnyFetch;
import org.hibernate.loader.plan.spi.CollectionReference;
import org.hibernate.loader.plan.spi.CompositeElementGraph;
import org.hibernate.loader.plan.spi.CompositeFetch;
import org.hibernate.loader.plan.spi.CompositeIndexGraph;
import org.hibernate.loader.plan.spi.EntityReference;
import org.hibernate.loader.plan.spi.Fetch;
import org.hibernate.loader.plan.spi.FetchOwner;
import org.hibernate.loader.plan.spi.Return;
import org.hibernate.loader.plan.spi.ScalarReturn;
import org.hibernate.loader.plan.spi.SourceQualifiable;
import org.hibernate.loader.plan2.build.spi.TreePrinterHelper;
import org.hibernate.loader.plan2.spi.LoadPlan;
import org.hibernate.loader.plan2.spi.QuerySpace;
import org.hibernate.loader.spi.JoinableAssociation;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.walking.spi.WalkingException;
import org.hibernate.type.EntityType;

/**
* Provides aliases that are used by load queries and ResultSet processors.
*
* @author Gail Badner
* @author Steve Ebersole
*/
public class AliasResolutionContextImpl implements AliasResolutionContext {
  private static final Logger log = CoreLogging.logger( AliasResolutionContextImpl.class );

  private final SessionFactoryImplementor sessionFactory;

  private final Map<Return,String> sourceAliasByReturnMap;
  private final Map<SourceQualifiable,String> sourceQualifiersByReturnMap;

  private final Map<EntityReference,EntityReferenceAliasesImpl> aliasesByEntityReference =
      new HashMap<EntityReference,EntityReferenceAliasesImpl>();
  private final Map<CollectionReference,LoadQueryCollectionAliasesImpl> aliasesByCollectionReference =
      new HashMap<CollectionReference,LoadQueryCollectionAliasesImpl>();
  private final Map<JoinableAssociation,JoinableAssociationAliasesImpl> aliasesByJoinableAssociation =
      new HashMap<JoinableAssociation, JoinableAssociationAliasesImpl>();

  private int currentAliasSuffix;
  private int currentTableAliasUniqueness;

  /**
   * Constructs a AliasResolutionContextImpl without any source aliases.  This form is used in
   * non-query (HQL, criteria, etc) contexts.
   *
   * @param sessionFactory The session factory
   */
  public AliasResolutionContextImpl(SessionFactoryImplementor sessionFactory) {
    this( sessionFactory, 0 );
  }

  /**
   * Constructs a AliasResolutionContextImpl without any source aliases.  This form is used in
   * non-query (HQL, criteria, etc) contexts.
   *
   * @param sessionFactory The session factory
   * @param suffixSeed The seed value to use for generating the suffix used when generating SQL aliases.
   */
  public AliasResolutionContextImpl(SessionFactoryImplementor sessionFactory, int suffixSeed) {
    this(
        sessionFactory,
        suffixSeed,
        Collections.<Return,String>emptyMap(),
        Collections.<SourceQualifiable,String>emptyMap()
    );
  }

  /**
   * Constructs a AliasResolutionContextImpl with source aliases.  See the notes on
   * {@link org.hibernate.loader.plan.exec.spi.AliasResolutionContext#getSourceAlias(Return)} for discussion of "source aliases".
   *
   * @param sessionFactory The session factory
   * @param suffixSeed The seed value to use for generating the suffix used when generating SQL aliases.
   * @param sourceAliasByReturnMap Mapping of the source alias for each return (select-clause assigned alias).
   * @param sourceQualifiersByReturnMap Mapping of source query qualifiers (from-clause assigned alias).
   */
  public AliasResolutionContextImpl(
      SessionFactoryImplementor sessionFactory,
      int suffixSeed,
      Map<Return, String> sourceAliasByReturnMap,
      Map<SourceQualifiable, String> sourceQualifiersByReturnMap) {
    this.sessionFactory = sessionFactory;
    this.currentAliasSuffix = suffixSeed;
    this.sourceAliasByReturnMap = new HashMap<Return, String>( sourceAliasByReturnMap );
    this.sourceQualifiersByReturnMap = new HashMap<SourceQualifiable, String>( sourceQualifiersByReturnMap );
  }

  @Override
  public String getSourceAlias(Return theReturn) {
    return sourceAliasByReturnMap.get( theReturn );
  }

  @Override
  public String[] resolveScalarColumnAliases(ScalarReturn scalarReturn) {
    final int numberOfColumns = scalarReturn.getType().getColumnSpan( sessionFactory );

    // if the scalar return was assigned an alias in the source query, use that as the basis for generating
    // the SQL aliases
    final String sourceAlias = getSourceAlias( scalarReturn );
    if ( sourceAlias != null ) {
      // generate one based on the source alias
      // todo : to do this properly requires dialect involvement ++
      //     due to needing uniqueness even across identifier length based truncation; just truncating is
      //    *not* enough since truncated names might clash
      //
      // for now, don't even truncate...
      return NameGenerator.scalarNames( sourceAlias, numberOfColumns );
    }
    else {
      // generate one from scratch
      return NameGenerator.scalarNames( currentAliasSuffix++, numberOfColumns );
    }
  }

  @Override
  public EntityReferenceAliases resolveAliases(EntityReference entityReference) {
    EntityReferenceAliasesImpl aliases = aliasesByEntityReference.get( entityReference );
    if ( aliases == null ) {
      if ( BidirectionalEntityFetch.class.isInstance( entityReference ) ) {
        return resolveAliases(
            ( (BidirectionalEntityFetch) entityReference ).getTargetEntityReference()
        );
      }
      final EntityPersister entityPersister = entityReference.getEntityPersister();
      aliases = new EntityReferenceAliasesImpl(
          createTableAlias( entityPersister ),
          createEntityAliases( entityPersister )
      );
      aliasesByEntityReference.put( entityReference, aliases );
    }
    return aliases;
  }

  @Override
  public CollectionReferenceAliases resolveAliases(CollectionReference collectionReference) {
    LoadQueryCollectionAliasesImpl aliases = aliasesByCollectionReference.get( collectionReference );
    if ( aliases == null ) {
      final CollectionPersister collectionPersister = collectionReference.getCollectionPersister();
      aliases = new LoadQueryCollectionAliasesImpl(
          createTableAlias( collectionPersister.getRole() ),
          collectionPersister.isManyToMany()
              ? createTableAlias( collectionPersister.getRole() )
              : null,
          createCollectionAliases( collectionPersister ),
          createCollectionElementAliases( collectionPersister )
      );
      aliasesByCollectionReference.put( collectionReference, aliases );
    }
    return aliases;
  }







  @Override
  public String resolveAssociationRhsTableAlias(JoinableAssociation joinableAssociation) {
    return getOrGenerateJoinAssocationAliases( joinableAssociation ).rhsAlias;
  }

  @Override
  public String resolveAssociationLhsTableAlias(JoinableAssociation joinableAssociation) {
    return getOrGenerateJoinAssocationAliases( joinableAssociation ).lhsAlias;
  }

  @Override
  public String[] resolveAssociationAliasedLhsColumnNames(JoinableAssociation joinableAssociation) {
    return getOrGenerateJoinAssocationAliases( joinableAssociation ).aliasedLhsColumnNames;
  }

  protected SessionFactoryImplementor sessionFactory() {
    return sessionFactory;
  }

  private String createSuffix() {
    return Integer.toString( currentAliasSuffix++ ) + '_';
  }

  private JoinableAssociationAliasesImpl getOrGenerateJoinAssocationAliases(JoinableAssociation joinableAssociation) {
    JoinableAssociationAliasesImpl aliases = aliasesByJoinableAssociation.get( joinableAssociation );
    if ( aliases == null ) {
      final Fetch currentFetch = joinableAssociation.getCurrentFetch();
      final String lhsAlias;
      if ( AnyFetch.class.isInstance( currentFetch ) ) {
        throw new WalkingException( "Any type should never be joined!" );
      }
      else if ( EntityReference.class.isInstance( currentFetch.getOwner() ) ) {
        lhsAlias = resolveAliases( (EntityReference) currentFetch.getOwner() ).getTableAlias();
      }
      else if ( CompositeFetch.class.isInstance( currentFetch.getOwner() ) ) {
        lhsAlias = resolveAliases(
            locateCompositeFetchEntityReferenceSource( (CompositeFetch) currentFetch.getOwner() )
        ).getTableAlias();
      }
      else if ( CompositeElementGraph.class.isInstance( currentFetch.getOwner() ) ) {
        CompositeElementGraph compositeElementGraph = (CompositeElementGraph) currentFetch.getOwner();
        lhsAlias = resolveAliases( compositeElementGraph.getCollectionReference() ).getElementTableAlias();
      }
      else if ( CompositeIndexGraph.class.isInstance( currentFetch.getOwner() ) ) {
        CompositeIndexGraph compositeIndexGraph = (CompositeIndexGraph) currentFetch.getOwner();
        lhsAlias = resolveAliases( compositeIndexGraph.getCollectionReference() ).getElementTableAlias();
      }
      else {
        throw new NotYetImplementedException( "Cannot determine LHS alias for FetchOwner." );
      }

      final String[] aliasedLhsColumnNames = currentFetch.toSqlSelectFragments( lhsAlias );
      final String rhsAlias;
      if ( EntityReference.class.isInstance( currentFetch ) ) {
        rhsAlias = resolveAliases( (EntityReference) currentFetch ).getTableAlias();
      }
      else if ( CollectionReference.class.isInstance( joinableAssociation.getCurrentFetch() ) ) {
        rhsAlias = resolveAliases( (CollectionReference) currentFetch ).getCollectionTableAlias();
      }
      else {
        throw new NotYetImplementedException( "Cannot determine RHS alis for a fetch that is not an EntityReference or CollectionReference." );
      }

      // TODO: can't this be found in CollectionAliases or EntityAliases? should be moved to AliasResolutionContextImpl

      aliases = new JoinableAssociationAliasesImpl( lhsAlias, aliasedLhsColumnNames, rhsAlias );
      aliasesByJoinableAssociation.put( joinableAssociation, aliases );
    }
    return aliases;
  }

  private EntityReference locateCompositeFetchEntityReferenceSource(CompositeFetch composite) {
    final FetchOwner owner = composite.getOwner();
    if ( EntityReference.class.isInstance( owner ) ) {
      return (EntityReference) owner;
    }
    if ( CompositeFetch.class.isInstance( owner ) ) {
      return locateCompositeFetchEntityReferenceSource( (CompositeFetch) owner );
    }

    throw new WalkingException( "Cannot resolve entity source for a CompositeFetch" );
  }

  private String createTableAlias(EntityPersister entityPersister) {
    return createTableAlias( StringHelper.unqualifyEntityName( entityPersister.getEntityName() ) );
  }

  private String createTableAlias(String name) {
    return StringHelper.generateAlias( name, currentTableAliasUniqueness++ );
  }

  private EntityAliases createEntityAliases(EntityPersister entityPersister) {
    return new DefaultEntityAliases( (Loadable) entityPersister, createSuffix() );
  }

  private CollectionAliases createCollectionAliases(CollectionPersister collectionPersister) {
    return new GeneratedCollectionAliases( collectionPersister, createSuffix() );
  }

  private EntityAliases createCollectionElementAliases(CollectionPersister collectionPersister) {
    if ( !collectionPersister.getElementType().isEntityType() ) {
      return null;
    }
    else {
      final EntityType entityElementType = (EntityType) collectionPersister.getElementType();
      return createEntityAliases( (EntityPersister) entityElementType.getAssociatedJoinable( sessionFactory() ) );
    }
  }

  private static class LoadQueryCollectionAliasesImpl implements CollectionReferenceAliases {
    private final String tableAlias;
    private final String manyToManyAssociationTableAlias;
    private final CollectionAliases collectionAliases;
    private final EntityAliases entityElementAliases;

    public LoadQueryCollectionAliasesImpl(
        String tableAlias,
        String manyToManyAssociationTableAlias,
        CollectionAliases collectionAliases,
        EntityAliases entityElementAliases) {
      this.tableAlias = tableAlias;
      this.manyToManyAssociationTableAlias = manyToManyAssociationTableAlias;
      this.collectionAliases = collectionAliases;
      this.entityElementAliases = entityElementAliases;
    }

    @Override
    public String getCollectionTableAlias() {
      return StringHelper.isNotEmpty( manyToManyAssociationTableAlias )
          ? manyToManyAssociationTableAlias
          : tableAlias;
    }

    @Override
    public String getElementTableAlias() {
      return tableAlias;
    }

    @Override
    public CollectionAliases getCollectionColumnAliases() {
      return collectionAliases;
    }

    @Override
    public EntityAliases getEntityElementColumnAliases() {
      return entityElementAliases;
    }
  }

  private static class JoinableAssociationAliasesImpl {
    private final String lhsAlias;
    private final String[] aliasedLhsColumnNames;
    private final String rhsAlias;

    public JoinableAssociationAliasesImpl(
        String lhsAlias,
        String[] aliasedLhsColumnNames,
        String rhsAlias) {
      this.lhsAlias = lhsAlias;
      this.aliasedLhsColumnNames = aliasedLhsColumnNames;
      this.rhsAlias = rhsAlias;
    }
  }
}
TOP

Related Classes of org.hibernate.loader.plan.exec.internal.AliasResolutionContextImpl

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.