// TODO we could cache such knowledge in a service if that turns out to be costly
  private String buildCollectionRole(OgmCollectionPersister collectionPersister) {
    String otherSidePropertyName = null;
    Loadable elementPersister = (Loadable) collectionPersister.getElementPersister();
    Type[] propertyTypes = elementPersister.getPropertyTypes();

    for (int index = 0; index < propertyTypes.length; index++) {
      Type type = propertyTypes[index];
      // we try and restrict type search as much as possible
      if (type.isAssociationType()) {
        boolean matching = false;
        // if the main side collection is a one-to-many, the reverse side should be a to-one is not
        // a collection
        if (collectionPersister.isOneToMany() && !type.isCollectionType()) {
          matching = isToOneMatching(elementPersister, index, type);
        }
        // if the main side collection is not a one-to-many, the reverse side should be a collection
        else if (!collectionPersister.isOneToMany() && type.isCollectionType()) {
          matching =
              isCollectionMatching((CollectionType) type, collectionPersister.getTableName());
        }
        if (matching) {
          otherSidePropertyName = elementPersister.getPropertyNames()[index];
          break;
        }
      }
    }
    return processOtherSidePropertyName(otherSidePropertyName);
  }
  private Queryable determineAppropriateOwnerPersister(NonScalarReturn ownerDescriptor) {
    String entityName = null;
    if (ownerDescriptor instanceof RootReturn) {
      entityName = ((RootReturn) ownerDescriptor).getEntityName();
    } else if (ownerDescriptor instanceof CollectionReturn) {
      CollectionReturn collRtn = (CollectionReturn) ownerDescriptor;
      String role = collRtn.getOwnerEntityName() + "." + collRtn.getOwnerProperty();
      CollectionPersister persister = getFactory().getCollectionPersister(role);
      EntityType ownerType = (EntityType) persister.getElementType();
      entityName = ownerType.getAssociatedEntityName(getFactory());
    } else if (ownerDescriptor instanceof FetchReturn) {
      FetchReturn fetchRtn = (FetchReturn) ownerDescriptor;
      Queryable persister = determineAppropriateOwnerPersister(fetchRtn.getOwner());
      Type ownerType = persister.getPropertyType(fetchRtn.getOwnerProperty());
      if (ownerType.isEntityType()) {
        entityName = ((EntityType) ownerType).getAssociatedEntityName(getFactory());
      } else if (ownerType.isCollectionType()) {
        Type ownerCollectionElementType = ((CollectionType) ownerType).getElementType(getFactory());
        if (ownerCollectionElementType.isEntityType()) {
          entityName =
              ((EntityType) ownerCollectionElementType).getAssociatedEntityName(getFactory());
        }
      }
    }

    if (entityName == null) {
      throw new HibernateException("Could not determine fetch owner : " + ownerDescriptor);
    }

    return (Queryable) getFactory().getEntityPersister(entityName);
  }
 private FromElement createCollectionJoin(JoinSequence collectionJoinSequence, String tableAlias)
     throws SemanticException {
   String text = queryableCollection.getTableName();
   AST ast = createFromElement(text);
   FromElement destination = (FromElement) ast;
   Type elementType = queryableCollection.getElementType();
   if (elementType.isCollectionType()) {
     throw new SemanticException("Collections of collections are not supported!");
   }
   destination.initializeCollection(fromClause, classAlias, tableAlias);
   destination.setType(JOIN_FRAGMENT); // Tag this node as a JOIN.
   destination.setIncludeSubclasses(false); // Don't include subclasses in the join.
   destination.setCollectionJoin(true); // This is a clollection join.
   destination.setJoinSequence(collectionJoinSequence);
   destination.setOrigin(origin, false);
   destination.setCollectionTableAlias(tableAlias);
   //		origin.addDestination( destination );
   // This was the cause of HHH-242
   //		origin.setType( FROM_FRAGMENT );			// Set the parent node type so that the AST is properly
   // formed.
   origin.setText(""); // The destination node will have all the FROM text.
   origin.setCollectionJoin(
       true); // The parent node is a collection join too (voodoo - see JoinProcessor)
   fromClause.addCollectionJoinFromElementByPath(path, destination);
   fromClause.getWalker().addQuerySpaces(queryableCollection.getCollectionSpaces());
   return destination;
 }
 private boolean indicatesCollection(Type type) {
   if (type.isCollectionType()) {
     return true;
   } else if (type.isComponentType()) {
     Type[] subtypes = ((CompositeType) type).getSubtypes();
     for (int i = 0; i < subtypes.length; i++) {
       if (indicatesCollection(subtypes[i])) {
         return true;
       }
     }
   }
   return false;
 }
 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);
     }
   }
 }
 // TODO we could cache such knowledge in a service if that turns out to be costly
 private String getCollectionRoleFromToOne(OgmEntityPersister associatedPersister) {
   // code logic is slightly duplicated but the input and context is different, hence this choice
   Type[] propertyTypes = associatedPersister.getPropertyTypes();
   String otherSidePropertyName = null;
   for (int index = 0; index < propertyTypes.length; index++) {
     Type type = propertyTypes[index];
     boolean matching = false;
     // we try and restrict type search as much as possible
     // we look for associations that also are collections
     if (type.isAssociationType() && type.isCollectionType()) {
       matching = isCollectionMatching((CollectionType) type, tableName);
     }
     // we look for associations that are to-one
     else if (type.isAssociationType()
         && !type.isCollectionType()) { // isCollectionType redundant but kept for readability
       matching = isToOneMatching(associatedPersister, index, type);
     }
     if (matching) {
       otherSidePropertyName = associatedPersister.getPropertyNames()[index];
       break;
     }
   }
   return processOtherSidePropertyName(otherSidePropertyName);
 }
  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;
  }
  public void end(QueryTranslatorImpl q) throws QueryException {
    ignoreInitialJoin = false;

    Type propertyType = getPropertyType();
    if (propertyType != null && propertyType.isCollectionType()) {
      collectionRole = ((CollectionType) propertyType).getRole();
      collectionName = q.createNameForCollection(collectionRole);
      prepareForIndex(q);
    } else {
      columns = currentColumns();
      setType();
    }

    // important!!
    continuation = false;
  }
  private static NonIdentifierAttributeNature decode(Type type) {
    if (type.isAssociationType()) {
      AssociationType associationType = (AssociationType) type;

      if (type.isComponentType()) {
        // an any type is both an association and a composite...
        return NonIdentifierAttributeNature.ANY;
      }

      return type.isCollectionType()
          ? NonIdentifierAttributeNature.COLLECTION
          : NonIdentifierAttributeNature.ENTITY;
    } else {
      if (type.isComponentType()) {
        return NonIdentifierAttributeNature.COMPOSITE;
      }

      return NonIdentifierAttributeNature.BASIC;
    }
  }
  private List<String> getCollectionRoles(
      final SessionFactory sessionFactory, final Class<?> entityClass) {
    List<String> collectionRoles = entityCollectionRoles.get(entityClass);
    if (collectionRoles != null) {
      return collectionRoles;
    }

    final com.google.common.collect.ImmutableList.Builder<String> collectionRolesBuilder =
        ImmutableList.builder();
    final ClassMetadata classMetadata = sessionFactory.getClassMetadata(entityClass);
    for (final Type type : classMetadata.getPropertyTypes()) {
      if (type.isCollectionType()) {
        collectionRolesBuilder.add(((CollectionType) type).getRole());
      }
    }

    collectionRoles = collectionRolesBuilder.build();
    entityCollectionRoles.put(entityClass, collectionRoles);

    return collectionRoles;
  }
  protected QueryableCollection getQueryableCollection(
      String entityName, String propertyName, SessionFactoryImplementor factory)
      throws HibernateException {
    PropertyMapping ownerMapping = (PropertyMapping) factory.getEntityPersister(entityName);
    Type type = ownerMapping.toType(propertyName);
    if (!type.isCollectionType()) {
      throw new MappingException(
          "Property path ["
              + entityName
              + "."
              + propertyName
              + "] does not reference a collection");
    }

    String role = ((CollectionType) type).getRole();
    try {
      return (QueryableCollection) factory.getCollectionPersister(role);
    } catch (ClassCastException cce) {
      throw new QueryException("collection role is not queryable: " + role);
    } catch (Exception e) {
      throw new QueryException("collection role not found: " + role);
    }
  }
  public void token(String token, QueryTranslatorImpl q) throws QueryException {

    if (token != null) path.append(token);

    String alias = q.getPathAlias(path.toString());
    if (alias != null) {
      reset(q); // reset the dotcount (but not the path)
      currentName = alias; // after reset!
      currentPropertyMapping = q.getPropertyMapping(currentName);
      if (!ignoreInitialJoin) {
        JoinSequence ojf = q.getPathJoin(path.toString());
        try {
          joinSequence.addCondition(
              ojf.toJoinFragment(q.getEnabledFilters(), true)
                  .toWhereFragmentString()); // after reset!
        } catch (MappingException me) {
          throw new QueryException(me);
        }
        // we don't need to worry about any condition in the ON clause
        // here (toFromFragmentString), since anything in the ON condition
        // is already applied to the whole query
      }
    } else if (".".equals(token)) {
      dotcount++;
    } else {
      if (dotcount == 0) {
        if (!continuation) {
          if (!q.isName(token)) throw new QueryException("undefined alias: " + token);
          currentName = token;
          currentPropertyMapping = q.getPropertyMapping(currentName);
        }
      } else if (dotcount == 1) {
        if (currentName != null) {
          currentProperty = token;
        } else if (collectionName != null) {
          // processCollectionProperty(token, q.getCollectionPersister(collectionRole),
          // collectionName);
          continuation = false;
        } else {
          throw new QueryException("unexpected");
        }
      } else { // dotcount>=2

        // Do the corresponding RHS
        Type propertyType = getPropertyType();

        if (propertyType == null) {
          throw new QueryException("unresolved property: " + path);
        }

        if (propertyType.isComponentType()) {
          dereferenceComponent(token);
        } else if (propertyType.isEntityType()) {
          if (!isCollectionValued()) dereferenceEntity(token, (EntityType) propertyType, q);
        } else if (propertyType.isCollectionType()) {
          dereferenceCollection(token, ((CollectionType) propertyType).getRole(), q);

        } else {
          if (token != null) throw new QueryException("dereferenced: " + path);
        }
      }
    }
  }