[hibernate-commits] Hibernate SVN: r16388 - in core/branches/antlr3/src/main/java/org/hibernate: sql/ast/phase/hql/resolve and 3 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Apr 21 14:29:41 EDT 2009


Author: steve.ebersole at jboss.com
Date: 2009-04-21 14:29:41 -0400 (Tue, 21 Apr 2009)
New Revision: 16388

Added:
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathResolutionStrategyStack.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/AbstractPathResolutionStrategy.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/AbstractUnexpectedPropertyTypeException.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/BasicPathResolutionStrategySupport.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/CollectionExpectedException.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/IndexedCollectionExectedException.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/InvalidPropertyJoinException.java
Modified:
   core/branches/antlr3/src/main/java/org/hibernate/QueryException.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/PersisterSpace.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/PersisterTableExpressionGenerator.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/ResolutionContext.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathResolutionStrategy.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathedPropertyReferenceSource.java
   core/branches/antlr3/src/main/java/org/hibernate/sql/ast/tree/Table.java
Log:
initial path resolution

Modified: core/branches/antlr3/src/main/java/org/hibernate/QueryException.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/QueryException.java	2009-04-21 18:19:38 UTC (rev 16387)
+++ core/branches/antlr3/src/main/java/org/hibernate/QueryException.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -32,9 +32,14 @@
 
 	private String queryString;
 
+	protected QueryException() {
+		super( "<expecting override of message building>" );
+	}
+
 	public QueryException(String message) {
 		super(message);
 	}
+
 	public QueryException(String message, Throwable e) {
 		super(message, e);
 	}
@@ -47,6 +52,7 @@
 	public QueryException(Exception e) {
 		super(e);
 	}
+
 	public String getQueryString() {
 		return queryString;
 	}
@@ -56,11 +62,16 @@
 	}
 
 	public String getMessage() {
-		String msg = super.getMessage();
-		if ( queryString!=null ) msg += " [" + queryString + ']';
+		String msg = internalGetMessage();
+		if ( queryString != null ) {
+			msg += " [" + queryString + ']';
+		}
 		return msg;
 	}
 
+	protected String internalGetMessage() {
+		return super.getMessage();
+	}
 }
 
 

Modified: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/PersisterSpace.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/PersisterSpace.java	2009-04-21 18:19:38 UTC (rev 16387)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/PersisterSpace.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -28,19 +28,41 @@
  */
 package org.hibernate.sql.ast.phase.hql.resolve;
 
-import java.util.List;
-
-import org.antlr.runtime.tree.Tree;
-
 import org.hibernate.type.Type;
+import org.hibernate.sql.ast.tree.Table;
 
 /**
  *
  * @author Steve Ebersole
  */
 public interface PersisterSpace {
-	public String getAlias();
-	public List<Tree> getTables();
+	/**
+	 * Retrieve the corresponding alias from the input (HQL, etc).
+	 *
+	 * @return The source alias.
+	 */
+	public String getSourceAlias();
 
+	/**
+	 * Retrieve the name of the underlying persister.
+	 *
+	 * @return The persister name.
+	 */
+	public String getName();
+
+	/**
+	 * Retrieve the short (unqualified) version of the persister name.
+	 * <p/>
+	 * Useful for alias basing.
+	 *
+	 * @return The persister short name.
+	 */
+	public String getShortName();
+
+	public Table.TableSpace getTableSpace();
+
 	public Type getPropertyType(String propertyName);
+
+	public Table locateReusablePropertyJoinedTable(String propertyName);
+	public void registerReusablePropertyJoinedTable(String propertyName, Table table);
 }

Modified: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/PersisterTableExpressionGenerator.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/PersisterTableExpressionGenerator.java	2009-04-21 18:19:38 UTC (rev 16387)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/PersisterTableExpressionGenerator.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -30,6 +30,7 @@
 package org.hibernate.sql.ast.phase.hql.resolve;
 
 import org.hibernate.persister.MappedTableMetadata;
+import org.hibernate.persister.collection.QueryableCollection;
 import org.hibernate.persister.entity.Queryable;
 import org.hibernate.sql.ast.alias.TableAliasGenerator;
 import org.hibernate.sql.ast.common.HibernateTree;
