KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > loader > criteria > CriteriaQueryTranslator


1 //$Id: CriteriaQueryTranslator.java,v 1.5 2005/05/31 20:24:40 oneovthafew Exp $
2
package org.hibernate.loader.criteria;
3
4 import java.util.ArrayList JavaDoc;
5 import java.util.Arrays JavaDoc;
6 import java.util.HashMap JavaDoc;
7 import java.util.HashSet JavaDoc;
8 import java.util.Iterator JavaDoc;
9 import java.util.List JavaDoc;
10 import java.util.Map JavaDoc;
11 import java.util.Set JavaDoc;
12 import java.util.StringTokenizer JavaDoc;
13
14 import org.apache.commons.collections.SequencedHashMap;
15 import org.hibernate.Criteria;
16 import org.hibernate.EntityMode;
17 import org.hibernate.HibernateException;
18 import org.hibernate.LockMode;
19 import org.hibernate.MappingException;
20 import org.hibernate.QueryException;
21 import org.hibernate.criterion.CriteriaQuery;
22 import org.hibernate.criterion.Projection;
23 import org.hibernate.engine.QueryParameters;
24 import org.hibernate.engine.RowSelection;
25 import org.hibernate.engine.SessionFactoryImplementor;
26 import org.hibernate.engine.TypedValue;
27 import org.hibernate.impl.CriteriaImpl;
28 import org.hibernate.persister.entity.Loadable;
29 import org.hibernate.persister.entity.PropertyMapping;
30 import org.hibernate.persister.entity.Queryable;
31 import org.hibernate.type.AssociationType;
32 import org.hibernate.type.Type;
33 import org.hibernate.util.ArrayHelper;
34 import org.hibernate.util.StringHelper;
35
36 /**
37  * @author Gavin King
38  */

