@Override
  public AssociationKey getAssociationKey() {
    final AssociationType type = getType();

    if (type.isAnyType()) {
      return new AssociationKey(
          JoinHelper.getLHSTableName(type, attributeNumber(), (OuterJoinLoadable) getSource()),
          JoinHelper.getLHSColumnNames(
              type, attributeNumber(), 0, (OuterJoinLoadable) getSource(), sessionFactory()));
    }

    final Joinable joinable = type.getAssociatedJoinable(sessionFactory());

    if (type.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT) {
      final String lhsTableName;
      final String[] lhsColumnNames;

      if (joinable.isCollection()) {
        final QueryableCollection collectionPersister = (QueryableCollection) joinable;
        lhsTableName = collectionPersister.getTableName();
        lhsColumnNames = collectionPersister.getElementColumnNames();
      } else {
        final OuterJoinLoadable entityPersister = (OuterJoinLoadable) source();
        lhsTableName = getLHSTableName(type, attributeNumber(), entityPersister);
        lhsColumnNames =
            getLHSColumnNames(type, attributeNumber(), entityPersister, sessionFactory());
      }
      return new AssociationKey(lhsTableName, lhsColumnNames);
    } else {
      return new AssociationKey(joinable.getTableName(), getRHSColumnNames(type, sessionFactory()));
    }
  }
 public OuterJoinableAssociation(
     PropertyPath propertyPath,
     AssociationType joinableType,
     String lhsAlias,
     String[] lhsColumns,
     String rhsAlias,
     JoinType joinType,
     String withClause,
     boolean hasRestriction,
     SessionFactoryImplementor factory,
     Map enabledFilters)
     throws MappingException {
   this.propertyPath = propertyPath;
   this.joinableType = joinableType;
   this.lhsAlias = lhsAlias;
   this.lhsColumns = lhsColumns;
   this.rhsAlias = rhsAlias;
   this.joinType = joinType;
   this.joinable = joinableType.getAssociatedJoinable(factory);
   this.rhsColumns = JoinHelper.getRHSColumnNames(joinableType, factory);
   this.on =
       joinableType.getOnCondition(rhsAlias, factory, enabledFilters)
           + (withClause == null || withClause.trim().length() == 0
               ? ""
               : " and ( " + withClause + " )");
   this.hasRestriction = hasRestriction;
   this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application
 }
 /** Used to detect circularities in the joined graph, note that this method is side-effecty */
 protected boolean isDuplicateAssociation(
     final String lhsTable, final String[] lhsColumnNames, final AssociationType type) {
   final String foreignKeyTable;
   final String[] foreignKeyColumns;
   if (type.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT) {
     foreignKeyTable = lhsTable;
     foreignKeyColumns = lhsColumnNames;
   } else {
     foreignKeyTable = type.getAssociatedJoinable(getFactory()).getTableName();
     foreignKeyColumns = JoinHelper.getRHSColumnNames(type, getFactory());
   }
   return isDuplicateAssociation(foreignKeyTable, foreignKeyColumns);
 }
  private CriteriaInfoProvider getPathInfo(String path) {
    StringTokenizer tokens = new StringTokenizer(path, ".");
    String componentPath = "";

    // start with the 'rootProvider'
    CriteriaInfoProvider provider = nameCriteriaInfoMap.get(rootEntityName);

    while (tokens.hasMoreTokens()) {
      componentPath += tokens.nextToken();
      Type type = provider.getType(componentPath);
      if (type.isAssociationType()) {
        // CollectionTypes are always also AssociationTypes - but there's not always an associated
        // entity...
        AssociationType atype = (AssociationType) type;
        CollectionType ctype = type.isCollectionType() ? (CollectionType) type : null;
        Type elementType = (ctype != null) ? ctype.getElementType(sessionFactory) : null;
        // is the association a collection of components or value-types? (i.e a colloction of valued
        // types?)
        if (ctype != null && elementType.isComponentType()) {
          provider =
              new ComponentCollectionCriteriaInfoProvider(
                  helper.getCollectionPersister(ctype.getRole()));
        } else if (ctype != null && !elementType.isEntityType()) {
          provider = new ScalarCollectionCriteriaInfoProvider(helper, ctype.getRole());
        } else {
          provider =
              new EntityCriteriaInfoProvider(
                  (Queryable)
                      sessionFactory.getEntityPersister(
                          atype.getAssociatedEntityName(sessionFactory)));
        }

        componentPath = "";
      } else if (type.isComponentType()) {
        if (!tokens.hasMoreTokens()) {
          throw new QueryException(
              "Criteria objects cannot be created directly on components.  Create a criteria on owning entity and use a dotted property to access component property: "
                  + path);
        } else {
          componentPath += '.';
        }
      } else {
        throw new QueryException("not an association: " + componentPath);
      }
    }

    return provider;
  }
 private boolean isOneToOne() {
   if (joinableType.isEntityType()) {
     EntityType etype = (EntityType) joinableType;
     return etype.isOneToOne() /*&& etype.isReferenceToPrimaryKey()*/;
   } else {
     return false;
   }
 }
 public String selectFragment(
     Joinable rhs,
     String rhsAlias,
     String lhsAlias,
     String entitySuffix,
     String collectionSuffix,
     boolean includeCollectionColumns) {
   // we need to determine the best way to know that two joinables
   // represent a single many-to-many...
   if (rhs != null && isManyToMany() && !rhs.isCollection()) {
     AssociationType elementType = ((AssociationType) getElementType());
     if (rhs.equals(elementType.getAssociatedJoinable(getFactory()))) {
       return manyToManySelectFragment(rhs, rhsAlias, lhsAlias, collectionSuffix);
     }
   }
   return includeCollectionColumns ? selectFragment(lhsAlias, collectionSuffix) : "";
 }
  protected void initPropertyPaths(
      final String path,
      final Type type,
      String[] columns,
      final String[] formulaTemplates,
      final Mapping factory)
      throws MappingException {

    if (columns.length != type.getColumnSpan(factory)) {
      throw new MappingException("broken column mapping for: " + path + " of: " + getEntityName());
    }

    if (type.isAssociationType()) {
      AssociationType actype = (AssociationType) type;
      if (actype.useLHSPrimaryKey()) {
        columns = getIdentifierColumnNames();
      } else {
        String foreignKeyProperty = actype.getLHSPropertyName();
        if (foreignKeyProperty != null && !path.equals(foreignKeyProperty)) {
          // TODO: this requires that the collection is defined after the
          //      referenced property in the mapping file (ok?)
          columns = (String[]) columnsByPropertyPath.get(foreignKeyProperty);
          if (columns == null) return; // get em on the second pass!
        }
      }
    }

    if (path != null) addPropertyPath(path, type, columns, formulaTemplates);

    if (type.isComponentType()) {
      AbstractComponentType actype = (AbstractComponentType) type;
      initComponentPropertyPaths(path, actype, columns, formulaTemplates, factory);
      if (actype.isEmbedded()) {
        initComponentPropertyPaths(
            path == null ? null : StringHelper.qualifier(path),
            actype,
            columns,
            formulaTemplates,
            factory);
      }
    } else if (type.isEntityType()) {
      initIdentifierPropertyPaths(path, (EntityType) type, columns, factory);
    }
  }
 /**
  * Does the mapping, and Hibernate default semantics, specify that this association should be
  * fetched by outer joining
  */
 protected boolean isJoinedFetchEnabledInMapping(FetchMode config, AssociationType type)
     throws MappingException {
   if (!type.isEntityType() && !type.isCollectionType()) {
     return false;
   } else {
     if (config == FetchMode.JOIN) return true;
     if (config == FetchMode.SELECT) return false;
     if (type.isEntityType()) {
       // TODO: look at the owning property and check that it
       //      isn't lazy (by instrumentation)
       EntityType entityType = (EntityType) type;
       EntityPersister persister =
           getFactory().getEntityPersister(entityType.getAssociatedEntityName());
       return !persister.hasProxy();
     } else {
       return false;
     }
   }
 }
 private String getPathEntityName(String path) {
   Queryable persister = (Queryable) sessionFactory.getEntityPersister(rootEntityName);
   StringTokenizer tokens = new StringTokenizer(path, ".");
   String componentPath = "";
   while (tokens.hasMoreTokens()) {
     componentPath += tokens.nextToken();
     Type type = persister.toType(componentPath);
     if (type.isAssociationType()) {
       AssociationType atype = (AssociationType) type;
       persister =
           (Queryable)
               sessionFactory.getEntityPersister(atype.getAssociatedEntityName(sessionFactory));
       componentPath = "";
     } else if (type.isComponentType()) {
       componentPath += '.';
     } else {
       throw new QueryException("not an association: " + componentPath);
     }
   }
   return persister.getEntityName();
 }
 protected void setRelatedClassType(
     GrailsHibernateDomainClassProperty prop, AssociationType assType, Type hibernateType) {
   try {
     String associatedEntity =
         assType.getAssociatedEntityName((SessionFactoryImplementor) getSessionFactory());
     ClassMetadata associatedMetaData = getSessionFactory().getClassMetadata(associatedEntity);
     prop.setRelatedClassType(associatedMetaData.getMappedClass(EntityMode.POJO));
   } catch (MappingException me) {
     // other side must be a value object
     if (hibernateType.isCollectionType()) {
       prop.setRelatedClassType(Collection.class);
     }
   }
 }
  /**
   * Add on association (one-to-one, many-to-one, or a collection) to a list of associations to be
   * fetched by outerjoin
   */
  private void addAssociationToJoinTree(
      final AssociationType type,
      final String[] aliasedLhsColumns,
      final String alias,
      final PropertyPath path,
      final int currentDepth,
      final JoinType joinType)
      throws MappingException {

    Joinable joinable = type.getAssociatedJoinable(getFactory());

    // important to generate alias based on size of association collection
    // *before* adding this join to that collection
    String subalias = generateTableAlias(associations.size() + 1, path, joinable);

    // NOTE : it should be fine to continue to pass only filters below
    // (instead of LoadQueryInfluencers) since "from that point on" we
    // only need to worry about restrictions (and not say adding more
    // joins)
    OuterJoinableAssociation assoc =
        new OuterJoinableAssociation(
            path,
            type,
            alias,
            aliasedLhsColumns,
            subalias,
            joinType,
            getWithClause(path),
            hasRestriction(path),
            getFactory(),
            loadQueryInfluencers.getEnabledFilters());
    assoc.validateJoin(path.getFullPath());
    associations.add(assoc);

    int nextDepth = currentDepth + 1;
    //		path = "";
    if (!joinable.isCollection()) {
      if (joinable instanceof OuterJoinLoadable) {
        walkEntityTree((OuterJoinLoadable) joinable, subalias, path, nextDepth);
      }
    } else {
      if (joinable instanceof QueryableCollection) {
        walkCollectionTree((QueryableCollection) joinable, subalias, path, nextDepth);
      }
    }
  }
 /**
  * Determine the appropriate associationType of join (if any) to use to fetch the given
  * association.
  *
  * @param associationType The association associationType.
  * @param config The metadata-defined fetch mode.
  * @param path The path to the association
  * @param lhsTable The owner table
  * @param lhsColumns The owner join columns
  * @param nullable Is the association nullable.
  * @param currentDepth Current join depth
  * @param cascadeStyle The metadata-defined cascade style.
  * @return type of join to use ({@link org.hibernate.sql.JoinType#INNER_JOIN}, {@link
  *     org.hibernate.sql.JoinType#LEFT_OUTER_JOIN}, or -1 to indicate no joining.
  * @throws MappingException ??
  */
 protected JoinType getJoinType(
     AssociationType associationType,
     FetchMode config,
     PropertyPath path,
     String lhsTable,
     String[] lhsColumns,
     boolean nullable,
     int currentDepth,
     CascadeStyle cascadeStyle)
     throws MappingException {
   if (!isJoinedFetchEnabled(associationType, config, cascadeStyle)) {
     return JoinType.NONE;
   }
   if (isTooDeep(currentDepth) || (associationType.isCollectionType() && isTooManyCollections())) {
     return JoinType.NONE;
   }
   if (isDuplicateAssociation(lhsTable, lhsColumns, associationType)) {
     return JoinType.NONE;
   }
   return getJoinType(nullable, currentDepth);
 }
// $Id: CascadeEntityJoinWalker.java,v 1.1 2005/07/26 05:51:47 oneovthafew Exp $
 public boolean isCollection() {
   return joinableType.isCollectionType();
 }
 public String getRHSUniqueKeyName() {
   return joinableType.getRHSUniqueKeyPropertyName();
 }
 /** Override on subclasses to enable or suppress joining of certain association types */
 protected boolean isJoinedFetchEnabled(
     AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
   return type.isEntityType() && isJoinedFetchEnabledInMapping(config, type);
 }
 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 Class getClassForAssociationType(AssociationType type) {
   String otherSideEntityName =
       type.getAssociatedEntityName((SessionFactoryImplementor) sessionFactory);
   return sessionFactory.getClassMetadata(otherSideEntityName).getMappedClass(EntityMode.POJO);
 }