Package org.hibernate.engine

Source Code of org.hibernate.engine.JoinSequence

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

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

import org.hibernate.MappingException;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.QueryJoinFragment;
import org.hibernate.type.AssociationType;
import org.hibernate.util.CollectionHelper;

/**
* @author Gavin King
*/
public class JoinSequence {

  private final SessionFactoryImplementor factory;
  private final List joins = new ArrayList();
  private boolean useThetaStyle = false;
  private final StringBuffer conditions = new StringBuffer();
  private String rootAlias;
  private Joinable rootJoinable;
  private Selector selector;
  private JoinSequence next;
  private boolean isFromPart = false;

  public String toString() {
    StringBuffer buf = new StringBuffer();
    buf.append( "JoinSequence{" );
    if ( rootJoinable != null ) {
      buf.append( rootJoinable )
          .append( '[' )
          .append( rootAlias )
          .append( ']' );
    }
    for ( int i = 0; i < joins.size(); i++ ) {
      buf.append( "->" ).append( joins.get( i ) );
    }
    return buf.append( '}' ).toString();
  }

  final class Join {

    private final AssociationType associationType;
    private final Joinable joinable;
    private final int joinType;
    private final String alias;
    private final String[] lhsColumns;

    Join(AssociationType associationType, String alias, int joinType, String[] lhsColumns)
        throws MappingException {
      this.associationType = associationType;
      this.joinable = associationType.getAssociatedJoinable( factory );
      this.alias = alias;
      this.joinType = joinType;
      this.lhsColumns = lhsColumns;
    }

    String getAlias() {
      return alias;
    }

    AssociationType getAssociationType() {
      return associationType;
    }

    Joinable getJoinable() {
      return joinable;
    }

    int getJoinType() {
      return joinType;
    }

    String[] getLHSColumns() {
      return lhsColumns;
    }

    public String toString() {
      return joinable.toString() + '[' + alias + ']';
    }
  }

  public JoinSequence(SessionFactoryImplementor factory) {
    this.factory = factory;
  }

  public JoinSequence getFromPart() {
    JoinSequence fromPart = new JoinSequence( factory );
    fromPart.joins.addAll( this.joins );
    fromPart.useThetaStyle = this.useThetaStyle;
    fromPart.rootAlias = this.rootAlias;
    fromPart.rootJoinable = this.rootJoinable;
    fromPart.selector = this.selector;
    fromPart.next = this.next == null ? null : this.next.getFromPart();
    fromPart.isFromPart = true;
    return fromPart;
  }

  public JoinSequence copy() {
    JoinSequence copy = new JoinSequence( factory );
    copy.joins.addAll( this.joins );
    copy.useThetaStyle = this.useThetaStyle;
    copy.rootAlias = this.rootAlias;
    copy.rootJoinable = this.rootJoinable;
    copy.selector = this.selector;
    copy.next = this.next == null ? null : this.next.copy();
    copy.isFromPart = this.isFromPart;
    copy.conditions.append( this.conditions.toString() );
    return copy;
  }

  public JoinSequence addJoin(AssociationType associationType, String alias, int joinType, String[] referencingKey)
      throws MappingException {
    joins.add( new Join( associationType, alias, joinType, referencingKey ) );
    return this;
  }

  public JoinFragment toJoinFragment() throws MappingException {
    return toJoinFragment( CollectionHelper.EMPTY_MAP, true );
  }

  public JoinFragment toJoinFragment(Map enabledFilters, boolean includeExtraJoins) throws MappingException {
    return toJoinFragment( enabledFilters, includeExtraJoins, null, null );
  }