39 public class CriteriaQueryTranslator implements CriteriaQuery {
40     
41     public static final String JavaDoc ROOT_SQL_ALIAS = Criteria.ROOT_ALIAS + '_';
42     
43     private CriteriaQuery outerQueryTranslator;
44     
45     private final CriteriaImpl rootCriteria;
46     private final String JavaDoc rootEntityName;
47     private final String JavaDoc rootSQLAlias;
48     private int aliasCount = 0;
49     
50     private final Map JavaDoc criteriaEntityNames = new SequencedHashMap();
51     private final Map JavaDoc criteriaSQLAliasMap = new HashMap JavaDoc();
52     private final Map JavaDoc aliasCriteriaMap = new HashMap JavaDoc();
53     private final Map JavaDoc associationPathCriteriaMap = new SequencedHashMap();
54         
55     private final SessionFactoryImplementor sessionFactory;
56     
57     public CriteriaQueryTranslator(
58             final SessionFactoryImplementor factory,
59             final CriteriaImpl criteria,
60             final String JavaDoc rootEntityName,
61             final String JavaDoc rootSQLAlias,
62             CriteriaQuery outerQuery)
63     throws HibernateException {
64         this(factory, criteria, rootEntityName, rootSQLAlias);
65         outerQueryTranslator = outerQuery;
66     }
67     public CriteriaQueryTranslator(
68             final SessionFactoryImplementor factory,
69             final CriteriaImpl criteria,
70             final String JavaDoc rootEntityName,
71             final String JavaDoc rootSQLAlias)
72         throws HibernateException {
73         
74         this.rootCriteria = criteria;
75         this.rootEntityName = rootEntityName;
76         this.sessionFactory = factory;
77         this.rootSQLAlias = rootSQLAlias;
78         
79         createAliasCriteriaMap();
80         createAssociationPathCriteriaMap();
81         createCriteriaEntityNameMap();
82         createCriteriaSQLAliasMap();
83                 
84     }
85     
86     public String JavaDoc generateSQLAlias() {
87         return StringHelper.generateAlias(Criteria.ROOT_ALIAS, aliasCount) + '_';
88     }
89     
90     public String JavaDoc getRootSQLALias() {
91         return rootSQLAlias;
92     }
93     
94     private Criteria getAliasedCriteria(String JavaDoc alias) {
95         return (Criteria) aliasCriteriaMap.get(alias);
96     }
97     
98     public boolean isJoin(String JavaDoc path) {
99         return associationPathCriteriaMap.containsKey(path);
100     }
101     
102     public Criteria getCriteria(String JavaDoc path) {
103         return (Criteria) associationPathCriteriaMap.get(path);
104     }
105     
106     public Set JavaDoc getQuerySpaces() {
107         Set JavaDoc result = new HashSet JavaDoc();
108         Iterator JavaDoc iter = criteriaEntityNames.values().iterator();
109         while ( iter.hasNext() ) {
110             String JavaDoc entityName = (String JavaDoc) iter.next();
111             result.addAll( Arrays.asList( getFactory().getEntityPersister(entityName).getQuerySpaces() ) );
112         }
113         return result;
114         
115     }
116     
117     private void createAliasCriteriaMap() {
118         aliasCriteriaMap.put( rootCriteria.getAlias(), rootCriteria );
119         Iterator JavaDoc iter = rootCriteria.iterateSubcriteria();
120         while ( iter.hasNext() ) {
121             Criteria subcriteria = (Criteria) iter.next();
122             if ( subcriteria.getAlias()!=null ) {
123                 Object JavaDoc old = aliasCriteriaMap.put( subcriteria.getAlias(), subcriteria );
124                 if (old!=null) {
125                     throw new QueryException("duplicate alias: " + subcriteria.getAlias() );
126                 }
127             }
128         }
129     }
130     
131     private void createAssociationPathCriteriaMap() {
132         Iterator JavaDoc iter = rootCriteria.iterateSubcriteria();
133         while ( iter.hasNext() ) {
134             CriteriaImpl.Subcriteria crit = (CriteriaImpl.Subcriteria) iter.next();
135             String JavaDoc wholeAssociationPath = getWholeAssociationPath(crit);
136             Object JavaDoc old = associationPathCriteriaMap.put( wholeAssociationPath, crit );
137             if (old!=null) {
138                 throw new QueryException("duplicate association path: " + wholeAssociationPath );
139             }
140         }
141     }
142     
143     private String JavaDoc getWholeAssociationPath(CriteriaImpl.Subcriteria subcriteria) {
144         String JavaDoc path = subcriteria.getPath();
145         
146         // some messy, complex stuff here, since createCriteria() can take an
147
// aliased path, or a path rooted at the creating criteria instance
148
Criteria parent = null;
149         if ( path.indexOf('.')>0 ) { //if it is a compound path
150
String JavaDoc testAlias = StringHelper.root(path);
151             if ( !testAlias.equals( subcriteria.getAlias() ) ) { //and the qualifier is not the alias of this criteria
152
parent = (Criteria) aliasCriteriaMap.get(testAlias); //check to see if we belong to some criteria other than the one that created us
153
}
154         }
155         if (parent==null) {
156             parent = subcriteria.getParent(); //otherwise assume the parent is the the criteria that created us
157
}
158         else {
159             path = StringHelper.unroot(path);
160         }
161         
162         if ( parent.equals(rootCriteria) ) { //if its the root criteria, we are done
163
return path;
164         }
165         else {
166             return getWholeAssociationPath( (CriteriaImpl.Subcriteria) parent ) + '.' + path; //otherwise, recurse
167
}
168     }
169     
170     private void createCriteriaEntityNameMap() {
171         criteriaEntityNames.put(rootCriteria, rootEntityName);
172         Iterator JavaDoc iter = associationPathCriteriaMap.entrySet().iterator();
173         while ( iter.hasNext() ) {
174             Map.Entry JavaDoc me = (Map.Entry JavaDoc) iter.next();
175             criteriaEntityNames.put(
176                     me.getValue(), //the criteria instance
177
getPathEntityName( (String JavaDoc) me.getKey() )
178             );
179         }
180     }
181     
182     private String JavaDoc getPathEntityName(String JavaDoc path) {
183         Queryable persister = (Queryable) sessionFactory.getEntityPersister(rootEntityName);
184         StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(path, ".");
185         String JavaDoc componentPath = "";
186         while ( tokens.hasMoreTokens() ) {
187             componentPath += tokens.nextToken();
188             Type type = persister.toType(componentPath);
189             if ( type.isAssociationType() ) {
190                 AssociationType atype = (AssociationType) type;
191                 persister = (Queryable) sessionFactory.getEntityPersister( atype.getAssociatedEntityName(sessionFactory) );
192                 componentPath = "";
193             }
194             else if ( type.isComponentType() ) {
195                 componentPath += '.';
196             }
197             else {
198                 throw new QueryException("not an association: " + componentPath);
199             }
200         }
201         return persister.getEntityName();
202     }
203     
204     public int getSQLAliasCount() {
205         return criteriaSQLAliasMap.size();
206     }
207     
208     private void createCriteriaSQLAliasMap() {
209         int i=0;
210         Iterator JavaDoc criteriaIterator = criteriaEntityNames.entrySet().iterator();
211         while ( criteriaIterator.hasNext() ) {
212             Map.Entry JavaDoc me = (Map.Entry JavaDoc) criteriaIterator.next();
213             Criteria crit = (Criteria) me.getKey();
214             String JavaDoc alias = crit.getAlias();
215             if (alias==null) alias = (String JavaDoc) me.getValue(); // the entity name
216
criteriaSQLAliasMap.put( crit, StringHelper.generateAlias(alias, i++) );
217         }
218         criteriaSQLAliasMap.put( rootCriteria, rootSQLAlias );
219     }
220     
221     public CriteriaImpl getRootCriteria() {
222         return rootCriteria;
223     }
224     
225     public QueryParameters getQueryParameters() {
226         List JavaDoc values = new ArrayList JavaDoc();
227         List JavaDoc types = new ArrayList JavaDoc();
228         Iterator JavaDoc iter = rootCriteria.iterateExpressionEntries();
229         while ( iter.hasNext() ) {
230             CriteriaImpl.CriterionEntry ce = (CriteriaImpl.CriterionEntry) iter.next();
231             TypedValue[] tv = ce.getCriterion().getTypedValues( ce.getCriteria(), this );
232             for ( int i=0; i<tv.length; i++ ) {
233                 values.add( tv[i].getValue() );
234                 types.add( tv[i].getType() );
235             }
236         }
237         Object JavaDoc[] valueArray = values.toArray();
238         Type[] typeArray = ArrayHelper.toTypeArray(types);
239         
240         RowSelection selection = new RowSelection();
241         selection.setFirstRow( rootCriteria.getFirstResult() );
242         selection.setMaxRows( rootCriteria.getMaxResults() );
243         selection.setTimeout( rootCriteria.getTimeout() );
244         selection.setFetchSize( rootCriteria.getFetchSize() );
245         
246         Map JavaDoc lockModes = new HashMap JavaDoc();
247         iter = rootCriteria.getLockModes().entrySet().iterator();
248         while ( iter.hasNext() ) {
249             Map.Entry JavaDoc me = (Map.Entry JavaDoc) iter.next();
250             final Criteria subcriteria = getAliasedCriteria( (String JavaDoc) me.getKey() );
251             lockModes.put( getSQLAlias(subcriteria), me.getValue() );
252         }
253         iter = rootCriteria.iterateSubcriteria();
254         while ( iter.hasNext() ) {
255             CriteriaImpl.Subcriteria subcriteria = (CriteriaImpl.Subcriteria) iter.next();
256             LockMode lm = subcriteria.getLockMode();
257             if (lm!=null) lockModes.put( getSQLAlias(subcriteria), lm );
258         }
259         
260         return new QueryParameters(
261             typeArray,
262             valueArray,
263             lockModes,
264             selection,
265             rootCriteria.getCacheable(),
266             rootCriteria.getCacheRegion(),
267             //criteria.isForceCacheRefresh(),
268
rootCriteria.getComment(),
269             rootCriteria.isLookupByNaturalKey()
270         );
271     }
272     
273     public boolean hasProjection() {
274         return rootCriteria.getProjection()!=null;
275     }
276     
277     public String JavaDoc getGroupBy() {
278         /*String[] aliases = rootCriteria.getProjection().getGroupColumnAliases(0);
279         return StringHelper.join(", ", aliases);*/

280         if ( rootCriteria.getProjection().isGrouped() ) {
281             return rootCriteria.getProjection()
282                 .toGroupSqlString( rootCriteria.getProjectionCriteria(), this );
283         }
284         else {
285             return "";
286         }
287     }
288     
289     public String JavaDoc getSelect() {
290         return rootCriteria.getProjection().toSqlString(
291                 rootCriteria.getProjectionCriteria(),
292                 0,
293                 this
294         );
295     }
296     
297     public Type[] getProjectedTypes() {
298         return rootCriteria.getProjection().getTypes(rootCriteria, this);
299     }
300
301     public String JavaDoc[] getProjectedColumnAliases() {
302         return rootCriteria.getProjection().getColumnAliases(0);
303     }
304     
305     public String JavaDoc[] getProjectedAliases() {
306         return rootCriteria.getProjection().getAliases();
307     }
308     
309     public String JavaDoc getWhereCondition() {
310         StringBuffer JavaDoc condition = new StringBuffer JavaDoc(30);
311         Iterator JavaDoc criterionIterator = rootCriteria.iterateExpressionEntries();
312         while ( criterionIterator.hasNext() ) {
313             CriteriaImpl.CriterionEntry entry = (CriteriaImpl.CriterionEntry) criterionIterator.next();
314             String JavaDoc sqlString = entry.getCriterion().toSqlString( entry.getCriteria(), this );
315             condition.append(sqlString);
316             if ( criterionIterator.hasNext() ) condition.append(" and ");
317         }
318         return condition.toString();
319     }
320     
321     public String JavaDoc getOrderBy() {
322         StringBuffer JavaDoc orderBy = new StringBuffer JavaDoc(30);
323         Iterator JavaDoc criterionIterator = rootCriteria.iterateOrderings();
324         while ( criterionIterator.hasNext() ) {
325             CriteriaImpl.OrderEntry oe = (CriteriaImpl.OrderEntry) criterionIterator.next();
326             orderBy.append( oe.getOrder().toSqlString( oe.getCriteria() , this ) );
327             if ( criterionIterator.hasNext() ) orderBy.append(", ");
328         }
329         return orderBy.toString();
330     }
331
332     public SessionFactoryImplementor getFactory() {
333         return sessionFactory;
334     }
335     
336     public String JavaDoc getSQLAlias(Criteria criteria) {
337         return (String JavaDoc) criteriaSQLAliasMap.get(criteria);
338     }
339     
340     public String JavaDoc getEntityName(Criteria criteria) {
341         return (String JavaDoc) criteriaEntityNames.get(criteria);
342     }
343     
344     public String JavaDoc getColumn(Criteria criteria, String JavaDoc propertyName) {
345         String JavaDoc[] cols = getColumns(propertyName, criteria);
346         if (cols.length!=1) {
347             throw new QueryException("property does not map to a single column: " + propertyName);
348         }
349         return cols[0];
350     }
351
352     /**
353      * Get the names of the columns constrained
354      * by this criterion.
355      */

356     public String JavaDoc[] getColumnsUsingProjection(Criteria subcriteria, String JavaDoc propertyName)
357     throws HibernateException {
358         
359         //first look for a reference to a projection alias
360
final Projection projection = rootCriteria.getProjection();
361         String JavaDoc[] projectionColumns = projection==null ?
362                 null :
363                 projection.getColumnAliases(propertyName, 0);
364         
365         if ( projectionColumns==null ) {
366             //it does not refer to an alias of a projection,
367
//look for a property
368
try {
369                 return getColumns(propertyName, subcriteria);
370             }
371             catch (HibernateException he) {
372                 //not found in inner query , try the outer query
373
if (outerQueryTranslator!=null) {
374                     return outerQueryTranslator.getColumnsUsingProjection(subcriteria, propertyName);
375                 }
376                 else {
377                     throw he;
378                 }
379             }
380         }
381         else {
382             //it refers to an alias of a projection
383
return projectionColumns;
384         }
385     }
386     
387     public String JavaDoc[] getIdentifierColumns(Criteria subcriteria) {
388         String JavaDoc[] idcols = ( (Loadable) getPropertyMapping( getEntityName(subcriteria) ) ).getIdentifierColumnNames();
389         return StringHelper.qualify( getSQLAlias(subcriteria), idcols );
390     }
391     
392     public Type getIdentifierType(Criteria subcriteria) {
393         return ( (Loadable) getPropertyMapping( getEntityName(subcriteria) ) ).getIdentifierType();
394     }
395     
396     public TypedValue getTypedIdentifierValue(Criteria subcriteria, Object JavaDoc value) {
397         final Loadable loadable = (Loadable) getPropertyMapping( getEntityName(subcriteria) );
398         return new TypedValue(
399                 loadable.getIdentifierType(),
400                 value,
401                 EntityMode.POJO
402             );
403     }
404     
405     private String JavaDoc[] getColumns(String JavaDoc propertyName, Criteria subcriteria)
406     throws HibernateException {
407         return getPropertyMapping( getEntityName(subcriteria, propertyName) )
408             .toColumns( getSQLAlias(subcriteria, propertyName), getPropertyName(propertyName) );
409     }
410     
411     public Type getTypeUsingProjection(Criteria subcriteria, String JavaDoc propertyName)
412     throws HibernateException {
413         
414         //first look for a reference to a projection alias
415
final Projection projection = rootCriteria.getProjection();
416         Type[] projectionTypes = projection==null ?
417                 null :
418                 projection.getTypes(propertyName, subcriteria, this);
419         
420         if ( projectionTypes==null ) {
421             try {
422                 //it does not refer to an alias of a projection,
423
//look for a property
424
return getType(subcriteria, propertyName);
425             }
426             catch (HibernateException he) {
427                 //not found in inner query , try the outer query
428
if (outerQueryTranslator!=null) {
429                     return outerQueryTranslator.getType(subcriteria, propertyName);
430                 }
431                 else {
432                     throw he;
433                 }
434             }
435         }
436         else {
437             if (projectionTypes.length!=1) {
438                 //should never happen, i think
439
throw new QueryException("not a single-length projection: " + propertyName);
440             }
441             return projectionTypes[0];
442         }
443     }
444     
445     public Type getType(Criteria subcriteria, String JavaDoc propertyName)
446     throws HibernateException {
447         return getPropertyMapping( getEntityName(subcriteria, propertyName) )
448             .toType( getPropertyName(propertyName) );
449     }
450
451     /**
452      * Get the a typed value for the given property value.
453      */

454     public TypedValue getTypedValue(Criteria subcriteria, String JavaDoc propertyName, Object JavaDoc value)
455     throws HibernateException {
456         return new TypedValue(
457                 getTypeUsingProjection(subcriteria, propertyName),
458                 value,
459                 EntityMode.POJO
460             );
461     }
462
463     private PropertyMapping getPropertyMapping(String JavaDoc entityName)
464     throws MappingException {
465         return (PropertyMapping) sessionFactory.getEntityPersister(entityName);
466     }
467     
468     //TODO: use these in methods above
469

470     public String JavaDoc getEntityName(Criteria subcriteria, String JavaDoc propertyName) {
471         if ( propertyName.indexOf('.')>0 ) {
472             String JavaDoc root = StringHelper.root(propertyName);
473             Criteria crit = getAliasedCriteria(root);
474             if (crit!=null) return getEntityName(crit);
475         }
476         return getEntityName(subcriteria);
477     }
478     
479     public String JavaDoc getSQLAlias(Criteria criteria, String JavaDoc propertyName) {
480         if ( propertyName.indexOf('.')>0 ) {
481             String JavaDoc root = StringHelper.root(propertyName);
482             Criteria subcriteria = getAliasedCriteria(root);
483             if (subcriteria!=null) return getSQLAlias(subcriteria);
484         }
485         return getSQLAlias(criteria);
486     }
487     
488     public String JavaDoc getPropertyName(String JavaDoc propertyName) {
489         if ( propertyName.indexOf('.')>0 ) {
490             String JavaDoc root = StringHelper.root(propertyName);
491             Criteria crit = getAliasedCriteria(root);
492             if (crit!=null) {
493                 return propertyName.substring( root.length()+1 );
494             }
495         }
496         return propertyName;
497     }
498
499 }
500
Popular Tags