FileDocCategorySizeDatePackage
PathExpressionParser.javaAPI DocHibernate 3.2.515838Thu Nov 16 13:21:48 GMT 2006org.hibernate.hql.classic

PathExpressionParser

public class PathExpressionParser extends Object implements Parser
Parses an expression of the form foo.bar.baz and builds up an expression involving two less table joins than there are path components.

Fields Summary
private int
dotcount
private String
currentName
private String
currentProperty
private String
oneToOneOwnerName
private org.hibernate.type.AssociationType
ownerAssociationType
private String[]
columns
private String
collectionName
private String
collectionOwnerName
private String
collectionRole
private final StringBuffer
componentPath
private org.hibernate.type.Type
type
private final StringBuffer
path
private boolean
ignoreInitialJoin
private boolean
continuation
private int
joinType
private boolean
useThetaStyleJoin
private org.hibernate.persister.entity.PropertyMapping
currentPropertyMapping
private org.hibernate.engine.JoinSequence
joinSequence
private boolean
expectingCollectionIndex
private LinkedList
collectionElements
Constructors Summary
Methods Summary
public voidaddAssociation(QueryTranslatorImpl q)

		q.addJoin( getName(), joinSequence );
	
public java.lang.StringaddFromAssociation(QueryTranslatorImpl q)

		if ( isCollectionValued() ) {
			return addFromCollection( q );
		}
		else {
			q.addFrom( currentName, joinSequence );
			return currentName;
		}
	
public java.lang.StringaddFromCollection(QueryTranslatorImpl q)

		Type collectionElementType = getPropertyType();

		if ( collectionElementType == null ) {
			throw new QueryException( "must specify 'elements' for collection valued property in from clause: " + path );
		}

		if ( collectionElementType.isEntityType() ) {
			// an association
			QueryableCollection collectionPersister = q.getCollectionPersister( collectionRole );
			Queryable entityPersister = ( Queryable ) collectionPersister.getElementPersister();
			String clazz = entityPersister.getEntityName();

			final String elementName;
			if ( collectionPersister.isOneToMany() ) {
				elementName = collectionName;
				//allow index() function:
				q.decoratePropertyMapping( elementName, collectionPersister );
			}
			else { //many-to-many
				q.addCollection( collectionName, collectionRole );
				elementName = q.createNameFor( clazz );
				addJoin( elementName, ( AssociationType ) collectionElementType );
			}
			q.addFrom( elementName, clazz, joinSequence );
			currentPropertyMapping = new CollectionPropertyMapping( collectionPersister );
			return elementName;
		}
		else {
			// collections of values
			q.addFromCollection( collectionName, collectionRole, joinSequence );
			return collectionName;
		}

	
private voidaddJoin(java.lang.String name, org.hibernate.type.AssociationType joinableType)

		try {
			joinSequence.addJoin( joinableType, name, joinType, currentColumns() );
		}
		catch ( MappingException me ) {
			throw new QueryException( me );
		}
	
private voidaddJoin(java.lang.String name, org.hibernate.type.AssociationType joinableType, java.lang.String[] foreignKeyColumns)

		try {
			joinSequence.addJoin( joinableType, name, joinType, foreignKeyColumns );
		}
		catch ( MappingException me ) {
			throw new QueryException( me );
		}
	
java.lang.StringcontinueFromManyToMany(java.lang.String entityName, java.lang.String[] joinColumns, QueryTranslatorImpl q)

		start( q );
		continuation = true;
		currentName = q.createNameFor( entityName );
		q.addType( currentName, entityName );
		Queryable classPersister = q.getEntityPersister( entityName );
		//QueryJoinFragment join = q.createJoinFragment(useThetaStyleJoin);
		addJoin( currentName, TypeFactory.manyToOne( entityName ), joinColumns );
		currentPropertyMapping = classPersister;
		return currentName;
	
protected java.lang.String[]currentColumns()

		String propertyPath = getPropertyPath();
		String[] propertyColumns = getPropertyMapping().toColumns( currentName, propertyPath );
		if ( propertyColumns == null ) {
			throw new QueryException( "could not resolve property columns: " + propertyPath );
		}
		return propertyColumns;
	