@@ -44,6 +45,7 @@
  * @author Steve Ebersole
  */
 public class PersisterTableExpressionGenerator {
+
 	public static Table generateTableExpression(
 			Queryable persister,
 			TableAliasGenerator.TableAliasRoot aliasRoot,
@@ -57,14 +59,13 @@
 
 		int suffix = 0;
 
-		MappedTableMetadata.JoinedTable[] tables = tableMetadata.getJoinedTables();
-		for ( int i = 0; i < tables.length; i++ ) {
+		for ( MappedTableMetadata.JoinedTable joinedTable : tableMetadata.getJoinedTables() ) {
 			final String joinTableAlias = aliasRoot.generate( ++suffix );
-			final Table table = generateTableReference( tables[i].getName(), joinTableAlias, tableSpace );
+			final Table table = generateTableReference( joinedTable.getName(), joinTableAlias, tableSpace );
 
 			final HibernateTree join = new HibernateTree( HQLParser.JOIN, "join" );
 			drivingTable.addChild( join );
-			if ( tables[i].useInnerJoin() ) {
+			if ( joinedTable.useInnerJoin() ) {
 				join.addChild( new HibernateTree( HQLParser.INNER, "inner" ) );
 			}
 			else {
@@ -78,7 +79,7 @@
 					drivingTableAlias,
 					drivingTableJoinColumns,
 					joinTableAlias,
-					tables[i].getKeyColumns()
+					joinedTable.getKeyColumns()
 			);
 			on.addChild( joinCondition );
 		}
@@ -86,6 +87,57 @@
 		return drivingTable;
 	}
 
+	public static Table generateTableExpression(
+			QueryableCollection collectionPersister,
+			TableAliasGenerator.TableAliasRoot aliasRoot,
+			Table.CollectionTableSpace tableSpace) {
+		if ( collectionPersister.isOneToMany() ) {
+			Table table = generateTableExpression(
+					( Queryable ) collectionPersister.getElementPersister(),
+					aliasRoot,
+					tableSpace.getEntityElementTableSpace()
+			);
+			tableSpace.setCollectionTable( table );
+			return table;
+		}
+		else {
+			Table associationTable = generateTableReference(
+					collectionPersister.getTableName(),
+					aliasRoot.generateCollectionTableAlias(),
+					tableSpace
+			);
+			tableSpace.setCollectionTable( associationTable );
+
+			if ( collectionPersister.isManyToMany() ) {
+				Queryable elementPersister = ( Queryable ) collectionPersister.getElementPersister();
+				Table drivingTable = generateTableExpression(
+						elementPersister,
+						aliasRoot,
+						tableSpace.getEntityElementTableSpace()
+				);
+
+				final HibernateTree join = new HibernateTree( HQLParser.JOIN );
+				associationTable.addChild( join );
+				join.addChild( new HibernateTree( HQLParser.LEFT, "left outer" ) );
+				join.addChild( drivingTable );
+
+				String[] entityFkColumnNames = collectionPersister.getElementColumnNames();
+				String[] entityPkColumnNames = elementPersister.getKeyColumnNames();
+
+				final HibernateTree on = new HibernateTree( HQLParser.ON );
+				join.addChild( on );
+				final HibernateTree joinCondition = generateJoinCorrelation(
+						associationTable.getAliasText(),
+						entityFkColumnNames,
+						drivingTable.getAliasText(),
+						entityPkColumnNames
+				);
+				on.addChild( joinCondition );
+			}
+			return associationTable;
+		}
+	}
+
 	private static Table generateTableReference(String tableName, String tableAlias, Table.TableSpace tableSpace) {
 		Table table = new Table( HQLParser.TABLE, tableSpace );
 		table.addChild( new HibernateTree( HQLParser.IDENTIFIER, tableName ) );

Modified: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/ResolutionContext.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/ResolutionContext.java	2009-04-21 18:19:38 UTC (rev 16387)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/ResolutionContext.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -32,7 +32,7 @@
 import org.antlr.runtime.tree.TreeAdaptor;
 
 import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.sql.ast.alias.ImplicitAliasGenerator;
+import org.hibernate.sql.ast.alias.TableAliasGenerator;
 import org.hibernate.sql.ast.util.TreePrinter;
 import org.hibernate.sql.ast.phase.hql.resolve.path.PathResolutionStrategy;
 
@@ -52,13 +52,6 @@
 
 	public TreeAdaptor getTreeAdaptor();
 
-//	/**
-//	 * The alias builder available in this context.
-//	 *
-//	 * @return The alias builder.
-//	 */
-//	public ImplicitAliasGenerator getAliasBuilder();
-
 	/**
 	 * The current {@link PersisterSpaceContext} for this context.  The {@link PersisterSpaceContext}
 	 * can change in relation to subqueries and such.  See {@link PersisterSpaceContext} docs for more info.
@@ -88,6 +81,8 @@
 	 */
 	public TreePrinter getTreePrinter();
 
+	public TableAliasGenerator getTableAliasGenerator();
+
 	/**
 	 * Is this context currently processing a function?
 	 *
@@ -97,7 +92,7 @@
 
 	public PathResolutionStrategy getCurrentPathResolutionStrategy();
 
-//	public void registerAssociationFetch(Join join);
-//
-//	public void registerPropertyFetch(PersisterReference persisterReference);
+	public void registerAssociationFetch(PersisterSpace persisterSpace);
+
+	public void registerPropertyFetch(PersisterSpace persisterSpace);
 }

Modified: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathResolutionStrategy.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathResolutionStrategy.java	2009-04-21 18:19:38 UTC (rev 16387)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathResolutionStrategy.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -30,7 +30,6 @@
 package org.hibernate.sql.ast.phase.hql.resolve.path;
 
 import org.hibernate.sql.ast.phase.hql.resolve.PersisterSpace;
-import org.hibernate.sql.ast.phase.hql.resolve.PropertyPathTerminus;
 import org.hibernate.sql.ast.common.HibernateTree;
 
 /**
@@ -67,7 +66,7 @@
 	 *
 	 * @return The terminal property reference indicated by the overall path.
 	 */
-	public PropertyPathTerminus handleTerminalPathPart(PathedPropertyReferenceSource source, String pathPart);
+	public HibernateTree handleTerminalPathPart(PathedPropertyReferenceSource source, String pathPart);
 
 	/**
 	 * Handle an index access operation (a.b[selector] for example).  In this particular case the index access
@@ -91,5 +90,5 @@
 	 *
 	 * @return The terminal property reference indicated by the overall path.
 	 */
-	public PropertyPathTerminus handleTerminalIndexAccess(PathedPropertyReferenceSource source, String pathPart, HibernateTree selector);
+	public HibernateTree handleTerminalIndexAccess(PathedPropertyReferenceSource source, String pathPart, HibernateTree selector);
 }

Added: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathResolutionStrategyStack.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathResolutionStrategyStack.java	                        (rev 0)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathResolutionStrategyStack.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -0,0 +1,53 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, 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.sql.ast.phase.hql.resolve.path;
+
+import java.util.LinkedList;
+
+/**
+ * Provides a stack of {@link PathResolutionStrategy} instances.
+ *
+ * @author Steve Ebersole
+ */
+public class PathResolutionStrategyStack {
+	private LinkedList<PathResolutionStrategy> stack = new LinkedList<PathResolutionStrategy>();
+
+	public void push(PathResolutionStrategy handler) {
+		stack.addFirst( handler );
+	}
+
+	public PathResolutionStrategy pop() {
+		return stack.removeFirst();
+	}
+
+	public PathResolutionStrategy getCurrent() {
+		return stack.getFirst();
+	}
+}

Modified: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathedPropertyReferenceSource.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathedPropertyReferenceSource.java	2009-04-21 18:19:38 UTC (rev 16387)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/PathedPropertyReferenceSource.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -26,13 +26,11 @@
  * 51 Franklin Street, Fifth Floor
  * Boston, MA  02110-1301  USA
  */
-
 package org.hibernate.sql.ast.phase.hql.resolve.path;
 
 import org.antlr.runtime.tree.Tree;
 
 import org.hibernate.sql.ast.common.HibernateTree;
-import org.hibernate.sql.ast.phase.hql.resolve.PropertyPathTerminus;
 
 /**
  * The contract for representing the non-terminal parts of a property path expression
@@ -66,7 +64,7 @@
 	 *
 	 * @return The property reference terminus.
 	 */
-	public PropertyPathTerminus handleTerminalPathPart(String name);
+	public HibernateTree handleTerminalPathPart(String name);
 
 	/**
 	 * Handle an index access operation (a.b[selector] for example).  In this particular case the index access
@@ -88,5 +86,5 @@
 	 *
 	 * @return The property reference terminus.
 	 */
-	public PropertyPathTerminus handleTerminalIndexAccess(String collectionPropertyName, HibernateTree selector);
+	public HibernateTree handleTerminalIndexAccess(String collectionPropertyName, HibernateTree selector);
 }

Added: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/AbstractPathResolutionStrategy.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/AbstractPathResolutionStrategy.java	                        (rev 0)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/AbstractPathResolutionStrategy.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -0,0 +1,595 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, 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.sql.ast.phase.hql.resolve.path.impl;
+
+import org.antlr.runtime.Token;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.ast.alias.TableAliasGenerator;
+import org.hibernate.sql.ast.common.HibernateToken;
+import org.hibernate.sql.ast.common.HibernateTree;
+import org.hibernate.sql.ast.phase.hql.parse.HQLParser;
+import org.hibernate.sql.ast.phase.hql.resolve.PersisterSpace;
+import org.hibernate.sql.ast.phase.hql.resolve.PersisterTableExpressionGenerator;
+import org.hibernate.sql.ast.phase.hql.resolve.ResolutionContext;
+import org.hibernate.sql.ast.phase.hql.resolve.path.PathResolutionStrategy;
+import org.hibernate.sql.ast.phase.hql.resolve.path.PathedPropertyReferenceSource;
+import org.hibernate.sql.ast.tree.Table;
+import org.hibernate.sql.ast.util.DisplayableNode;
+import org.hibernate.sql.ast.util.TreePrinter;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.ComponentType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+
+/**
+ * Abstract implementation of {@link PathResolutionStrategy} providing convenience methods to actual
+ * {@link PathResolutionStrategy} implementors.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractPathResolutionStrategy implements PathResolutionStrategy {
+	private static final Logger log = LoggerFactory.getLogger( AbstractPathResolutionStrategy.class );
+
+	private final ResolutionContext resolutionContext;
+	private String pathThusFar = null;
+
+	protected AbstractPathResolutionStrategy(ResolutionContext resolutionContext) {
+		this.resolutionContext = resolutionContext;
+	}
+
+	// reolution context ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Getter for property 'resolutionContext'.
+	 *
+	 * @return Value for property 'resolutionContext'.
+	 */
+	protected ResolutionContext resolutionContext() {
+		return resolutionContext;
+	}
+
+	protected final HibernateTree createNode(int type, String text) {
+		return ( HibernateTree ) resolutionContext().getTreeAdaptor().create( type, text );
+	}
+
+	/**
+	 * Getter for property 'sessionFactoryImplementor'.
+	 *
+	 * @return Value for property 'sessionFactoryImplementor'.
+	 */
+	protected final SessionFactoryImplementor getSessionFactoryImplementor() {
+		return resolutionContext().getSessionFactoryImplementor();
+	}
+
+	/**
+	 * Getter for property 'ASTPrinter'.
+	 *
+	 * @return Value for property 'ASTPrinter'.
+	 */
+	protected final TreePrinter getTreePrinter() {
+		return resolutionContext().getTreePrinter();
+	}
+
+
+	// path ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	protected void initializePathSoFar(String root) {
+		pathThusFar = root;
+	}
+
+	/**
+	 * Getter for property 'pathThusFar'.
+	 *
+	 * @return Value for property 'pathThusFar'.
+	 */
+	public String getPathThusFar() {
+		return pathThusFar;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public final PathedPropertyReferenceSource handleRoot(PersisterSpace persisterSpace) {
+		initializePathSoFar( persisterSpace.getSourceAlias() );
+		log.trace( "handling root path source [" + pathThusFar + "]" );
+		return internalHandleRoot( persisterSpace );
+	}
+
+	/**
+	 * Hook for subclasses to process the path root.
+	 *
+	 * @param persisterSpace The persister defining the source root.
+	 * @return The appropriate property path source implementation.
+	 */
+	protected abstract PathedPropertyReferenceSource internalHandleRoot(PersisterSpace persisterSpace);
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public final PathedPropertyReferenceSource handleIntermediatePathPart(PathedPropertyReferenceSource source, String pathPart) {
+		pathThusFar = ( pathThusFar == null ) ? pathPart : pathThusFar + "." + pathPart;
+		log.trace( "handling intermediate path source [" + pathThusFar + "]" );
+		return internalResolveIntermediatePathPart( source, pathPart );
+	}
+
+	/**
+	 * Hook for subclasses to process an intermediate part of the path.
+	 *
+	 * @param source The source from which pathPart originates.
+	 * @param pathPart The name of the path part to be processed.
+	 * @return The appropriate property path source implementation.
+	 */
+	protected PathedPropertyReferenceSource internalResolveIntermediatePathPart(PathedPropertyReferenceSource source, String pathPart) {
+		return source.handleIntermediatePathPart( pathPart );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public final HibernateTree handleTerminalPathPart(PathedPropertyReferenceSource source, String pathPart) {
+		pathThusFar = ( pathThusFar == null ) ? pathPart : pathThusFar + "." + pathPart;
+		log.trace( "handling terminal path part [" + pathThusFar + "]" );
+		try {
+			return internalResolveTerminalPathPart( source, pathPart );
+		}
+		finally {
+			pathThusFar = null;
+		}
+	}
+
+	/**
+	 * Hook for subclasses to process the terminal (or ending) part of a path.
+	 *
+	 * @param source The source from which pathPart originates.
+	 * @param pathPart The name of the path part to be processed.
+	 * @return a node representing the normalized property path.
+	 */
+	protected HibernateTree internalResolveTerminalPathPart(PathedPropertyReferenceSource source, String pathPart) {
+		return source.handleTerminalPathPart( pathPart );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public final PathedPropertyReferenceSource handleIntermediateIndexAccess(PathedPropertyReferenceSource source, String pathPart, HibernateTree selector) {
+		pathThusFar = ( ( pathThusFar == null ) ? pathPart : pathThusFar + "." + pathPart ) + "[]";
+		log.trace( "handling intermediate index access [" + pathThusFar + "]" );
+		try {
+			return internalHandleIntermediateIndexAccess( source, pathPart, selector );
+		}
+		finally {
+			pathThusFar = null;
+		}
+	}
+
+	/**
+	 * Hook for subclasses to process an index access as an intermediate property path.
+	 *
+	 * @param source The source from which pathPart originates.
+	 * @param pathPart The name of the path part to be processed.
+	 * @param selector The index selector to be appliedto the indexed collection
+	 *
+	 * @return The appropriate property path source implementation.
+	 */
+	protected PathedPropertyReferenceSource internalHandleIntermediateIndexAccess(PathedPropertyReferenceSource source, String pathPart, HibernateTree selector) {
+		return source.handleIntermediateIndexAccess( pathPart, selector );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public final HibernateTree handleTerminalIndexAccess(PathedPropertyReferenceSource source, String pathPart, HibernateTree selector) {
+		pathThusFar = ( ( pathThusFar == null ) ? pathPart : pathThusFar + "." + pathPart ) + "[]";
+		log.trace( "handling terminal index access [" + pathThusFar + "]" );
+		try {
+			return internalHandleTerminalIndexAccess( source, pathPart, selector );
+		}
+		finally {
+			pathThusFar = null;
+		}
+	}
+
+	/**
+	 * Hook for subclasses to process an index access as the terminus of a property path.
+	 *
+	 * @param source The source from which pathPart originates.
+	 * @param pathPart The name of the path part to be processed.
+	 * @param selector The index selector to be appliedto the indexed collection
+	 *
+	 * @return a node representing the normalized property path.
+	 */
+	protected HibernateTree internalHandleTerminalIndexAccess(PathedPropertyReferenceSource source, String pathPart, HibernateTree selector) {
+		return source.handleTerminalIndexAccess( pathPart, selector );
+	}
+
+	/**
+	 * Convenience method to locate the index of a component sub-property.  The returned index is relative to
+	 * {@link ComponentType#getPropertyNames}.
+	 *
+	 * @param componentType The component type mapping.
+	 * @param subPropertyName The sub-property name.
+	 * @return The index.
+	 */
+	protected static int locateComponentPropertyIndex(ComponentType componentType, String subPropertyName) {
+		String[] componentPropertyNames = componentType.getPropertyNames();
+		for ( int i = 0; i < componentPropertyNames.length; i++ ) {
+			if ( componentPropertyNames[i].equals( subPropertyName ) ) {
+				return i;
+			}
+		}
+		throw new QueryException( "could not locate component property [" + subPropertyName + "]" );
+	}
+
+	/**
+	 * Hook to allow subclasses to disallow implicit join.
+	 *
+	 * @param origin The persister-reference which is the origin of the property
+	 * @param property The property resulting in a join.
+	 */
+	protected void validateJoinCreation(PersisterSpace origin, String property) {
+		log.debug( "creating path expression implied join [" + origin.getSourceAlias() + "].[" + property + "]" );
+	}
+
+	/**
+	 * Hook to allow subclasses to define the type of join to use for an implciit join.
+	 * <p/>
+	 * The default is to use an {@link HQLParser#INNER} join.
+	 *
+	 * @return The join type node.
+	 */
+	protected HibernateTree buildJoinTypeNode() {
+		return createNode( HQLParser.INNER, "inner" );
+	}
+
+	/**
+	 * Does this strategy allows property joins to be reused?
+	 *
+	 * @return True/false.
+	 */
+	protected boolean areJoinsReusable() {
+		return true;
+	}
+
+	/**
+	 * Locate (if property joins are reusable) or build an appropriate joined table.
+	 *
+	 * @param lhs The join lhs, which is the origin of the property.
+	 * @param propertyName The name of the property
+	 * @param alias The alias, if any, to apply to the generated RHS persister reference.
+	 * @param propertyFetching Should property fetching be applied to the generated RHS?
+	 * @param associationFetching Did this property join specify association fetching (join fetch)?
+	 * @return The appropriate join.
+	 */
+	protected final Table locateOrBuildPropertyJoinedTable(
+			PersisterSpace lhs,
+			String propertyName,
+			String alias,
+			boolean propertyFetching,
+			boolean associationFetching) {
+		Table joinedTable = null;
+		if ( areJoinsReusable() ) {
+			joinedTable = lhs.locateReusablePropertyJoinedTable( propertyName );
+		}
+
+		if ( joinedTable == null ) {
+			joinedTable = buildPropertyJoinedTable( lhs, propertyName, alias, propertyFetching, associationFetching );
+			if ( areJoinsReusable() ) {
+				lhs.registerReusablePropertyJoinedTable( propertyName, joinedTable );
+			}
+		}
+
+		return joinedTable;
+	}
+
+	/**
+	 * Build a property joined table
+	 *
+	 * @param lhs The join's left-hand-side persister-reference
+	 * @param propertyName The property name.
+	 * @param alias The alias to apply to the rhs of the join
+	 * @param propertyFetching should property fetching be applied to the joined persister?
+	 * @param associationFetching Should the association making up the property join also be fetched?
+	 *
+	 * @return The right-hand-side persister-reference.
+	 */
+	protected Table buildPropertyJoinedTable(
+			PersisterSpace lhs,
+			String propertyName,
+			String alias,
+			boolean propertyFetching,
+			boolean associationFetching) {
+		validateJoinCreation( lhs, propertyName );
+		Table joinedTable;
+		Type propertyType = lhs.getPropertyType( propertyName );
+		if ( propertyType.isEntityType() ) {
+			EntityType entityType = ( EntityType ) propertyType;
+			Queryable entityPersister = ( Queryable ) getSessionFactoryImplementor()
+					.getEntityPersister( entityType.getAssociatedEntityName( getSessionFactoryImplementor() ) );
+			joinedTable = createJoin( lhs, entityPersister, alias );
+		}
+		else if ( propertyType.isCollectionType() ) {
+			CollectionType collectionType = ( CollectionType ) propertyType;
+			QueryableCollection collectionPersister = ( QueryableCollection ) getSessionFactoryImplementor()
+					.getCollectionPersister( collectionType.getRole() );
+			joinedTable = createJoin( lhs, collectionPersister, alias, null );
+		}
+		else {
+			throw new InvalidPropertyJoinException( getPathThusFar(), lhs.getName(), propertyName );
+		}
+
+		if ( propertyFetching ) {
+			resolutionContext().registerPropertyFetch( joinedTable.getTableSpace().getPersisterSpace() );
+		}
+		if ( associationFetching ) {
+			resolutionContext.registerAssociationFetch( joinedTable.getTableSpace().getPersisterSpace() );
+		}
+
+		return joinedTable;
+	}
+
+	/**
+	 * Generate a column list (tree w/ token type {@link HQLParser#COLUMN_LIST} for the columns making up the given
+	 * property.
+	 *
+	 * @param origin The persister-space from which the property originates.
+	 * @param propertyName The name of the property being referenced.
+	 *
+	 * @return The column list.
+	 */
+	protected final HibernateTree generatePropertyColumnList(PersisterSpace origin, String propertyName) {
+		HibernateTree columnList = new HibernateTree( HQLParser.COLUMN_LIST );
+		Table containingTable = origin.getTableSpace().getContainingTable( propertyName );
+		for ( String columnName : origin.getTableSpace().getPropertyColumnNames( propertyName ) ) {
+			final HibernateTree column = new HibernateTree( HQLParser.COLUMN );
+			columnList.addChild( column );
+			column.addChild( new HibernateTree( HQLParser.ALIAS_REF, containingTable.getAliasText() ) );
+			column.addChild( new HibernateTree( HQLParser.IDENTIFIER, columnName ) );
+		}
+		return columnList;
+	}
+
+
+	// source impl support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public abstract class AbstractPathedPropertyReferenceSource
+			extends HibernateTree
+			implements PathedPropertyReferenceSource, DisplayableNode {
+		private final String originationPath;
+
+		/**
+		 * Constructs a new AbstractPathedPropertyReferenceSource.
+		 */
+		protected AbstractPathedPropertyReferenceSource() {
+			this( getPathThusFar() );
+		}
+
+		protected AbstractPathedPropertyReferenceSource(Token token) {
+			this( token, getPathThusFar() );
+		}
+
+		protected AbstractPathedPropertyReferenceSource(String originationPath) {
+			super( new HibernateToken( HQLParser.IDENTIFIER, originationPath ) );
+			this.originationPath = originationPath;
+		}
+
+		protected AbstractPathedPropertyReferenceSource(Token token, String originationPath) {
+			super( token );
+			this.originationPath = originationPath;
+		}
+
+		public HibernateTree handleTerminalIndexAccess(PersisterSpace lhs, String collectionPropertyName, HibernateTree selector) {
+			Table joinedCollectionTable = createIndexAccessJoin( lhs, collectionPropertyName, selector );
+
+			// in general we need the collection element column list
+			QueryableCollection collectionPersister = resolveCollectionPersister( lhs, collectionPropertyName );
+			HibernateTree columnList = new HibernateTree( HQLParser.COLUMN_LIST );
+			for ( String columnName : collectionPersister.getElementColumnNames() ) {
+				final HibernateTree column = new HibernateTree( HQLParser.COLUMN );
+				column.addChild( new HibernateTree( HQLParser.ALIAS_REF, joinedCollectionTable.getAliasText() ) );
+				column.addChild( new HibernateTree( HQLParser.IDENTIFIER, columnName ) );
+			}
+			return columnList;
+		}
+
+		protected Table createIndexAccessJoin(PersisterSpace lhs, String collectionPropertyName, HibernateTree selector) {
+			validateIndexedCollectionReference( lhs, collectionPropertyName );
+
+			QueryableCollection collectionPersister = resolveCollectionPersister( lhs, collectionPropertyName );
+			HibernateTree join = createJoin( lhs, collectionPersister, null, selector );
+
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						resolutionContext().getTreePrinter().renderAsString(
+								join,
+								"implicit join : " + lhs.getSourceAlias() + "." + collectionPropertyName + "[]"
+						)
+				);
+			}
+
+			return ( Table ) join.getChild( 1 );
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public String getOriginationPath() {
+			return originationPath;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public final String getDisplayText() {
+				return " ADPATER : SHOULD NEVER END UP IN TREE!";
+		}
+	}
+
+	protected Table createJoin(PersisterSpace lhs, Queryable entityPersister, String alias) {
+		EntityType entityType = entityPersister.getEntityMetamodel().getEntityType();
+
+		Table.EntityTableSpace tableSpace = new Table.EntityTableSpace( entityPersister, alias );
+		TableAliasGenerator.TableAliasRoot tableAliasRoot = resolutionContext().getTableAliasGenerator()
+				.generateSqlAliasRoot( entityPersister, alias );
+
+		Table joinedTableExpression = PersisterTableExpressionGenerator.generateTableExpression(
+				entityPersister,
+				tableAliasRoot,
+				tableSpace
+		);
+
+		HibernateTree join = new HibernateTree( HQLParser.JOIN );
+		join.addChild( buildJoinTypeNode() );
+		join.addChild( joinedTableExpression );
+
+		HibernateTree joinCondition;
+		final String lhsJoinProperty = entityType.getLHSPropertyName();
+		if ( lhsJoinProperty == null ) {
+			// join using the lhs PK
+			joinCondition = PersisterTableExpressionGenerator.generateJoinCorrelation(
+					lhs.getTableSpace().getJoinIntoTable().getAliasText(),
+					lhs.getTableSpace().getJoinIntoColumns(),
+					joinedTableExpression.getAliasText(),
+					entityPersister.getKeyColumnNames()
+			);
+		}
+		else {
+			// join using the columns to which the given lhs property is mapped
+			joinCondition = PersisterTableExpressionGenerator.generateJoinCorrelation(
+					lhs.getTableSpace().getContainingTable( lhsJoinProperty ).getAliasText(),
+					lhs.getTableSpace().getPropertyColumnNames( lhsJoinProperty ),
+					joinedTableExpression.getAliasText(),
+					entityPersister.getKeyColumnNames()
+			);
+		}
+
+		HibernateTree on = new HibernateTree( HQLParser.ON );
+		join.addChild( on );
+		on.addChild( joinCondition );
+
+		return joinedTableExpression;
+	}
+
+	protected Table createJoin(PersisterSpace lhs, QueryableCollection collectionPersister, String sourceAlias, HibernateTree extraJoinConditions) {
+		CollectionType collectionType = collectionPersister.getCollectionType();
+
+		Table.CollectionTableSpace tableSpace = new Table.CollectionTableSpace( collectionPersister, sourceAlias );
+		TableAliasGenerator.TableAliasRoot tableAliasRoot = resolutionContext().getTableAliasGenerator()
+				.generateSqlAliasRoot( collectionPersister, sourceAlias );
+
+		Table collectionTableExpression = PersisterTableExpressionGenerator.generateTableExpression(
+				collectionPersister,
+				tableAliasRoot,
+				tableSpace
+		);
+
+		HibernateTree joinNode = new HibernateTree( HQLParser.JOIN );
+		joinNode.addChild( buildJoinTypeNode() );
+		joinNode.addChild( collectionTableExpression );
+
+		HibernateTree joinCondition;
+		final String lhsJoinProperty = collectionType.getLHSPropertyName();
+		if ( lhsJoinProperty == null ) {
+			// join using the lhs PK
+			joinCondition = PersisterTableExpressionGenerator.generateJoinCorrelation(
+					lhs.getTableSpace().getJoinIntoTable().getAliasText(),
+					lhs.getTableSpace().getJoinIntoColumns(),
+					collectionTableExpression.getAliasText(),
+					collectionPersister.getKeyColumnNames()
+			);
+		}
+		else {
+			// join using the columns to which the given lhs property is mapped
+			joinCondition = PersisterTableExpressionGenerator.generateJoinCorrelation(
+					lhs.getTableSpace().getContainingTable( lhsJoinProperty ).getAliasText(),
+					lhs.getTableSpace().getPropertyColumnNames( lhsJoinProperty ),
+					collectionTableExpression.getAliasText(),
+					collectionPersister.getKeyColumnNames()
+			);
+		}
+
+		if ( extraJoinConditions != null ) {
+			HibernateTree mappedJoinCondition = joinCondition;
+			joinCondition = new HibernateTree( HQLParser.AND );
+			joinCondition.addChild( mappedJoinCondition );
+			joinCondition.addChild( extraJoinConditions );
+		}
+
+		HibernateTree on = new HibernateTree( HQLParser.ON );
+		joinNode.addChild( on );
+		on.addChild( joinCondition );
+
+		return collectionTableExpression;
+	}
+
+	protected void validateCollectionReference(PersisterSpace lhs, String propertyName) {
+		if ( ! isCollectionReference( lhs.getPropertyType( propertyName ) ) ) {
+			throw new CollectionExpectedException( getPathThusFar(), lhs.getName(), propertyName );
+		}
+	}
+
+	private boolean isCollectionReference(Type propertyType) {
+		return propertyType.isCollectionType();
+	}
+
+	protected void validateIndexedCollectionReference(PersisterSpace lhs, String propertyName) {
+		if ( ! isIndexedCollectionReference( lhs.getPropertyType( propertyName ) ) ) {
+			throw new IndexedCollectionExectedException( getPathThusFar(), lhs.getName(), propertyName );
+		}
+	}
+
+	private boolean isIndexedCollectionReference(Type propertyType) {
+		return isCollectionReference( propertyType )
+				&& resolveCollectionPersister( ( CollectionType ) propertyType ).hasIndex();
+	}
+
+	protected QueryableCollection resolveCollectionPersister(PersisterSpace lhs, String propertyName) {
+		return resolveCollectionPersister( ( CollectionType ) lhs.getPropertyType( propertyName ) );
+	}
+
+	protected QueryableCollection resolveCollectionPersister(CollectionType collectionType) {
+		return ( QueryableCollection ) getSessionFactoryImplementor().getCollectionPersister( collectionType.getRole() );
+	}
+
+	protected Queryable resolveEntityPersister(PersisterSpace lhs, String propertyName) {
+		return resolveEntityPersister( ( EntityType ) lhs.getPropertyType( propertyName ) );
+	}
+
+	protected Queryable resolveEntityPersister(EntityType entityType) {
+		return ( Queryable ) getSessionFactoryImplementor().getEntityPersister(
+				entityType.getAssociatedEntityName( getSessionFactoryImplementor() )
+		);
+	}
+}

Added: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/AbstractUnexpectedPropertyTypeException.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/AbstractUnexpectedPropertyTypeException.java	                        (rev 0)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/AbstractUnexpectedPropertyTypeException.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -0,0 +1,71 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, 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.sql.ast.phase.hql.resolve.path.impl;
+
+import org.hibernate.QueryException;
+
+/**
+ * todo : javadocs
+ *
+ * @author Steve Ebersole
+ */
+public class AbstractUnexpectedPropertyTypeException extends QueryException {
+	private final String path;
+	private final String persisterName;
+	private final String propertyName;
+
+	public AbstractUnexpectedPropertyTypeException(String path, String persisterName, String propertyName) {
+		super();
+		this.path = path;
+		this.persisterName = persisterName;
+		this.propertyName = propertyName;
+	}
+
+	@Override
+	protected String internalGetMessage() {
+		return "Referenced property [" + buildPropertyReferenceFragment() + "] was not of expected type";
+	}
+
+	protected String buildPropertyReferenceFragment() {
+		return path + " (" + persisterName + ")." + propertyName;
+	}
+
+	public String getPath() {
+		return path;
+	}
+
+	public String getPersisterName() {
+		return persisterName;
+	}
+
+	public String getPropertyName() {
+		return propertyName;
+	}
+}

Added: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/BasicPathResolutionStrategySupport.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/BasicPathResolutionStrategySupport.java	                        (rev 0)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/BasicPathResolutionStrategySupport.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -0,0 +1,334 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, 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.sql.ast.phase.hql.resolve.path.impl;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.hql.CollectionProperties;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.sql.ast.common.HibernateTree;
+import org.hibernate.sql.ast.phase.hql.resolve.PersisterSpace;
+import org.hibernate.sql.ast.phase.hql.resolve.PropertyPathTerminus;
+import org.hibernate.sql.ast.phase.hql.resolve.ResolutionContext;
+import org.hibernate.sql.ast.phase.hql.resolve.path.PathedPropertyReferenceSource;
+import org.hibernate.sql.ast.tree.Table;
+import org.hibernate.type.ComponentType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+
+/**
+ * todo : javadocs
+ *
+ * @author Steve Ebersole
+ */
+public class BasicPathResolutionStrategySupport extends AbstractPathResolutionStrategy {
+	private static final Logger log = LoggerFactory.getLogger( BasicPathResolutionStrategySupport.class );
+
+
+	public BasicPathResolutionStrategySupport(ResolutionContext resolutionContext) {
+		super( resolutionContext );
+	}
+
+	protected PathedPropertyReferenceSource internalHandleRoot(PersisterSpace persisterSpace) {
+		return new RootSourceImpl( persisterSpace );
+	}
+
+	private PathedPropertyReferenceSource determineAppropriateIntermediateSourceType(PersisterSpace origin, String propertyName) {
+		final Type propertyType = origin.getPropertyType( propertyName );
+		if ( propertyType.isComponentType() ) {
+			return new ComponentIntermediatePathSource( origin, propertyName, ( ComponentType ) propertyType );
+		}
+		else if ( propertyType.isEntityType() ) {
+			return new EntityIntermediatePathSource( origin, propertyName );
+		}
+		else if ( propertyType.isCollectionType() ) {
+			return new CollectionIntermediatePathSource( origin, propertyName );
+		}
+		else {
+			return new SimpleIntermediatePathSource();
+		}
+	}
+
+	/**
+	 * Is the given property name a reference to the primary key of the associated
+	 * entity construed by the given entity type?
+	 * <p/>
+	 * For example, consider a fragment like order.customer.id
+	 * (where order is a from-element alias).  Here, we'd have:
+	 * propertyName = "id" AND
+	 * owningType = ManyToOneType(Customer)
+	 * and are being asked to determine whether "customer.id" is a reference
+	 * to customer's PK...
+	 *
+	 * @param propertyName The name of the property to check.
+	 * @param owningType The type represeting the entity "owning" the property
+	 * @return True if propertyName references the enti ty's (owningType->associatedEntity)
+	 * primary key; false otherwise.
+	 */
+	private boolean isReferenceToPrimaryKey(EntityType owningType, String propertyName) {
+		EntityPersister persister = getSessionFactoryImplementor().getEntityPersister(
+				owningType.getAssociatedEntityName( getSessionFactoryImplementor() )
+		);
+		if ( persister.getEntityMetamodel().hasNonIdentifierPropertyNamedId() ) {
+			// only the identifier property field name can be a reference to the associated entity's PK...
+			return propertyName.equals( persister.getIdentifierPropertyName() ) && owningType.isReferenceToPrimaryKey();
+		}
+		else {
+			// here, we have two possibilities:
+			// 		1) the property-name matches the explicitly identifier property name
+			//		2) the property-name matches the implicit 'id' property name
+			if ( EntityPersister.ENTITY_ID.equals( propertyName ) ) {
+				// the referenced node text is the special 'id'
+				return owningType.isReferenceToPrimaryKey();
+			}
+			else {
+				String keyPropertyName = owningType.getIdentifierOrUniqueKeyPropertyName( getSessionFactoryImplementor() );
+				return keyPropertyName != null && keyPropertyName.equals( propertyName ) && owningType.isReferenceToPrimaryKey();
+			}
+		}
+	}
+
+
+
+	// source impls ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	private class RootSourceImpl extends AbstractPathedPropertyReferenceSource {
+		private final PersisterSpace lhs;
+
+		public RootSourceImpl(PersisterSpace lhs) {
+			this.lhs = lhs;
+		}
+
+		public PathedPropertyReferenceSource handleIntermediatePathPart(String name) {
+			return determineAppropriateIntermediateSourceType( lhs, name );
+		}
+
+		public HibernateTree handleTerminalPathPart(String name) {
+			if ( lhs.getPropertyType( name ).isEntityType() ) {
+				if ( shouldTerminalEntityPropertyForceJoin() ) {
+					locateOrBuildPropertyJoinedTable( lhs, name, null, false, false );
+				}
+			}
+			return generatePropertyColumnList( lhs, name );
+		}
+
+		public PathedPropertyReferenceSource handleIntermediateIndexAccess(String collectionPropertyName, HibernateTree selector) {
+			validateIndexedCollectionReference( lhs, collectionPropertyName );
+			QueryableCollection collectionPersister = resolveCollectionPersister( lhs, collectionPropertyName );
+
+			Table joinedCollectionTable = createJoin( lhs, collectionPersister, null, selector );
+			return new IndexAccessIntermediatePathSource(joinedCollectionTable.getTableSpace().getPersisterSpace() );
+		}
+
+		public HibernateTree handleTerminalIndexAccess(String collectionPropertyName, HibernateTree selector) {
+			return handleTerminalIndexAccess( lhs, collectionPropertyName, selector );
+		}
+
+		public String getText() {
+			return "root-source {" + lhs.getSourceAlias() + "}";
+		}
+	}
+
+	protected class SimpleIntermediatePathSource extends AbstractPathedPropertyReferenceSource {
+		public PathedPropertyReferenceSource handleIntermediatePathPart(String name) {
+			throw new HibernateException( "cannot dereference simple value as part of path expression" );
+		}
+
+		public HibernateTree handleTerminalPathPart(String name) {
+			throw new HibernateException( "cannot dereference simple value as part of path expression" );
+		}
+
+		public PathedPropertyReferenceSource handleIntermediateIndexAccess(String name, HibernateTree selector) {
+			throw new HibernateException( "cannot apply index operation to simple value" );
+		}
+
+		public HibernateTree handleTerminalIndexAccess(String name, HibernateTree selector) {
+			throw new HibernateException( "cannot apply index operation to simple value" );
+		}
+	}
+
+	private class ComponentIntermediatePathSource extends AbstractPathedPropertyReferenceSource {
+		private final PersisterSpace lhs;
+		private final String propertyPath;
+		private final ComponentType componentType;
+
+		public ComponentIntermediatePathSource(PersisterSpace lhs, String propertyPath) {
+			this( lhs, propertyPath, ( ComponentType ) lhs.getPropertyType( propertyPath ) );
+		}
+
+		private ComponentIntermediatePathSource(PersisterSpace lhs, String propertyPath, ComponentType componentType) {
+			this.lhs = lhs;
+			this.propertyPath = propertyPath;
+			this.componentType = componentType;
+		}
+
+		public PathedPropertyReferenceSource handleIntermediatePathPart(String propertyName) {
+			final int index = locateComponentPropertyIndex( componentType, propertyName );
+			final String path = buildComponentDereferencePath( propertyName );
+			final Type propertyType = componentType.getSubtypes()[index];
+			if ( propertyType.isComponentType() ) {
+				return new ComponentIntermediatePathSource( lhs, path, ( ComponentType ) propertyType );
+			}
+			else if ( propertyType.isEntityType() ) {
+				return new EntityIntermediatePathSource( lhs, path );
+			}
+			else {
+				return new SimpleIntermediatePathSource();
+			}
+		}
+
+		public HibernateTree handleTerminalPathPart(String name) {
+			return generatePropertyColumnList( lhs, buildComponentDereferencePath( name ) );
+		}
+
+		public PathedPropertyReferenceSource handleIntermediateIndexAccess(String name, HibernateTree selector) {
+			throw new HibernateException( "cannot apply index operation to component value" );
+		}
+
+		public PropertyPathTerminus handleTerminalIndexAccess(String name, HibernateTree selector) {
+			throw new HibernateException( "cannot apply index operation to component value" );
+		}
+
+		private String buildComponentDereferencePath(String subPropertyName) {
+			return propertyPath + "." + subPropertyName;
+		}
+	}
+
+	protected class EntityIntermediatePathSource extends AbstractPathedPropertyReferenceSource {
+		private final PersisterSpace lhs;
+		private final String lhsPropertyName;
+
+		public EntityIntermediatePathSource(PersisterSpace lhs, String lhsPropertyName) {
+			this.lhs = lhs;
+			this.lhsPropertyName = lhsPropertyName;
+		}
+
+		public PathedPropertyReferenceSource handleIntermediatePathPart(String name) {
+			Table joinedTable = locateOrBuildPropertyJoinedTable( lhs, lhsPropertyName, null, false, false );
+			return determineAppropriateIntermediateSourceType( joinedTable.getTableSpace().getPersisterSpace(), name );
+		}
+
+		public HibernateTree handleTerminalPathPart(String name) {
+			final EntityType type = ( EntityType ) lhs.getPropertyType( lhsPropertyName );
+			if ( isReferenceToPrimaryKey( type, lhsPropertyName ) ) {
+				// todo : create a column-list based on the FKs...
+				return null;
+			}
+			else {
+				Table joinedTable = locateOrBuildPropertyJoinedTable( lhs, lhsPropertyName, null, false, false );
+				PersisterSpace rhs = joinedTable.getTableSpace().getPersisterSpace();
+				if ( type.isEntityType() ) {
+					if ( shouldTerminalEntityPropertyForceJoin() ) {
+						locateOrBuildPropertyJoinedTable( rhs, name, null, false, false );
+					}
+				}
+				return generatePropertyColumnList( rhs, name );
+			}
+
+		}
+
+		public PathedPropertyReferenceSource handleIntermediateIndexAccess(String name, HibernateTree selector) {
+			Table lhsJoinedTable = locateOrBuildPropertyJoinedTable( lhs, lhsPropertyName, null, false, false );
+			PersisterSpace lhsJoinedPersisterSpace = lhsJoinedTable.getTableSpace().getPersisterSpace();
+
+			validateIndexedCollectionReference( lhs, name );
+			QueryableCollection collectionPersister = resolveCollectionPersister( lhsJoinedPersisterSpace, name );
+			Table joinedTable = createJoin( lhsJoinedPersisterSpace, collectionPersister, null, selector );
+
+			return new IndexAccessIntermediatePathSource( joinedTable.getTableSpace().getPersisterSpace() );
+		}
+
+		public HibernateTree handleTerminalIndexAccess(String collectionPropertyName, HibernateTree selector) {
+			return handleTerminalIndexAccess( lhs, collectionPropertyName, selector );
+		}
+	}
+
+	protected boolean shouldTerminalEntityPropertyForceJoin() {
+		return false;
+	}
+
+	protected class CollectionIntermediatePathSource extends AbstractPathedPropertyReferenceSource {
+		private final PersisterSpace lhs;
+		private final String propertyName;
+
+		public CollectionIntermediatePathSource(PersisterSpace lhs, String propertyName) {
+			this.lhs = lhs;
+			this.propertyName = propertyName;
+		}
+
+		public PathedPropertyReferenceSource handleIntermediatePathPart(String name) {
+			throw new HibernateException( "cannot implicit join across a collection association" );
+		}
+
+		public HibernateTree handleTerminalPathPart(String name) {
+			// TODO : what are the circusmstances under which we need to *join* to the collection, as opposed to say munge it into a subquery???
+			if ( CollectionProperties.isAnyCollectionProperty( name ) ) {
+				Table joinedTable = locateOrBuildPropertyJoinedTable( lhs, propertyName, null, false, false );
+				return generatePropertyColumnList( joinedTable.getTableSpace().getPersisterSpace(), name );
+			}
+			throw new HibernateException( "cannot implicit join across a collection association" );
+		}
+
+		public PathedPropertyReferenceSource handleIntermediateIndexAccess(String name, HibernateTree selector) {
+			throw new HibernateException( "cannot implicit join across a collection association" );
+		}
+
+		public HibernateTree handleTerminalIndexAccess(String name, HibernateTree selector) {
+			throw new HibernateException( "cannot implicit join across a collection association" );
+		}
+	}
+
+	protected class IndexAccessIntermediatePathSource extends AbstractPathedPropertyReferenceSource {
+		private final PersisterSpace persisterSpace;
+
+		public IndexAccessIntermediatePathSource(PersisterSpace persisterSpace) {
+			this.persisterSpace = persisterSpace;
+		}
+
+		public PathedPropertyReferenceSource handleIntermediatePathPart(String name) {
+			return determineAppropriateIntermediateSourceType( persisterSpace, name );
+		}
+
+		public HibernateTree handleTerminalPathPart(String name) {
+			return generatePropertyColumnList( persisterSpace, name );
+		}
+
+		public PathedPropertyReferenceSource handleIntermediateIndexAccess(String name, HibernateTree selector) {
+			throw new IllegalStateException( "doubled up index operators" );
+		}
+
+		public HibernateTree handleTerminalIndexAccess(String name, HibernateTree selector) {
+			throw new IllegalStateException( "doubled up index operators" );
+		}
+	}
+}

Added: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/CollectionExpectedException.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/CollectionExpectedException.java	                        (rev 0)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/CollectionExpectedException.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -0,0 +1,46 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, 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.sql.ast.phase.hql.resolve.path.impl;
+
+/**
+ * Indicates that we were expecting a property reference to identify a collection, but it did not.
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionExpectedException extends AbstractUnexpectedPropertyTypeException {
+	public CollectionExpectedException(String path, String persisterName, String propertyName) {
+		super( path, persisterName, propertyName );
+	}
+
+	@Override
+	protected String internalGetMessage() {
+		return "Expected property reference [" + buildPropertyReferenceFragment() + "] to identify collection";
+	}
+}

Added: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/IndexedCollectionExectedException.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/IndexedCollectionExectedException.java	                        (rev 0)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/IndexedCollectionExectedException.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -0,0 +1,46 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, 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.sql.ast.phase.hql.resolve.path.impl;
+
+/**
+ * Indicates that we were expecting a property reference to identify an indexed collection, but it did not.
+ *
+ * @author Steve Ebersole
+ */
+public class IndexedCollectionExectedException extends AbstractUnexpectedPropertyTypeException {
+	public IndexedCollectionExectedException(String path, String persisterName, String propertyName) {
+		super( path, persisterName, propertyName );
+	}
+
+	@Override
+	protected String internalGetMessage() {
+		return "Expected property reference [" + buildPropertyReferenceFragment() + "] to identify indexed collection";
+	}
+}

Added: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/InvalidPropertyJoinException.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/InvalidPropertyJoinException.java	                        (rev 0)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/phase/hql/resolve/path/impl/InvalidPropertyJoinException.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -0,0 +1,46 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, 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.sql.ast.phase.hql.resolve.path.impl;
+
+/**
+ * Indicates an attempt to define an implicit or explicit property join based on a non-association property.
+ *
+ * @author Steve Ebersole
+ */
+public class InvalidPropertyJoinException extends AbstractUnexpectedPropertyTypeException {
+	public InvalidPropertyJoinException(String path, String persisterName, String propertyName) {
+		super( path, persisterName, propertyName );
+	}
+
+	@Override
+	protected String internalGetMessage() {
+		return "Referenced property [" + buildPropertyReferenceFragment() + "] not valid for join";
+	}
+}

Modified: core/branches/antlr3/src/main/java/org/hibernate/sql/ast/tree/Table.java
===================================================================
--- core/branches/antlr3/src/main/java/org/hibernate/sql/ast/tree/Table.java	2009-04-21 18:19:38 UTC (rev 16387)
+++ core/branches/antlr3/src/main/java/org/hibernate/sql/ast/tree/Table.java	2009-04-21 18:29:41 UTC (rev 16388)
@@ -26,12 +26,11 @@
  * 51 Franklin Street, Fifth Floor
  * Boston, MA  02110-1301  USA
  */
-
 package org.hibernate.sql.ast.tree;
 
-import java.util.List;
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
+import java.util.HashMap;
 
 import org.antlr.runtime.Token;
 
@@ -41,6 +40,7 @@
 import org.hibernate.sql.ast.common.HibernateToken;
 import org.hibernate.sql.ast.util.DisplayableNode;
 import org.hibernate.sql.ast.phase.hql.parse.HQLParser;
+import org.hibernate.sql.ast.phase.hql.resolve.PersisterSpace;
 import org.hibernate.persister.entity.Queryable;
 import org.hibernate.persister.collection.QueryableCollection;
 import org.hibernate.util.StringHelper;
@@ -95,7 +95,13 @@
 		return "[source-alias=" + tableSpace.getSourceAlias() + "]";
 	}
 
+	/**
+	 * Represents a grouping of related tables (i.e. all tables for a given persister).
+	 */
 	public static interface TableSpace {
+
+		public void addTable(Table table);
+
 		/**
 		 * Used as a unique identification since each table space originates from a single source alias (persister reference).
 		 *
@@ -104,6 +110,13 @@
 		public String getSourceAlias();
 
 		/**
+		 * PersisterSpace and TableSpace are related one-to-one...
+		 *
+		 * @return The persister space corresponding to this table space.
+		 */
+		public PersisterSpace getPersisterSpace();
+
+		/**
 		 * Get the table reference that should act as the RHS for this table space whenever we join to into it.
 		 *
 		 * @return The RHS table for joining into this table space structure.
@@ -112,9 +125,8 @@
 
 		public String[] getJoinIntoColumns();
 
-		public void addTable(Table table);
+		public Type getPropertyType(String propertyName);
 
-
 		/**
 		 * Get the table reference that contains the columns to which the given property is mapped.
 		 *
@@ -124,23 +136,23 @@
 		 */
 		public Table getContainingTable(String propertyName);
 
-		public Type getPropertyType(String propertyName);
-
 		public String[] getPropertyColumnNames(String propertyName);
 
-		public List buildIdentifierColumnReferences();
+		public HibernateTree buildIdentifierColumnReferences();
 
-		public List buildCompleteColumnReferences();
+		public HibernateTree buildCompleteColumnReferences();
 	}
 
 	public static abstract class AbstractTableSpace implements Table.TableSpace {
 		private final String sourceAlias;
-		private final String sqlAliasBaseRoot;
+		private final boolean implicitSourceAlias;
 		protected final LinkedHashSet<Table> tables = new LinkedHashSet<Table>();
+		protected final HashMap<String,Table> aliasToTableMap = new HashMap<String,Table>();
+		protected final HashMap<String,Table> nameToTableMap = new HashMap<String,Table>();
 
-		private AbstractTableSpace(String sourceAlias, String persisterName) {
+		private AbstractTableSpace(String sourceAlias) {
 			this.sourceAlias = sourceAlias;
-			this.sqlAliasBaseRoot = ImplicitAliasGenerator.isImplicitAlias( sourceAlias ) ? persisterName : sourceAlias;
+			this.implicitSourceAlias = ImplicitAliasGenerator.isImplicitAlias( sourceAlias );
 		}
 
 		public String getSourceAlias() {
@@ -148,32 +160,46 @@
 		}
 
 		public String getSqlAliasBaseRoot() {
-			return sqlAliasBaseRoot;
+			return implicitSourceAlias ? getPersisterSpace().getShortName() : sourceAlias;
 		}
 
 		public void addTable(Table table) {
 			tables.add( table );
+			aliasToTableMap.put( table.getAliasText(), table );
+			nameToTableMap.put( table.getTableNameText(), table );
 		}
 	}
 
+	public static abstract class AbstractPersisterSpace implements PersisterSpace {
+		private final HashMap<String,Table> propertyToJoinedTableMap = new HashMap<String,Table>();
+
+		public Table locateReusablePropertyJoinedTable(String propertyName) {
+			return propertyToJoinedTableMap.get( propertyName );
+		}
+
+		public void registerReusablePropertyJoinedTable(String propertyName, Table table) {
+			propertyToJoinedTableMap.put( propertyName, table );
+		}
+	}
+
 	public static class EntityTableSpace extends AbstractTableSpace {
-		private final Queryable entityPersister;
+		private final EntityPersisterSpace persisterSpace;
 		private final ArrayList tables;
 
 		public EntityTableSpace(Queryable entityPersister, String sourecAlias) {
-			super( sourecAlias, StringHelper.unqualifyEntityName( entityPersister.getEntityName() ) );
-			this.entityPersister = entityPersister;
+			super( sourecAlias );
+			this.persisterSpace = new EntityPersisterSpace( this, entityPersister );
 			int numberOfTables = entityPersister.getMappedTableMetadata().getJoinedTables().length + 1;
 			int listSize = numberOfTables + (int) ( numberOfTables * .75 ) + 1;
 			this.tables = new ArrayList( listSize );
 		}
 
-		public Queryable getEntityPersister() {
-			return entityPersister;
+		public PersisterSpace getPersisterSpace() {
+			return persisterSpace;
 		}
 
-		public void addTable(Table table) {
-			tables.add( table );
+		public Queryable getEntityPersister() {
+			return persisterSpace.getEntityPersister();
 		}
 
 		public Table getDrivingTable() {
@@ -185,69 +211,98 @@
 		}
 
 		public String[] getJoinIntoColumns() {
-			return entityPersister.getIdentifierColumnNames();
+			return getEntityPersister().getIdentifierColumnNames();
 		}
 
 		public Table getContainingTable(String propertyName) {
-			return ( Table ) tables.get( entityPersister.getSubclassPropertyTableNumber( propertyName ) );
+			// todo : probably a better solution here is to iterate the internal collection of tables...
+			return ( Table ) tables.get( getEntityPersister().getSubclassPropertyTableNumber( propertyName ) );
 		}
 
 		public Type getPropertyType(String propertyName) {
-			return entityPersister.getPropertyType( propertyName );
+			return getEntityPersister().getPropertyType( propertyName );
 		}
 
 		public String[] getPropertyColumnNames(String propertyName) {
-			int index = entityPersister.getEntityMetamodel().getPropertyIndex( propertyName );
-			return entityPersister.getPropertyColumnNames( index );
+			int index = getEntityPersister().getEntityMetamodel().getPropertyIndex( propertyName );
+			return getEntityPersister().getPropertyColumnNames( index );
 		}
 
-		public List buildIdentifierColumnReferences() {
-			String[] identifierColumnsNames = entityPersister.getIdentifierColumnNames();
-			ArrayList columnsReferences = new ArrayList( collectionSizeWithoutRehashing( identifierColumnsNames.length ) );
-			for ( int i = 0; i < identifierColumnsNames.length; i++ ) {
+		public HibernateTree buildIdentifierColumnReferences() {
+			HibernateTree columnList = new HibernateTree( HQLParser.COLUMN_LIST );
+			for ( String columnName : getEntityPersister().getIdentifierColumnNames() ) {
 				HibernateTree columnNode = new HibernateTree( HQLParser.COLUMN );
 				columnNode.addChild( new HibernateTree( HQLParser.ALIAS_REF, getDrivingTable().getAliasText() ) );
-				columnNode.addChild( new HibernateTree( HQLParser.IDENTIFIER, identifierColumnsNames[i] ) );
-				columnsReferences.add( columnNode );
+				columnNode.addChild( new HibernateTree( HQLParser.IDENTIFIER, columnName ) );
+				columnList.addChild( columnNode );
 			}
-			return columnsReferences;
+			return columnList;
 		}
 
-		public List buildCompleteColumnReferences() {
+		public HibernateTree buildCompleteColumnReferences() {
 			// todo : implement
 			return null;
 		}
 	}
 
-	private static int collectionSizeWithoutRehashing(int elements) {
-		// usually collection load factors are .75
-		return collectionSizeWithoutRehashing( elements, .75 );
-	}
+	private static class EntityPersisterSpace extends AbstractPersisterSpace {
+		private final EntityTableSpace correspondingTableSpace;
+		private final Queryable entityPersister;
+		private final String shortName;
 
-	private static int collectionSizeWithoutRehashing(int elements, double factor) {
-		return elements + ( (int) ( elements * factor ) + 1 );
+		private EntityPersisterSpace(EntityTableSpace correspondingTableSpace, Queryable entityPersister) {
+			this.correspondingTableSpace = correspondingTableSpace;
+			this.entityPersister = entityPersister;
+			this.shortName = StringHelper.unqualifyEntityName( entityPersister.getEntityName() );
+		}
+
+		public Queryable getEntityPersister() {
+			return entityPersister;
+		}
+
+		public String getSourceAlias() {
+			return correspondingTableSpace.getSourceAlias();
+		}
+
+		public String getName() {
+			return entityPersister.getName();
+		}
+
+		public String getShortName() {
+			return shortName;
+		}
+
+		public TableSpace getTableSpace() {
+			return correspondingTableSpace;
+		}
+
+		public Type getPropertyType(String propertyName) {
+			return entityPersister.getPropertyType( propertyName );
+		}
 	}
 
 	public static class CollectionTableSpace extends AbstractTableSpace {
-		private final QueryableCollection persister;
-		private final boolean areElementsEntities;
+		private final CollectionPersisterSpace persisterSpace;
 
 		private Table collectionTable;
 		private EntityTableSpace entityElementTableSpace;
 
 		public CollectionTableSpace(QueryableCollection persister, String sourceAlias) {
-			super( sourceAlias, StringHelper.unqualify( persister.getRole() ) );
-			this.persister = persister;
-			this.areElementsEntities = persister.getElementType().isEntityType();
-			if ( areElementsEntities ) {
+			super( sourceAlias );
+			this.persisterSpace = new CollectionPersisterSpace( this, persister );
+			if ( persisterSpace.areElementsEntities ) {
 				entityElementTableSpace = new EntityTableSpace( ( Queryable ) persister.getElementPersister(), sourceAlias );
 			}
 		}
 
-		public QueryableCollection getPersister() {
-			return persister;
+		public QueryableCollection getCollectionPersister() {
+			return persisterSpace.getCollectionPersister();
 		}
 
+		public PersisterSpace getPersisterSpace() {
+			return persisterSpace;
+		}
+
 		public void setCollectionTable(Table collectionTable) {
 			this.collectionTable = collectionTable;
 		}
@@ -261,7 +316,7 @@
 		}
 
 		public String[] getJoinIntoColumns() {
-			return persister.getKeyColumnNames();
+			return getCollectionPersister().getKeyColumnNames();
 		}
 
 		public Table getContainingTable(String propertyName) {
@@ -277,14 +332,55 @@
 			return getEntityElementTableSpace().getPropertyColumnNames( propertyName );
 		}
 
-		public List buildIdentifierColumnReferences() {
+		public HibernateTree buildIdentifierColumnReferences() {
 			// todo : implement
 			return null;
 		}
 
-		public List buildCompleteColumnReferences() {
+		public HibernateTree buildCompleteColumnReferences() {
 			// todo : implement
 			return null;
 		}
 	}
+
+	public static class CollectionPersisterSpace extends AbstractPersisterSpace {
+		private final CollectionTableSpace correspondingTableSpace;
+		private final QueryableCollection collectionPersister;
+
+		private final String shortName;
+		private final boolean areElementsEntities;
+
+		public CollectionPersisterSpace(CollectionTableSpace correspondingTableSpace, QueryableCollection collectionPersister) {
+			this.correspondingTableSpace = correspondingTableSpace;
+			this.collectionPersister = collectionPersister;
+			this.shortName = StringHelper.unqualify( collectionPersister.getRole() );
+			this.areElementsEntities = collectionPersister.getElementType().isEntityType();
+		}
+
+		public String getSourceAlias() {
+			return correspondingTableSpace.getSourceAlias();
+		}
+
+		public QueryableCollection getCollectionPersister() {
+			return collectionPersister;
+		}
+
+		public String getName() {
+			return collectionPersister.getRole();
+		}
+
+		public String getShortName() {
+			return shortName;
+		}
+
+		public TableSpace getTableSpace() {
+			return correspondingTableSpace;
+		}
+
+		public Type getPropertyType(String propertyName) {
+			return areElementsEntities
+					? correspondingTableSpace.entityElementTableSpace.getPersisterSpace().getPropertyType( propertyName )
+					: null;
+		}
+	}
 }




More information about the hibernate-commits mailing list