Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » hql » ast » util » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.hql.ast.util;
   26   
   27   import java.util.HashMap;
   28   import java.util.Map;
   29   
   30   import org.hibernate.MappingException;
   31   import org.hibernate.QueryException;
   32   import org.hibernate.dialect.function.SQLFunction;
   33   import org.hibernate.engine.JoinSequence;
   34   import org.hibernate.engine.SessionFactoryImplementor;
   35   import org.hibernate.hql.NameGenerator;
   36   import org.hibernate.hql.ast.DetailedSemanticException;
   37   import org.hibernate.hql.ast.QuerySyntaxException;
   38   import org.hibernate.hql.ast.tree.SqlNode;
   39   import org.hibernate.persister.collection.CollectionPropertyMapping;
   40   import org.hibernate.persister.collection.CollectionPropertyNames;
   41   import org.hibernate.persister.collection.QueryableCollection;
   42   import org.hibernate.persister.entity.EntityPersister;
   43   import org.hibernate.persister.entity.PropertyMapping;
   44   import org.hibernate.persister.entity.Queryable;
   45   import org.hibernate.type.AssociationType;
   46   import org.hibernate.type.CollectionType;
   47   import org.hibernate.type.EntityType;
   48   import org.hibernate.type.Type;
   49   import org.hibernate.type.TypeFactory;
   50   
   51   import antlr.SemanticException;
   52   import antlr.collections.AST;
   53   
   54   /**
   55    * Helper for performing common and/or complex operations with the
   56    * {@link SessionFactoryImplementor} during translation of an HQL query.
   57    *
   58    * @author Joshua Davis
   59    */
   60   public class SessionFactoryHelper {
   61   
   62   	private SessionFactoryImplementor sfi;
   63   	private Map collectionPropertyMappingByRole;
   64   
   65   	/**
   66   	 * Construct a new SessionFactoryHelper instance.
   67   	 *
   68   	 * @param sfi The SessionFactory impl to be encapsualted.
   69   	 */
   70   	public SessionFactoryHelper(SessionFactoryImplementor sfi) {
   71   		this.sfi = sfi;
   72   		collectionPropertyMappingByRole = new HashMap();
   73   	}
   74   
   75   	/**
   76   	 * Get a handle to the encapsulated SessionFactory.
   77   	 *
   78   	 * @return The encapsulated SessionFactory.
   79   	 */
   80   	public SessionFactoryImplementor getFactory() {
   81   		return sfi;
   82   	}
   83   
   84   	/**
   85   	 * Does the given persister define a physical discriminator column
   86   	 * for the purpose of inheritence discrimination?
   87   	 *
   88   	 * @param persister The persister to be checked.
   89   	 * @return True if the persister does define an actual discriminator column.
   90   	 */
   91   	public boolean hasPhysicalDiscriminatorColumn(Queryable persister) {
   92   		if ( persister.getDiscriminatorType() != null ) {
   93   			String discrimColumnName = persister.getDiscriminatorColumnName();
   94   			// Needed the "clazz_" check to work around union-subclasses
   95   			// TODO : is there a way to tell whether a persister is truly discrim-column based inheritence?
   96   			if ( discrimColumnName != null && !"clazz_".equals( discrimColumnName ) ) {
   97   				return true;
   98   			}
   99   		}
  100   		return false;
  101   	}
  102   
  103   	/**
  104   	 * Given a (potentially unqualified) class name, locate its imported qualified name.
  105   	 *
  106   	 * @param className The potentially unqualified class name
  107   	 * @return The qualified class name.
  108   	 */
  109   	public String getImportedClassName(String className) {
  110   		return sfi.getImportedClassName( className );
  111   	}
  112   
  113   	/**
  114   	 * Given a (potentially unqualified) class name, locate its persister.
  115   	 *
  116   	 * @param className The (potentially unqualified) class name.
  117   	 * @return The defined persister for this class, or null if none found.
  118   	 */
  119   	public Queryable findQueryableUsingImports(String className) {
  120   		return findQueryableUsingImports( sfi, className );
  121   	}
  122   
  123   
  124   	/**
  125   	 * Given a (potentially unqualified) class name, locate its persister.
  126   	 *
  127   	 * @param sfi The session factory implementor.
  128   	 * @param className The (potentially unqualified) class name.
  129   	 * @return The defined persister for this class, or null if none found.
  130   	 */
  131   	public static Queryable findQueryableUsingImports(SessionFactoryImplementor sfi, String className) {
  132   		final String importedClassName = sfi.getImportedClassName( className );
  133   		if ( importedClassName == null ) {
  134   			return null;
  135   		}
  136   		try {
  137   			return ( Queryable ) sfi.getEntityPersister( importedClassName );
  138   		}
  139   		catch ( MappingException me ) {
  140   			return null;
  141   		}
  142   	}
  143   
  144   	/**
  145   	 * Locate the persister by class or entity name.
  146   	 *
  147   	 * @param name The class or entity name
  148   	 * @return The defined persister for this entity, or null if none found.
  149   	 * @throws MappingException
  150   	 */
  151   	private EntityPersister findEntityPersisterByName(String name) throws MappingException {
  152   		// First, try to get the persister using the given name directly.
  153   		try {
  154   			return sfi.getEntityPersister( name );
  155   		}
  156   		catch ( MappingException ignore ) {
  157   			// unable to locate it using this name
  158   		}
  159   
  160   		// If that didn't work, try using the 'import' name.
  161   		String importedClassName = sfi.getImportedClassName( name );
  162   		if ( importedClassName == null ) {
  163   			return null;
  164   		}
  165   		return sfi.getEntityPersister( importedClassName );
  166   	}
  167   
  168   	/**
  169   	 * Locate the persister by class or entity name, requiring that such a persister
  170   	 * exist.
  171   	 *
  172   	 * @param name The class or entity name
  173   	 * @return The defined persister for this entity
  174   	 * @throws SemanticException Indicates the persister could not be found
  175   	 */
  176   	public EntityPersister requireClassPersister(String name) throws SemanticException {
  177   		EntityPersister cp;
  178   		try {
  179   			cp = findEntityPersisterByName( name );
  180   			if ( cp == null ) {
  181   				throw new QuerySyntaxException( name + " is not mapped" );
  182   			}
  183   		}
  184   		catch ( MappingException e ) {
  185   			throw new DetailedSemanticException( e.getMessage(), e );
  186   		}
  187   		return cp;
  188   	}
  189   
  190   	/**
  191   	 * Locate the collection persister by the collection role.
  192   	 *
  193   	 * @param role The collection role name.
  194   	 * @return The defined CollectionPersister for this collection role, or null.
  195   	 */
  196   	public QueryableCollection getCollectionPersister(String role) {
  197   		try {
  198   			return ( QueryableCollection ) sfi.getCollectionPersister( role );
  199   		}
  200   		catch ( ClassCastException cce ) {
  201   			throw new QueryException( "collection is not queryable: " + role );
  202   		}
  203   		catch ( Exception e ) {
  204   			throw new QueryException( "collection not found: " + role );
  205   		}
  206   	}
  207   
  208   	/**
  209   	 * Locate the collection persister by the collection role, requiring that
  210   	 * such a persister exist.
  211   	 *
  212   	 * @param role The collection role name.
  213   	 * @return The defined CollectionPersister for this collection role.
  214   	 * @throws QueryException Indicates that the collection persister could not be found.
  215   	 */
  216   	public QueryableCollection requireQueryableCollection(String role) throws QueryException {
  217   		try {
  218   			QueryableCollection queryableCollection = ( QueryableCollection ) sfi.getCollectionPersister( role );
  219   			if ( queryableCollection != null ) {
  220   				collectionPropertyMappingByRole.put( role, new CollectionPropertyMapping( queryableCollection ) );
  221   			}
  222   			return queryableCollection;
  223   		}
  224   		catch ( ClassCastException cce ) {
  225   			throw new QueryException( "collection role is not queryable: " + role );
  226   		}
  227   		catch ( Exception e ) {
  228   			throw new QueryException( "collection role not found: " + role );
  229   		}
  230   	}
  231   
  232   	/**
  233   	 * Retreive a PropertyMapping describing the given collection role.
  234   	 *
  235   	 * @param role The collection role for whcih to retrieve the property mapping.
  236   	 * @return The property mapping.
  237   	 */
  238   	private PropertyMapping getCollectionPropertyMapping(String role) {
  239   		return ( PropertyMapping ) collectionPropertyMappingByRole.get( role );
  240   	}
  241   
  242   	/**
  243   	 * Retrieves the column names corresponding to the collection elements for the given
  244   	 * collection role.
  245   	 *
  246   	 * @param role The collection role
  247   	 * @param roleAlias The sql column-qualification alias (i.e., the table alias)
  248   	 * @return the collection element columns
  249   	 */
  250   	public String[] getCollectionElementColumns(String role, String roleAlias) {
  251   		return getCollectionPropertyMapping( role ).toColumns( roleAlias, CollectionPropertyNames.COLLECTION_ELEMENTS );
  252   	}
  253   
  254   	/**
  255   	 * Generate an empty join sequence instance.
  256   	 *
  257   	 * @return The generate join sequence.
  258   	 */
  259   	public JoinSequence createJoinSequence() {
  260   		return new JoinSequence( sfi );
  261   	}
  262   
  263   	/**
  264   	 * Generate a join sequence representing the given association type.
  265   	 *
  266   	 * @param implicit Should implicit joins (theta-style) or explicit joins (ANSI-style) be rendered
  267   	 * @param associationType The type representing the thing to be joined into.
  268   	 * @param tableAlias The table alias to use in qualifing the join conditions
  269   	 * @param joinType The type of join to render (inner, outer, etc);  see {@link org.hibernate.sql.JoinFragment}
  270   	 * @param columns The columns making up the condition of the join.
  271   	 * @return The generated join sequence.
  272   	 */
  273   	public JoinSequence createJoinSequence(boolean implicit, AssociationType associationType, String tableAlias, int joinType, String[] columns) {
  274   		JoinSequence joinSequence = createJoinSequence();
  275   		joinSequence.setUseThetaStyle( implicit );	// Implicit joins use theta style (WHERE pk = fk), explicit joins use JOIN (after from)
  276   		joinSequence.addJoin( associationType, tableAlias, joinType, columns );
  277   		return joinSequence;
  278   	}
  279   
  280   	/**
  281   	 * Create a join sequence rooted at the given collection.
  282   	 *
  283   	 * @param collPersister The persister for the collection at which the join should be rooted.
  284   	 * @param collectionName The alias to use for qualifying column references.
  285   	 * @return The generated join sequence.
  286   	 */
  287   	public JoinSequence createCollectionJoinSequence(QueryableCollection collPersister, String collectionName) {
  288   		JoinSequence joinSequence = createJoinSequence();
  289   		joinSequence.setRoot( collPersister, collectionName );
  290   		joinSequence.setUseThetaStyle( true );		// TODO: figure out how this should be set.
  291   ///////////////////////////////////////////////////////////////////////////////
  292   // This was the reason for failures regarding INDEX_OP and subclass joins on
  293   // theta-join dialects; not sure what behaviour we were trying to emulate ;)
  294   //		joinSequence = joinSequence.getFromPart();	// Emulate the old addFromOnly behavior.
  295   		return joinSequence;
  296   	}
  297   
  298   	/**
  299   	 * Determine the name of the property for the entity encapsulated by the
  300   	 * given type which represents the id or unique-key.
  301   	 *
  302   	 * @param entityType The type representing the entity.
  303   	 * @return The corresponding property name
  304   	 * @throws QueryException Indicates such a property could not be found.
  305   	 */
  306   	public String getIdentifierOrUniqueKeyPropertyName(EntityType entityType) {
  307   		try {
  308   			return entityType.getIdentifierOrUniqueKeyPropertyName( sfi );
  309   		}
  310   		catch ( MappingException me ) {
  311   			throw new QueryException( me );
  312   		}
  313   	}
  314   
  315   	/**
  316   	 * Retreive the number of columns represented by this type.
  317   	 *
  318   	 * @param type The type.
  319   	 * @return The number of columns.
  320   	 */
  321   	public int getColumnSpan(Type type) {
  322   		return type.getColumnSpan( sfi );
  323   	}
  324   
  325   	/**
  326   	 * Given a collection type, determine the entity name of the elements
  327   	 * contained within instance of that collection.
  328   	 *
  329   	 * @param collectionType The collection type to check.
  330   	 * @return The entity name of the elements of this collection.
  331   	 */
  332   	public String getAssociatedEntityName(CollectionType collectionType) {
  333   		return collectionType.getAssociatedEntityName( sfi );
  334   	}
  335   
  336   	/**
  337   	 * Given a collection type, determine the Type representing elements
  338   	 * within instances of that collection.
  339   	 *
  340   	 * @param collectionType The collection type to be checked.
  341   	 * @return The Type of the elements of the collection.
  342   	 */
  343   	private Type getElementType(CollectionType collectionType) {
  344   		return collectionType.getElementType( sfi );
  345   	}
  346   
  347   	/**
  348   	 * Essentially the same as {@link #getElementType}, but requiring that the
  349   	 * element type be an association type.
  350   	 *
  351   	 * @param collectionType The collection type to be checked.
  352   	 * @return The AssociationType of the elements of the collection.
  353   	 */
  354   	public AssociationType getElementAssociationType(CollectionType collectionType) {
  355   		return ( AssociationType ) getElementType( collectionType );
  356   	}
  357   
  358   	/**
  359   	 * Locate a registered sql function by name.
  360   	 *
  361   	 * @param functionName The name of the function to locate
  362   	 * @return The sql function, or null if not found.
  363   	 */
  364   	public SQLFunction findSQLFunction(String functionName) {
  365   		return sfi.getSqlFunctionRegistry().findSQLFunction( functionName.toLowerCase() );
  366   	}
  367   
  368   	/**
  369   	 * Locate a registered sql function by name, requiring that such a registered function exist.
  370   	 *
  371   	 * @param functionName The name of the function to locate
  372   	 * @return The sql function.
  373   	 * @throws QueryException Indicates no matching sql functions could be found.
  374   	 */
  375   	private SQLFunction requireSQLFunction(String functionName) {
  376   		SQLFunction f = findSQLFunction( functionName );
  377   		if ( f == null ) {
  378   			throw new QueryException( "Unable to find SQL function: " + functionName );
  379   		}
  380   		return f;
  381   	}
  382   
  383   	/**
  384   	 * Find the function return type given the function name and the first argument expression node.
  385   	 *
  386   	 * @param functionName The function name.
  387   	 * @param first        The first argument expression.
  388   	 * @return the function return type given the function name and the first argument expression node.
  389   	 */
  390   	public Type findFunctionReturnType(String functionName, AST first) {
  391   		// locate the registered function by the given name
  392   		SQLFunction sqlFunction = requireSQLFunction( functionName );
  393   
  394   		// determine the type of the first argument...
  395   		Type argumentType = null;
  396   		if ( first != null ) {
  397   			if ( "cast".equals(functionName) ) {
  398   				argumentType = TypeFactory.heuristicType( first.getNextSibling().getText() );
  399   			}
  400   			else if ( first instanceof SqlNode ) {
  401   				argumentType = ( (SqlNode) first ).getDataType();
  402   			}
  403   		}
  404   
  405   		return sqlFunction.getReturnType( argumentType, sfi );
  406   	}
  407   
  408   	public String[][] generateColumnNames(Type[] sqlResultTypes) {
  409   		return NameGenerator.generateColumnNames( sqlResultTypes, sfi );
  410   	}
  411   
  412   	public boolean isStrictJPAQLComplianceEnabled() {
  413   		return sfi.getSettings().isStrictJPAQLCompliance();
  414   	}
  415   }

Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » hql » ast » util » [javadoc | source]