private voiddereferenceCollection(java.lang.String propertyName, java.lang.String role, QueryTranslatorImpl q)

		collectionRole = role;
		QueryableCollection collPersister = q.getCollectionPersister( role );
		String name = q.createNameForCollection( role );
		addJoin( name, collPersister.getCollectionType() );
		//if ( collPersister.hasWhere() ) join.addCondition( collPersister.getSQLWhereString(name) );
		collectionName = name;
		collectionOwnerName = currentName;
		currentName = name;
		currentProperty = propertyName;
		componentPath.setLength( 0 );
		currentPropertyMapping = new CollectionPropertyMapping( collPersister );
	
private voiddereferenceComponent(java.lang.String propertyName)

		if ( propertyName != null ) {
			if ( componentPath.length() > 0 ) componentPath.append( '." );
			componentPath.append( propertyName );
		}
	
private voiddereferenceEntity(java.lang.String propertyName, org.hibernate.type.EntityType propertyType, QueryTranslatorImpl q)

		//NOTE: we avoid joining to the next table if the named property is just the foreign key value

		//if its "id"
		boolean isIdShortcut = EntityPersister.ENTITY_ID.equals( propertyName ) &&
				propertyType.isReferenceToPrimaryKey();

		//or its the id property name
		final String idPropertyName;
		try {
			idPropertyName = propertyType.getIdentifierOrUniqueKeyPropertyName( q.getFactory() );
		}
		catch ( MappingException me ) {
			throw new QueryException( me );
		}
		boolean isNamedIdPropertyShortcut = idPropertyName != null
				&& idPropertyName.equals( propertyName )
				&& propertyType.isReferenceToPrimaryKey();

		if ( isIdShortcut || isNamedIdPropertyShortcut ) {
			// special shortcut for id properties, skip the join!
			// this must only occur at the _end_ of a path expression
			if ( componentPath.length() > 0 ) componentPath.append( '." );
			componentPath.append( propertyName );
		}
		else {
			String entityClass = propertyType.getAssociatedEntityName();
			String name = q.createNameFor( entityClass );
			q.addType( name, entityClass );
			addJoin( name, propertyType );
			if ( propertyType.isOneToOne() ) oneToOneOwnerName = currentName;
			ownerAssociationType = propertyType;
			currentName = name;
			currentProperty = propertyName;
			q.addPathAliasAndJoin( path.substring( 0, path.toString().lastIndexOf( '." ) ), name, joinSequence.copy() );
			componentPath.setLength( 0 );
			currentPropertyMapping = q.getEntityPersister( entityClass );
		}
	
public voidend(QueryTranslatorImpl q)

		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;

	
public voidfetch(QueryTranslatorImpl q, java.lang.String entityName)

		if ( isCollectionValued() ) {
			q.setCollectionToFetch( getCollectionRole(), getCollectionName(), getCollectionOwnerName(), entityName );
		}
		else {
			q.addEntityToFetch( entityName, getOneToOneOwnerName(), getOwnerAssociationType() );
		}
	
java.lang.StringgetCollectionName()

		return collectionName;
	
java.lang.StringgetCollectionOwnerName()

		return collectionOwnerName;
	
java.lang.StringgetCollectionRole()

		return collectionRole;
	
public java.lang.StringgetCollectionSubquery(java.util.Map enabledFilters)

		return CollectionSubqueryFactory.createCollectionSubquery( joinSequence, enabledFilters, currentColumns() );
	
java.lang.StringgetCurrentName()

		return currentName;
	
java.lang.StringgetCurrentProperty()

		return currentProperty;
	
public java.lang.StringgetName()

		return currentName == null ? collectionName : currentName;
	
java.lang.StringgetOneToOneOwnerName()

		return oneToOneOwnerName;
	
org.hibernate.type.AssociationTypegetOwnerAssociationType()

		return ownerAssociationType;
	
private org.hibernate.persister.entity.PropertyMappinggetPropertyMapping()

		return currentPropertyMapping;
	
private java.lang.StringgetPropertyPath()

		if ( currentProperty == null ) {
			return EntityPersister.ENTITY_ID;
		}
		else {
			if ( componentPath.length() > 0 ) {
				return new StringBuffer()
						.append( currentProperty )
						.append( '." )
						.append( componentPath.toString() )
						.toString();
			}
			else {
				return currentProperty;
			}
		}
	
protected org.hibernate.type.TypegetPropertyType()

		String propertyPath = getPropertyPath();
		Type propertyType = getPropertyMapping().toType( propertyPath );
		if ( propertyType == null ) {
			throw new QueryException( "could not resolve property type: " + propertyPath );
		}
		return propertyType;
	
public java.lang.StringgetWhereColumn()

		if ( columns.length != 1 ) {
			throw new QueryException( "path expression ends in a composite value: " + path );
		}
		return columns[0];
	
public org.hibernate.type.TypegetWhereColumnType()

		return type;
	
public java.lang.String[]getWhereColumns()

		return columns;
	
public org.hibernate.engine.JoinSequencegetWhereJoin()

		return joinSequence;
	
public voidignoreInitialJoin()

		ignoreInitialJoin = true;
	
public booleanisCollectionValued()

		//TODO: is there a better way?
		return collectionName != null && !getPropertyType().isCollectionType();
	
public booleanisExpectingCollectionIndex()

		return expectingCollectionIndex;
	
public org.hibernate.hql.classic.PathExpressionParser$CollectionElementlastCollectionElement()

	

	   
		return ( CollectionElement ) collectionElements.removeLast();
	
private voidprepareForIndex(QueryTranslatorImpl q)


		QueryableCollection collPersister = q.getCollectionPersister( collectionRole );

		if ( !collPersister.hasIndex() ) throw new QueryException( "unindexed collection before []: " + path );
		String[] indexCols = collPersister.getIndexColumnNames();
		if ( indexCols.length != 1 ) throw new QueryException( "composite-index appears in []: " + path );
		//String[] keyCols = collPersister.getKeyColumnNames();

		JoinSequence fromJoins = new JoinSequence( q.getFactory() )
				.setUseThetaStyle( useThetaStyleJoin )
				.setRoot( collPersister, collectionName )
				.setNext( joinSequence.copy() );

		if ( !continuation ) addJoin( collectionName, collPersister.getCollectionType() );

		joinSequence.addCondition( collectionName + '." + indexCols[0] + " = " ); //TODO: get SQL rendering out of here

		CollectionElement elem = new CollectionElement();
		elem.elementColumns = collPersister.getElementColumnNames(collectionName);
		elem.elementType = collPersister.getElementType();
		elem.isOneToMany = collPersister.isOneToMany();
		elem.alias = collectionName;
		elem.joinSequence = joinSequence;
		collectionElements.addLast( elem );
		setExpectingCollectionIndex();

		q.addCollection( collectionName, collectionRole );
		q.addFromJoinOnly( collectionName, fromJoins );
	
private voidreset(QueryTranslatorImpl q)

		//join = q.createJoinFragment(useThetaStyleJoin);
		dotcount = 0;
		currentName = null;
		currentProperty = null;
		collectionName = null;
		collectionRole = null;
		componentPath.setLength( 0 );
		type = null;
		collectionName = null;
		columns = null;
		expectingCollectionIndex = false;
		continuation = false;
		currentPropertyMapping = null;
	
protected voidsetExpectingCollectionIndex()

		expectingCollectionIndex = true;
	
voidsetJoinType(int joinType)


	   
		this.joinType = joinType;
	
public voidsetLastCollectionElementIndexValue(java.lang.String value)

		( ( CollectionElement ) collectionElements.getLast() ).indexValue.append( value );
	
private voidsetType()

		if ( currentProperty == null ) {
			type = getPropertyMapping().getType();
		}
		else {
			type = getPropertyType();
		}
	
voidsetUseThetaStyleJoin(boolean useThetaStyleJoin)

		this.useThetaStyleJoin = useThetaStyleJoin;
	
public voidstart(QueryTranslatorImpl q)

		if ( !continuation ) {
			reset( q );
			path.setLength( 0 );
			joinSequence = new JoinSequence( q.getFactory() ).setUseThetaStyle( useThetaStyleJoin );
		}
	
public voidtoken(java.lang.String token, QueryTranslatorImpl q)


		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 );
				}

			}
		}