KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > hql > QuerySplitter


1 //$Id: QuerySplitter.java,v 1.5 2005/05/23 19:54:12 oneovthafew Exp $
2
package org.hibernate.hql;
3
4 import org.apache.commons.logging.Log;
5 import org.apache.commons.logging.LogFactory;
6 import org.hibernate.MappingException;
7 import org.hibernate.engine.SessionFactoryImplementor;
8 import org.hibernate.hql.classic.ParserHelper;
9 import org.hibernate.util.StringHelper;
10
11 import java.util.ArrayList JavaDoc;
12 import java.util.HashSet JavaDoc;
13 import java.util.Set JavaDoc;
14
15 /**
16  * Provides query splitting methods, which were originally in QueryTranslator.
17  * <br>
18  * TODO: This will need to be refactored at some point.
19  *
20  * @author josh Mar 14, 2004 10:50:23 AM
21  */

22 public final class QuerySplitter {
23
24     private static final Log log = LogFactory.getLog( QuerySplitter.class );
25
26     private static final Set JavaDoc BEFORE_CLASS_TOKENS = new HashSet JavaDoc();
27     private static final Set JavaDoc NOT_AFTER_CLASS_TOKENS = new HashSet JavaDoc();
28
29     static {
30         BEFORE_CLASS_TOKENS.add( "from" );
31         //beforeClassTokens.add("new"); DEFINITELY DON'T HAVE THIS!!
32
BEFORE_CLASS_TOKENS.add( "," );
33         NOT_AFTER_CLASS_TOKENS.add( "in" );
34         //notAfterClassTokens.add(",");
35
NOT_AFTER_CLASS_TOKENS.add( "from" );
36         NOT_AFTER_CLASS_TOKENS.add( ")" );
37     }
38
39     /**
40      * Private empty constructor.
41      * (or else checkstyle says: 'warning: Utility classes should not have a public or default constructor.')
42      */

43     private QuerySplitter() {
44     }
45
46     /**
47      * Handle Hibernate "implicit" polymorphism, by translating the query string into
48      * several "concrete" queries against mapped classes.
49      */

50     public static String JavaDoc[] concreteQueries(String JavaDoc query, SessionFactoryImplementor factory) throws MappingException {
51
52         //scan the query string for class names appearing in the from clause and replace
53
//with all persistent implementors of the class/interface, returning multiple
54
//query strings (make sure we don't pick up a class in the select clause!)
55

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

58         String JavaDoc[] tokens = StringHelper.split( StringHelper.WHITESPACE + "(),", query, true );
59         if ( tokens.length == 0 ) return new String JavaDoc[]{query}; // just especially for the trivial collection filter
60
ArrayList JavaDoc placeholders = new ArrayList JavaDoc();
61         ArrayList JavaDoc replacements = new ArrayList JavaDoc();
62         StringBuffer JavaDoc templateQuery = new StringBuffer JavaDoc( 40 );
63         int count = 0;
64         String JavaDoc last = null;
65         int nextIndex = 0;
66         String JavaDoc next = null;
67         boolean isSelectClause = false;
68
69         templateQuery.append( tokens[0] );
70         if ( "select".equals( tokens[0].toLowerCase() ) ) isSelectClause = true;
71         
72         for ( int i = 1; i < tokens.length; i++ ) {
73
74             //update last non-whitespace token, if necessary
75
if ( !ParserHelper.isWhitespace( tokens[i - 1] ) ) last = tokens[i - 1].toLowerCase();
76
77             // select-range is terminated by declaration of "from"
78
if ( "from".equals( tokens[i].toLowerCase() ) ) isSelectClause = false;
79
80             String JavaDoc token = tokens[i];
81             if ( !ParserHelper.isWhitespace( token ) || last == null ) {
82
83                 //scan for next non-whitespace token
84
if ( nextIndex <= i ) {
85                     for ( nextIndex = i + 1; nextIndex < tokens.length; nextIndex++ ) {
86                         next = tokens[nextIndex].toLowerCase();
87                         if ( !ParserHelper.isWhitespace( next ) ) break;
88                     }
89                 }
90
91                 boolean process = !isSelectClause &&
92                         isJavaIdentifier( token ) &&
93                         isPossiblyClassName( last, next );
94                         
95                 if (process) {
96                     String JavaDoc importedClassName = getImportedClass( token, factory );
97                     if ( importedClassName != null ) {
98                         String JavaDoc[] implementors = factory.getImplementors( importedClassName );
99                         String JavaDoc placeholder = "$clazz" + count++ + "$";
100                         if ( implementors != null ) {
101                             placeholders.add( placeholder );
102                             replacements.add( implementors );
103                         }
104                         token = placeholder; // Note this!!
105
}
106                 }
107
108             }
109
110             templateQuery.append( token );
111
112         }
113         String JavaDoc[] results = StringHelper.multiply( templateQuery.toString(), placeholders.iterator(), replacements.iterator() );
114         if ( results.length == 0 ) log.warn( "no persistent classes found for query class: " + query );
115         return results;
116     }
117
118     private static boolean isPossiblyClassName(String JavaDoc last, String JavaDoc next) {
119         return "class".equals( last ) || (
120                 BEFORE_CLASS_TOKENS.contains( last ) &&
121                 !NOT_AFTER_CLASS_TOKENS.contains( next )
122             );
123     }
124
125     private static boolean isJavaIdentifier(String JavaDoc token) {
126         return Character.isJavaIdentifierStart( token.charAt( 0 ) );
127     }
128
129     public static String JavaDoc getImportedClass(String JavaDoc name, SessionFactoryImplementor factory) {
130         return factory.getImportedClassName( name );
131     }
132 }
133
Popular Tags