  public JoinFragment toJoinFragment(
      Map enabledFilters,
          boolean includeExtraJoins,
          String withClauseFragment,
          String withClauseJoinAlias) throws MappingException {
    QueryJoinFragment joinFragment = new QueryJoinFragment( factory.getDialect(), useThetaStyle );
    if ( rootJoinable != null ) {
      joinFragment.addCrossJoin( rootJoinable.getTableName(), rootAlias );
      String filterCondition = rootJoinable.filterFragment( rootAlias, enabledFilters );
      // JoinProcessor needs to know if the where clause fragment came from a dynamic filter or not so it
      // can put the where clause fragment in the right place in the SQL AST.   'hasFilterCondition' keeps track
      // of that fact.
      joinFragment.setHasFilterCondition( joinFragment.addCondition( filterCondition ) );
      if (includeExtraJoins) { //TODO: not quite sure about the full implications of this!
        addExtraJoins( joinFragment, rootAlias, rootJoinable, true );
      }
    }

    Joinable last = rootJoinable;

    for ( int i = 0; i < joins.size(); i++ ) {
      Join join = ( Join ) joins.get( i );
      String on = join.getAssociationType().getOnCondition( join.getAlias(), factory, enabledFilters );
      String condition = null;
      if ( last != null &&
              isManyToManyRoot( last ) &&
              ( ( QueryableCollection ) last ).getElementType() == join.getAssociationType() ) {
        // the current join represents the join between a many-to-many association table
        // and its "target" table.  Here we need to apply any additional filters
        // defined specifically on the many-to-many
        String manyToManyFilter = ( ( QueryableCollection ) last )
                .getManyToManyFilterFragment( join.getAlias(), enabledFilters );
        condition = "".equals( manyToManyFilter )
            ? on
            : "".equals( on )
                ? manyToManyFilter
                : on + " and " + manyToManyFilter;
      }
      else {
        condition = on;
      }
      if ( withClauseFragment != null ) {
        if ( join.getAlias().equals( withClauseJoinAlias ) ) {
          condition += " and " + withClauseFragment;
        }
      }
      joinFragment.addJoin(
              join.getJoinable().getTableName(),
          join.getAlias(),
          join.getLHSColumns(),
          JoinHelper.getRHSColumnNames( join.getAssociationType(), factory ),
          join.joinType,
          condition
      );
      if (includeExtraJoins) { //TODO: not quite sure about the full implications of this!
        addExtraJoins( joinFragment, join.getAlias(), join.getJoinable(), join.joinType == JoinFragment.INNER_JOIN );
      }
      last = join.getJoinable();
    }
    if ( next != null ) {
      joinFragment.addFragment( next.toJoinFragment( enabledFilters, includeExtraJoins ) );
    }
    joinFragment.addCondition( conditions.toString() );
    if ( isFromPart ) joinFragment.clearWherePart();
    return joinFragment;
  }

  private boolean isManyToManyRoot(Joinable joinable) {
    if ( joinable != null && joinable.isCollection() ) {
      QueryableCollection persister = ( QueryableCollection ) joinable;
      return persister.isManyToMany();
    }
    return false;
  }

  private boolean isIncluded(String alias) {
    return selector != null && selector.includeSubclasses( alias );
  }

  private void addExtraJoins(JoinFragment joinFragment, String alias, Joinable joinable, boolean innerJoin) {
    boolean include = isIncluded( alias );
    joinFragment.addJoins( joinable.fromJoinFragment( alias, innerJoin, include ),
        joinable.whereJoinFragment( alias, innerJoin, include ) );
  }

  public JoinSequence addCondition(String condition) {
    if ( condition.trim().length() != 0 ) {
      if ( !condition.startsWith( " and " ) ) conditions.append( " and " );
      conditions.append( condition );
    }
    return this;
  }

  public JoinSequence addCondition(String alias, String[] columns, String condition) {
    for ( int i = 0; i < columns.length; i++ ) {
      conditions.append( " and " )
          .append( alias )
          .append( '.' )
          .append( columns[i] )
          .append( condition );
    }
    return this;
  }

  public JoinSequence setRoot(Joinable joinable, String alias) {
    this.rootAlias = alias;
    this.rootJoinable = joinable;
    return this;
  }

  public JoinSequence setNext(JoinSequence next) {
    this.next = next;
    return this;
  }

  public JoinSequence setSelector(Selector s) {
    this.selector = s;
    return this;
  }

  public JoinSequence setUseThetaStyle(boolean useThetaStyle) {
    this.useThetaStyle = useThetaStyle;
    return this;
  }

  public boolean isThetaStyle() {
    return useThetaStyle;
  }

  public int getJoinCount() {
    return joins.size();
  }
 
  public static interface Selector {
    public boolean includeSubclasses(String alias);
  }
}
TOP

Related Classes of org.hibernate.engine.JoinSequence

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.