Open Source Repository

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



org/hibernate/engine/JoinSequence.java
//$Id: JoinSequence.java 9336 2006-02-24 22:12:13Z steveebersole $
package org.hibernate.engine;

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

import org.hibernate.MappingException;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.collection.QueryableCollection;
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.appendrootJoinable )
          .append'[' )
          .appendrootAlias )
          .append']' );
    }
    for int i = 0; i < joins.size(); i++ ) {
      buf.append"->" ).appendjoins.get) );
    }
    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.getAssociatedJoinablefactory );
      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 JoinSequencefactory );
    fromPart.joins.addAllthis.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 JoinSequencefactory );
    copy.joins.addAllthis.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.appendthis.conditions.toString() );
    return copy;
  }

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

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

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

  public JoinFragment toJoinFragment(
      Map enabledFilters,
          boolean includeExtraJoins,
          String withClauseFragment,
          String withClauseJoinAliasthrows MappingException {
    QueryJoinFragment joinFragment = new QueryJoinFragmentfactory.getDialect(), useThetaStyle );
    if rootJoinable != null ) {
      joinFragment.addCrossJoinrootJoinable.getTableName(), rootAlias );
      String filterCondition = rootJoinable.filterFragmentrootAlias, 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.setHasFilterConditionjoinFragment.addConditionfilterCondition ) );
      if (includeExtraJoins) { //TODO: not quite sure about the full implications of this!
        addExtraJoinsjoinFragment, rootAlias, rootJoinable, true );
      }
    }

    Joinable last = rootJoinable;

    for int i = 0; i < joins.size(); i++ ) {
      Join join = Join joins.get);
      String on = join.getAssociationType().getOnConditionjoin.getAlias(), factory, enabledFilters );
      String condition = null;
      if last != null &&
              isManyToManyRootlast &&
              ( ( 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 )
                .getManyToManyFilterFragmentjoin.getAlias(), enabledFilters );
        condition = "".equalsmanyToManyFilter )
            ? on
            "".equalson )
                ? manyToManyFilter
                : on + " and " + manyToManyFilter;
      }
      else {
        condition = on;
      }
      if withClauseFragment != null ) {
        if join.getAlias().equalswithClauseJoinAlias ) ) {
          condition += " and " + withClauseFragment;
        }
      }
      joinFragment.addJoin(
              join.getJoinable().getTableName(),
          join.getAlias(),
          join.getLHSColumns(),
          JoinHelper.getRHSColumnNamesjoin.getAssociationType(), factory ),
          join.joinType,
          condition
      );
      if (includeExtraJoins) { //TODO: not quite sure about the full implications of this!
        addExtraJoinsjoinFragment, join.getAlias(), join.getJoinable(), join.joinType == JoinFragment.INNER_JOIN );
      }
      last = join.getJoinable();
    }
    if next != null ) {
      joinFragment.addFragmentnext.toJoinFragmentenabledFilters, includeExtraJoins ) );
    }
    joinFragment.addConditionconditions.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.includeSubclassesalias );
  }

  private void addExtraJoins(JoinFragment joinFragment, String alias, Joinable joinable, boolean innerJoin) {
    boolean include = isIncludedalias );
    joinFragment.addJoinsjoinable.fromJoinFragmentalias, innerJoin, include ),
        joinable.whereJoinFragmentalias, innerJoin, include ) );
  }

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

  public JoinSequence addCondition(String alias, String[] columns, String condition) {
    for int i = 0; i < columns.length; i++ ) {
      conditions.append" and " )
          .appendalias )
          .append'.' )
          .appendcolumns[i] )
          .appendcondition );
    }
    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);
  }
}