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.impl;
26
27 import java.io.Serializable;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33
34 import org.hibernate.CacheMode;
35 import org.hibernate.Criteria;
36 import org.hibernate.FetchMode;
37 import org.hibernate.FlushMode;
38 import org.hibernate.HibernateException;
39 import org.hibernate.LockMode;
40 import org.hibernate.ScrollMode;
41 import org.hibernate.ScrollableResults;
42 import org.hibernate.criterion.Criterion;
43 import org.hibernate.criterion.NaturalIdentifier;
44 import org.hibernate.criterion.Order;
45 import org.hibernate.criterion.Projection;
46 import org.hibernate.engine.SessionImplementor;
47 import org.hibernate.transform.ResultTransformer;
48 import org.hibernate.util.StringHelper;
49
50 /**
51 * Implementation of the <tt>Criteria</tt> interface
52 * @author Gavin King
53 */
54 public class CriteriaImpl implements Criteria, Serializable {
55
56 private final String entityOrClassName;
57 private transient SessionImplementor session;
58 private final String rootAlias;
59
60 private List criterionEntries = new ArrayList();
61 private List orderEntries = new ArrayList();
62 private Projection projection;
63 private Criteria projectionCriteria;
64
65 private List subcriteriaList = new ArrayList();
66
67 private Map fetchModes = new HashMap();
68 private Map lockModes = new HashMap();
69
70 private Integer maxResults;
71 private Integer firstResult;
72 private Integer timeout;
73 private Integer fetchSize;
74
75 private boolean cacheable;
76 private String cacheRegion;
77 private String comment;
78
79 private FlushMode flushMode;
80 private CacheMode cacheMode;
81 private FlushMode sessionFlushMode;
82 private CacheMode sessionCacheMode;
83
84 private ResultTransformer resultTransformer = Criteria.ROOT_ENTITY;
85
86
87 // Constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88
89 public CriteriaImpl(String entityOrClassName, SessionImplementor session) {
90 this(entityOrClassName, ROOT_ALIAS, session);
91 }
92
93 public CriteriaImpl(String entityOrClassName, String alias, SessionImplementor session) {
94 this.session = session;
95 this.entityOrClassName = entityOrClassName;
96 this.cacheable = false;
97 this.rootAlias = alias;
98 }
99
100 public String toString() {
101 return "CriteriaImpl(" +
102 entityOrClassName + ":" +
103 (rootAlias==null ? "" : rootAlias) +
104 subcriteriaList.toString() +
105 criterionEntries.toString() +
106 ( projection==null ? "" : projection.toString() ) +
107 ')';
108 }
109
110
111 // State ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112
113 public SessionImplementor getSession() {
114 return session;
115 }
116
117 public void setSession(SessionImplementor session) {
118 this.session = session;
119 }
120
121 public String getEntityOrClassName() {
122 return entityOrClassName;
123 }
124
125 public Map getLockModes() {
126 return lockModes;
127 }
128
129 public Criteria getProjectionCriteria() {
130 return projectionCriteria;
131 }
132
133 public Iterator iterateSubcriteria() {
134 return subcriteriaList.iterator();
135 }
136
137 public Iterator iterateExpressionEntries() {
138 return criterionEntries.iterator();
139 }
140
141 public Iterator iterateOrderings() {
142 return orderEntries.iterator();
143 }
144
145 public Criteria add(Criteria criteriaInst, Criterion expression) {
146 criterionEntries.add( new CriterionEntry(expression, criteriaInst) );
147 return this;
148 }
149
150
151 // Criteria impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
152
153 public String getAlias() {
154 return rootAlias;
155 }
156
157 public Projection getProjection() {
158 return projection;
159 }
160
161 public Criteria setProjection(Projection projection) {
162 this.projection = projection;
163 this.projectionCriteria = this;
164 setResultTransformer( PROJECTION );
165 return this;
166 }
167
168 public Criteria add(Criterion expression) {
169 add( this, expression );
170 return this;
171 }
172
173 public Criteria addOrder(Order ordering) {
174 orderEntries.add( new OrderEntry( ordering, this ) );
175 return this;
176 }
177
178 public FetchMode getFetchMode(String path) {
179 return (FetchMode) fetchModes.get(path);
180 }
181
182 public Criteria setFetchMode(String associationPath, FetchMode mode) {
183 fetchModes.put( associationPath, mode );
184 return this;
185 }
186
187 public Criteria setLockMode(LockMode lockMode) {
188 return setLockMode( getAlias(), lockMode );
189 }
190
191 public Criteria setLockMode(String alias, LockMode lockMode) {
192 lockModes.put( alias, lockMode );
193 return this;
194 }
195
196 public Criteria createAlias(String associationPath, String alias) {
197 return createAlias( associationPath, alias, INNER_JOIN );
198 }
199
200 public Criteria createAlias(String associationPath, String alias, int joinType) {
201 new Subcriteria( this, associationPath, alias, joinType );
202 return this;
203 }
204
205 public Criteria createCriteria(String associationPath) {
206 return createCriteria( associationPath, INNER_JOIN );
207 }
208
209 public Criteria createCriteria(String associationPath, int joinType) {
210 return new Subcriteria( this, associationPath, joinType );
211 }
212
213 public Criteria createCriteria(String associationPath, String alias) {
214 return createCriteria( associationPath, alias, INNER_JOIN );
215 }
216
217 public Criteria createCriteria(String associationPath, String alias, int joinType) {
218 return new Subcriteria( this, associationPath, alias, joinType );
219 }
220
221 public ResultTransformer getResultTransformer() {
222 return resultTransformer;
223 }
224
225 public Criteria setResultTransformer(ResultTransformer tupleMapper) {
226 this.resultTransformer = tupleMapper;
227 return this;
228 }
229
230 public Integer getMaxResults() {
231 return maxResults;
232 }
233
234 public Criteria setMaxResults(int maxResults) {
235 this.maxResults = new Integer(maxResults);
236 return this;
237 }
238
239 public Integer getFirstResult() {
240 return firstResult;
241 }
242
243 public Criteria setFirstResult(int firstResult) {
244 this.firstResult = new Integer(firstResult);
245 return this;
246 }
247
248 public Integer getFetchSize() {
249 return fetchSize;
250 }
251
252 public Criteria setFetchSize(int fetchSize) {
253 this.fetchSize = new Integer(fetchSize);
254 return this;
255 }
256
257 public Integer getTimeout() {
258 return timeout;
259 }
260
261 public Criteria setTimeout(int timeout) {
262 this.timeout = new Integer(timeout);
263 return this;
264 }
265
266 public boolean getCacheable() {
267 return this.cacheable;
268 }
269
270 public Criteria setCacheable(boolean cacheable) {
271 this.cacheable = cacheable;
272 return this;
273 }
274
275 public String getCacheRegion() {
276 return this.cacheRegion;
277 }
278
279 public Criteria setCacheRegion(String cacheRegion) {
280 this.cacheRegion = cacheRegion.trim();
281 return this;
282 }
283
284 public String getComment() {
285 return comment;
286 }
287
288 public Criteria setComment(String comment) {
289 this.comment = comment;
290 return this;
291 }
292
293 public Criteria setFlushMode(FlushMode flushMode) {
294 this.flushMode = flushMode;
295 return this;
296 }
297
298 public Criteria setCacheMode(CacheMode cacheMode) {
299 this.cacheMode = cacheMode;
300 return this;
301 }
302
303 public List list() throws HibernateException {
304 before();
305 try {
306 return session.list( this );
307 }
308 finally {
309 after();
310 }
311 }
312
313 public ScrollableResults scroll() {
314 return scroll( ScrollMode.SCROLL_INSENSITIVE );
315 }
316
317 public ScrollableResults scroll(ScrollMode scrollMode) {
318 before();
319 try {
320 return session.scroll(this, scrollMode);
321 }
322 finally {
323 after();
324 }
325 }
326
327 public Object uniqueResult() throws HibernateException {
328 return AbstractQueryImpl.uniqueElement( list() );
329 }
330
331 protected void before() {
332 if ( flushMode != null ) {
333 sessionFlushMode = getSession().getFlushMode();
334 getSession().setFlushMode( flushMode );
335 }
336 if ( cacheMode != null ) {
337 sessionCacheMode = getSession().getCacheMode();
338 getSession().setCacheMode( cacheMode );
339 }
340 }
341
342 protected void after() {
343 if ( sessionFlushMode != null ) {
344 getSession().setFlushMode( sessionFlushMode );
345 sessionFlushMode = null;
346 }
347 if ( sessionCacheMode != null ) {
348 getSession().setCacheMode( sessionCacheMode );
349 sessionCacheMode = null;
350 }
351 }
352
353 public boolean isLookupByNaturalKey() {
354 if ( projection != null ) {
355 return false;
356 }
357 if ( subcriteriaList.size() > 0 ) {
358 return false;
359 }
360 if ( criterionEntries.size() != 1 ) {
361 return false;
362 }
363 CriterionEntry ce = (CriterionEntry) criterionEntries.get(0);
364 return ce.getCriterion() instanceof NaturalIdentifier;
365 }
366
367
368 // Inner classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
369
370 public final class Subcriteria implements Criteria, Serializable {
371
372 private String alias;
373 private String path;
374 private Criteria parent;
375 private LockMode lockMode;
376 private int joinType;
377
378
379 // Constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
380
381 private Subcriteria(Criteria parent, String path, String alias, int joinType) {
382 this.alias = alias;
383 this.path = path;
384 this.parent = parent;
385 this.joinType = joinType;
386 CriteriaImpl.this.subcriteriaList.add(this);
387 }
388
389 private Subcriteria(Criteria parent, String path, int joinType) {
390 this( parent, path, null, joinType );
391 }
392
393 public String toString() {
394 return "Subcriteria(" +
395 path + ":" +
396 (alias==null ? "" : alias) +
397 ')';
398 }
399
400
401 // State ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
402
403 public String getAlias() {
404 return alias;
405 }
406
407 public void setAlias(String alias) {
408 this.alias = alias;
409 }
410
411 public String getPath() {
412 return path;
413 }
414
415 public Criteria getParent() {
416 return parent;
417 }
418
419 public LockMode getLockMode() {
420 return lockMode;
421 }
422
423 public Criteria setLockMode(LockMode lockMode) {
424 this.lockMode = lockMode;
425 return this;
426 }
427
428 public int getJoinType() {
429 return joinType;
430 }
431
432
433 // Criteria impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
434
435 public Criteria add(Criterion expression) {
436 CriteriaImpl.this.add(this, expression);
437 return this;
438 }
439
440 public Criteria addOrder(Order order) {
441 CriteriaImpl.this.orderEntries.add( new OrderEntry(order, this) );
442 return this;
443 }
444
445 public Criteria createAlias(String associationPath, String alias) {
446 return createAlias( associationPath, alias, INNER_JOIN );
447 }
448
449 public Criteria createAlias(String associationPath, String alias, int joinType) throws HibernateException {
450 new Subcriteria( this, associationPath, alias, joinType );
451 return this;
452 }
453
454 public Criteria createCriteria(String associationPath) {
455 return createCriteria( associationPath, INNER_JOIN );
456 }
457
458 public Criteria createCriteria(String associationPath, int joinType) throws HibernateException {
459 return new Subcriteria( Subcriteria.this, associationPath, joinType );
460 }
461
462 public Criteria createCriteria(String associationPath, String alias) {
463 return createCriteria( associationPath, alias, INNER_JOIN );
464 }
465
466 public Criteria createCriteria(String associationPath, String alias, int joinType) throws HibernateException {
467 return new Subcriteria( Subcriteria.this, associationPath, alias, joinType );
468 }
469
470 public Criteria setCacheable(boolean cacheable) {
471 CriteriaImpl.this.setCacheable(cacheable);
472 return this;
473 }
474
475 public Criteria setCacheRegion(String cacheRegion) {
476 CriteriaImpl.this.setCacheRegion(cacheRegion);
477 return this;
478 }
479
480 public List list() throws HibernateException {
481 return CriteriaImpl.this.list();
482 }
483
484 public ScrollableResults scroll() throws HibernateException {
485 return CriteriaImpl.this.scroll();
486 }
487
488 public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException {
489 return CriteriaImpl.this.scroll(scrollMode);
490 }
491
492 public Object uniqueResult() throws HibernateException {
493 return CriteriaImpl.this.uniqueResult();
494 }
495
496 public Criteria setFetchMode(String associationPath, FetchMode mode)
497 throws HibernateException {
498 CriteriaImpl.this.setFetchMode( StringHelper.qualify(path, associationPath), mode);
499 return this;
500 }
501
502 public Criteria setFlushMode(FlushMode flushMode) {
503 CriteriaImpl.this.setFlushMode(flushMode);
504 return this;
505 }
506
507 public Criteria setCacheMode(CacheMode cacheMode) {
508 CriteriaImpl.this.setCacheMode(cacheMode);
509 return this;
510 }
511
512 public Criteria setFirstResult(int firstResult) {
513 CriteriaImpl.this.setFirstResult(firstResult);
514 return this;
515 }
516
517 public Criteria setMaxResults(int maxResults) {
518 CriteriaImpl.this.setMaxResults(maxResults);
519 return this;
520 }
521
522 public Criteria setTimeout(int timeout) {
523 CriteriaImpl.this.setTimeout(timeout);
524 return this;
525 }
526
527 public Criteria setFetchSize(int fetchSize) {
528 CriteriaImpl.this.setFetchSize(fetchSize);
529 return this;
530 }
531
532 public Criteria setLockMode(String alias, LockMode lockMode) {
533 CriteriaImpl.this.setLockMode(alias, lockMode);
534 return this;
535 }
536
537 public Criteria setResultTransformer(ResultTransformer resultProcessor) {
538 CriteriaImpl.this.setResultTransformer(resultProcessor);
539 return this;
540 }
541
542 public Criteria setComment(String comment) {
543 CriteriaImpl.this.setComment(comment);
544 return this;
545 }
546
547 public Criteria setProjection(Projection projection) {
548 CriteriaImpl.this.projection = projection;
549 CriteriaImpl.this.projectionCriteria = this;
550 setResultTransformer(PROJECTION);
551 return this;
552 }
553 }
554
555 public static final class CriterionEntry implements Serializable {
556 private final Criterion criterion;
557 private final Criteria criteria;
558
559 private CriterionEntry(Criterion criterion, Criteria criteria) {
560 this.criteria = criteria;
561 this.criterion = criterion;
562 }
563
564 public Criterion getCriterion() {
565 return criterion;
566 }
567
568 public Criteria getCriteria() {
569 return criteria;
570 }
571
572 public String toString() {
573 return criterion.toString();
574 }
575 }
576
577 public static final class OrderEntry implements Serializable {
578 private final Order order;
579 private final Criteria criteria;
580
581 private OrderEntry(Order order, Criteria criteria) {
582 this.criteria = criteria;
583 this.order = order;
584 }
585
586 public Order getOrder() {
587 return order;
588 }
589
590 public Criteria getCriteria() {
591 return criteria;
592 }
593
594 public String toString() {
595 return order.toString();
596 }
597 }
598 }