1 package org.hibernate.loader.criteria; 3 4 import java.util.ArrayList ; 5 import java.util.Arrays ; 6 import java.util.HashMap ; 7 import java.util.HashSet ; 8 import java.util.Iterator ; 9 import java.util.List ; 10 import java.util.Map ; 11 import java.util.Set ; 12 import java.util.StringTokenizer ; 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 39 public class CriteriaQueryTranslator implements CriteriaQuery { 40 41 public static final String ROOT_SQL_ALIAS = Criteria.ROOT_ALIAS + '_'; 42 43 private CriteriaQuery outerQueryTranslator; 44 45 private final CriteriaImpl rootCriteria; 46 private final String rootEntityName; 47 private final String rootSQLAlias; 48 private int aliasCount = 0; 49 50 private final Map criteriaEntityNames = new SequencedHashMap(); 51 private final Map criteriaSQLAliasMap = new HashMap (); 52 private final Map aliasCriteriaMap = new HashMap (); 53 private final Map associationPathCriteriaMap = new SequencedHashMap(); 54 55 private final SessionFactoryImplementor sessionFactory; 56 57 public CriteriaQueryTranslator( 58 final SessionFactoryImplementor factory, 59 final CriteriaImpl criteria, 60 final String rootEntityName, 61 final String 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 rootEntityName, 71 final String 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 generateSQLAlias() { 87 return StringHelper.generateAlias(Criteria.ROOT_ALIAS, aliasCount) + '_'; 88 } 89 90 public String getRootSQLALias() { 91 return rootSQLAlias; 92 } 93 94 private Criteria getAliasedCriteria(String alias) { 95 return (Criteria) aliasCriteriaMap.get(alias); 96 } 97 98 public boolean isJoin(String path) { 99 return associationPathCriteriaMap.containsKey(path); 100 } 101 102 public Criteria getCriteria(String path) { 103 return (Criteria) associationPathCriteriaMap.get(path); 104 } 105 106 public Set getQuerySpaces() { 107 Set result = new HashSet (); 108 Iterator iter = criteriaEntityNames.values().iterator(); 109 while ( iter.hasNext() ) { 110 String entityName = (String ) 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 iter = rootCriteria.iterateSubcriteria(); 120 while ( iter.hasNext() ) { 121 Criteria subcriteria = (Criteria) iter.next(); 122 if ( subcriteria.getAlias()!=null ) { 123 Object 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 iter = rootCriteria.iterateSubcriteria(); 133 while ( iter.hasNext() ) { 134 CriteriaImpl.Subcriteria crit = (CriteriaImpl.Subcriteria) iter.next(); 135 String wholeAssociationPath = getWholeAssociationPath(crit); 136 Object old = associationPathCriteriaMap.put( wholeAssociationPath, crit ); 137 if (old!=null) { 138 throw new QueryException("duplicate association path: " + wholeAssociationPath ); 139 } 140 } 141 } 142 143 private String getWholeAssociationPath(CriteriaImpl.Subcriteria subcriteria) { 144 String path = subcriteria.getPath(); 145 146 Criteria parent = null; 149 if ( path.indexOf('.')>0 ) { String testAlias = StringHelper.root(path); 151 if ( !testAlias.equals( subcriteria.getAlias() ) ) { parent = (Criteria) aliasCriteriaMap.get(testAlias); } 154 } 155 if (parent==null) { 156 parent = subcriteria.getParent(); } 158 else { 159 path = StringHelper.unroot(path); 160 } 161 162 if ( parent.equals(rootCriteria) ) { return path; 164 } 165 else { 166 return getWholeAssociationPath( (CriteriaImpl.Subcriteria) parent ) + '.' + path; } 168 } 169 170 private void createCriteriaEntityNameMap() { 171 criteriaEntityNames.put(rootCriteria, rootEntityName); 172 Iterator iter = associationPathCriteriaMap.entrySet().iterator(); 173 while ( iter.hasNext() ) { 174 Map.Entry me = (Map.Entry ) iter.next(); 175 criteriaEntityNames.put( 176 me.getValue(), getPathEntityName( (String ) me.getKey() ) 178 ); 179 } 180 } 181 182 private String getPathEntityName(String path) { 183 Queryable persister = (Queryable) sessionFactory.getEntityPersister(rootEntityName); 184 StringTokenizer tokens = new StringTokenizer (path, "."); 185 String 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 criteriaIterator = criteriaEntityNames.entrySet().iterator(); 211 while ( criteriaIterator.hasNext() ) { 212 Map.Entry me = (Map.Entry ) criteriaIterator.next(); 213 Criteria crit = (Criteria) me.getKey(); 214 String alias = crit.getAlias(); 215 if (alias==null) alias = (String ) me.getValue(); 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 values = new ArrayList (); 227 List types = new ArrayList (); 228 Iterator 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 [] 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 lockModes = new HashMap (); 247 iter = rootCriteria.getLockModes().entrySet().iterator(); 248 while ( iter.hasNext() ) { 249 Map.Entry me = (Map.Entry ) iter.next(); 250 final Criteria subcriteria = getAliasedCriteria( (String ) 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 rootCriteria.getComment(), 269 rootCriteria.isLookupByNaturalKey() 270 ); 271 } 272 273 public boolean hasProjection() { 274 return rootCriteria.getProjection()!=null; 275 } 276 277 public String getGroupBy() { 278 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 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 [] getProjectedColumnAliases() { 302 return rootCriteria.getProjection().getColumnAliases(0); 303 } 304 305 public String [] getProjectedAliases() { 306 return rootCriteria.getProjection().getAliases(); 307 } 308 309 public String getWhereCondition() { 310 StringBuffer condition = new StringBuffer (30); 311 Iterator criterionIterator = rootCriteria.iterateExpressionEntries(); 312 while ( criterionIterator.hasNext() ) { 313 CriteriaImpl.CriterionEntry entry = (CriteriaImpl.CriterionEntry) criterionIterator.next(); 314 String 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 getOrderBy() { 322 StringBuffer orderBy = new StringBuffer (30); 323 Iterator 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 getSQLAlias(Criteria criteria) { 337 return (String ) criteriaSQLAliasMap.get(criteria); 338 } 339 340 public String getEntityName(Criteria criteria) { 341 return (String ) criteriaEntityNames.get(criteria); 342 } 343 344 public String getColumn(Criteria criteria, String propertyName) { 345 String [] 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 356 public String [] getColumnsUsingProjection(Criteria subcriteria, String propertyName) 357 throws HibernateException { 358 359 final Projection projection = rootCriteria.getProjection(); 361 String [] projectionColumns = projection==null ? 362 null : 363 projection.getColumnAliases(propertyName, 0); 364 365 if ( projectionColumns==null ) { 366 try { 369 return getColumns(propertyName, subcriteria); 370 } 371 catch (HibernateException he) { 372 if (outerQueryTranslator!=null) { 374 return outerQueryTranslator.getColumnsUsingProjection(subcriteria, propertyName); 375 } 376 else { 377 throw he; 378 } 379 } 380 } 381 else { 382 return projectionColumns; 384 } 385 } 386 387 public String [] getIdentifierColumns(Criteria subcriteria) { 388 String [] 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 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 [] getColumns(String 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 propertyName) 412 throws HibernateException { 413 414 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 return getType(subcriteria, propertyName); 425 } 426 catch (HibernateException he) { 427 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 throw new QueryException("not a single-length projection: " + propertyName); 440 } 441 return projectionTypes[0]; 442 } 443 } 444 445 public Type getType(Criteria subcriteria, String propertyName) 446 throws HibernateException { 447 return getPropertyMapping( getEntityName(subcriteria, propertyName) ) 448 .toType( getPropertyName(propertyName) ); 449 } 450 451 454 public TypedValue getTypedValue(Criteria subcriteria, String propertyName, Object 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 entityName) 464 throws MappingException { 465 return (PropertyMapping) sessionFactory.getEntityPersister(entityName); 466 } 467 468 470 public String getEntityName(Criteria subcriteria, String propertyName) { 471 if ( propertyName.indexOf('.')>0 ) { 472 String 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 getSQLAlias(Criteria criteria, String propertyName) { 480 if ( propertyName.indexOf('.')>0 ) { 481 String 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 getPropertyName(String propertyName) { 489 if ( propertyName.indexOf('.')>0 ) { 490 String 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 |