FileDocCategorySizeDatePackage
QuerySplitter.javaAPI DocHibernate 3.2.54599Mon Jul 25 02:37:14 BST 2005org.hibernate.hql

QuerySplitter

public final class QuerySplitter extends Object
Provides query splitting methods, which were originally in QueryTranslator.
TODO: This will need to be refactored at some point.
author
josh Mar 14, 2004 10:50:23 AM

Fields Summary
private static final Log
log
private static final Set
BEFORE_CLASS_TOKENS
private static final Set
NOT_AFTER_CLASS_TOKENS
Constructors Summary
private QuerySplitter()
Private empty constructor. (or else checkstyle says: 'warning: Utility classes should not have a public or default constructor.')


	 
		BEFORE_CLASS_TOKENS.add( "from" );
		BEFORE_CLASS_TOKENS.add( "delete" );
		BEFORE_CLASS_TOKENS.add( "update" );
		//beforeClassTokens.add("new"); DEFINITELY DON'T HAVE THIS!!
		BEFORE_CLASS_TOKENS.add( "," );
		NOT_AFTER_CLASS_TOKENS.add( "in" );
		//notAfterClassTokens.add(",");
		NOT_AFTER_CLASS_TOKENS.add( "from" );
		NOT_AFTER_CLASS_TOKENS.add( ")" );
	
	
Methods Summary
public static java.lang.String[]concreteQueries(java.lang.String query, org.hibernate.engine.SessionFactoryImplementor factory)
Handle Hibernate "implicit" polymorphism, by translating the query string into several "concrete" queries against mapped classes.


		//scan the query string for class names appearing in the from clause and replace
		//with all persistent implementors of the class/interface, returning multiple
		//query strings (make sure we don't pick up a class in the select clause!)

		//TODO: this is one of the ugliest and most fragile pieces of code in Hibernate....

		String[] tokens = StringHelper.split( StringHelper.WHITESPACE + "(),", query, true );
		if ( tokens.length == 0 ) return new String[]{query}; // just especially for the trivial collection filter
		ArrayList placeholders = new ArrayList();
		ArrayList replacements = new ArrayList();
		StringBuffer templateQuery = new StringBuffer( 40 );
		int count = 0;
		String last = null;
		int nextIndex = 0;
		String next = null;
		boolean isSelectClause = false;

		templateQuery.append( tokens[0] );
		if ( "select".equals( tokens[0].toLowerCase() ) ) isSelectClause = true;
        
		for ( int i = 1; i < tokens.length; i++ ) {

			//update last non-whitespace token, if necessary
			if ( !ParserHelper.isWhitespace( tokens[i - 1] ) ) last = tokens[i - 1].toLowerCase();

			// select-range is terminated by declaration of "from"
			if ( "from".equals( tokens[i].toLowerCase() ) ) isSelectClause = false;

			String token = tokens[i];
			if ( !ParserHelper.isWhitespace( token ) || last == null ) {

				//scan for next non-whitespace token
				if ( nextIndex <= i ) {
					for ( nextIndex = i + 1; nextIndex < tokens.length; nextIndex++ ) {
						next = tokens[nextIndex].toLowerCase();
						if ( !ParserHelper.isWhitespace( next ) ) break;
					}
				}

				boolean process = !isSelectClause && 
						isJavaIdentifier( token ) && 
						isPossiblyClassName( last, next );
						
				if (process) {
					String importedClassName = getImportedClass( token, factory );
					if ( importedClassName != null ) {
						String[] implementors = factory.getImplementors( importedClassName );
						String placeholder = "$clazz" + count++ + "$";
						if ( implementors != null ) {
							placeholders.add( placeholder );
							replacements.add( implementors );
						}
						token = placeholder; // Note this!!
					}
				}

			}

			templateQuery.append( token );

		}
		String[] results = StringHelper.multiply( templateQuery.toString(), placeholders.iterator(), replacements.iterator() );
		if ( results.length == 0 ) log.warn( "no persistent classes found for query class: " + query );
		return results;
	
public static java.lang.StringgetImportedClass(java.lang.String name, org.hibernate.engine.SessionFactoryImplementor factory)

		return factory.getImportedClassName( name );
	
private static booleanisJavaIdentifier(java.lang.String token)

		return Character.isJavaIdentifierStart( token.charAt( 0 ) );
	
private static booleanisPossiblyClassName(java.lang.String last, java.lang.String next)

		return "class".equals( last ) || ( 
				BEFORE_CLASS_TOKENS.contains( last ) && 
				!NOT_AFTER_CLASS_TOKENS.contains( next ) 
			);