1 package org.apache.ojb.broker.query;
2
3 /* Copyright 2002-2005 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Enumeration;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Vector;
26
27 import org.apache.ojb.broker.PersistenceBrokerFactory;
28 import org.apache.ojb.broker.metadata.FieldHelper;
29 import org.apache.ojb.broker.core.PersistenceBrokerConfiguration;
30 import org.apache.ojb.broker.util.configuration.ConfigurationException;
31
32 /**
33 * Persistent Criteria can be used to retrieve sets of objects based on their attributes
34 * Normally each attribute is ANDed together, an OR can be performed by creating a new
35 * PersistentCriteria and adding it.
36 * <P>
37 * Criteria are used, rather than a simple string, because they can be precompiled for
38 * efficiency.
39 *
40 * This code is based on stuff from
41 * COBRA - Java Object Persistence Layer
42 * Copyright (C) 1997, 1998 DB Harvey-George
43 * eMail: cobra@lowrent.org
44 *
45 * @author <a href="mailto:jbraeuchi@gmx.ch">Jakob Braeuchi</a>
46 * @version $Id: Criteria.java,v 1.1 2007-08-24 22:17:36 ewestfal Exp $
47 */
48 public class Criteria implements java.io.Serializable
49 {
50 static final long serialVersionUID = 7384550404778187808L;
51
52 /** criteria is OR-ed with it's parent */
53 public static final int OR = 0;
54 /** criteria is AND-ed with it's parent */
55 public static final int AND = 1;
56 /** criteria has no parent */
57 public static final int NONE = 9;
58
59 /** prefix to identify attributes referencing enclosing query */
60 public static final String PARENT_QUERY_PREFIX = "parentQuery.";
61
62 private Vector m_criteria;
63 private int m_type;
64 private boolean m_embraced;
65 private boolean m_negative = false;
66
67 // holding CriteriaFields for orderBy and groupBy
68 private List orderby = null;
69 private List groupby = null;
70 private List prefetchedRelationships = null;
71
72 // an optional alias to be used for this criteria
73 private String m_alias = null;
74
75 // PAW
76 // an aliasPath to be used for this criteria
77 private String m_aliasPath = null;
78
79 // holds the path segment(s) to which the alias applies
80 private UserAlias m_userAlias = null;
81
82 /** the max. number of parameters in a IN-statement */
83 protected static final int IN_LIMIT = getSqlInLimit();
84
85 private QueryByCriteria m_query;
86 private Criteria m_parentCriteria;
87
88 // PAW
89 // hint classes for paths of this criteria
90 private Map m_pathClasses;
91
92 /**
93 * Constructor declaration
94 */
95 public Criteria()
96 {
97 m_criteria = new Vector();
98 groupby = new ArrayList();
99 orderby = new ArrayList();
100 prefetchedRelationships = new ArrayList();
101 m_type = NONE;
102 m_embraced = false;
103 // PAW
104 m_pathClasses = new HashMap();
105 }
106
107 /**
108 * Constructor with a SelectionCriteria
109 * @param aSelectionCriteria SelectionCriteria
110 */
111 public Criteria(SelectionCriteria aSelectionCriteria)
112 {
113 this();
114 addSelectionCriteria(aSelectionCriteria);
115 }
116
117 /**
118 * make a copy of the criteria
119 * @param includeGroupBy if true
120 * @param includeOrderBy if ture
121 * @param includePrefetchedRelationships if true
122 * @return a copy of the criteria
123 */
124 public Criteria copy(boolean includeGroupBy, boolean includeOrderBy, boolean includePrefetchedRelationships)
125 {
126 Criteria copy = new Criteria();
127
128 copy.m_criteria = new Vector(this.m_criteria);
129 copy.m_negative = this.m_negative;
130
131 if (includeGroupBy)
132 {
133 copy.groupby = this.groupby;
134 }
135 if (includeOrderBy)
136 {
137 copy.orderby = this.orderby;
138 }
139 if (includePrefetchedRelationships)
140 {
141 copy.prefetchedRelationships = this.prefetchedRelationships;
142 }
143
144 return copy;
145 }
146
147 protected void addSelectionCriteria(SelectionCriteria selectionCrit)
148 {
149 selectionCrit.setCriteria(this);
150 m_criteria.addElement(selectionCrit);
151 }
152
153 protected void addCriteria(Criteria crit)
154 {
155 crit.setParentCriteria(this);
156 m_criteria.addElement(crit);
157 }
158
159 protected void addCriteria(Vector criteria)
160 {
161 Object crit;
162
163 for (int i = 0; i < criteria.size(); i++)
164 {
165 crit = criteria.elementAt(i);
166 if (crit instanceof SelectionCriteria)
167 {
168 addSelectionCriteria((SelectionCriteria) crit);
169 }
170 else if (crit instanceof Criteria)
171 {
172 addCriteria((Criteria) crit);
173 }
174 }
175 }
176
177 /**
178 * Answer a List of InCriteria based on values, each InCriteria
179 * contains only inLimit values
180 * @param attribute
181 * @param values
182 * @param negative
183 * @param inLimit the maximum number of values for IN (-1 for no limit)
184 * @return List of InCriteria
185 */
186 protected List splitInCriteria(Object attribute, Collection values, boolean negative, int inLimit)
187 {
188 List result = new ArrayList();
189 Collection inCollection = new ArrayList();
190
191 if (values == null || values.isEmpty())
192 {
193 // OQL creates empty Criteria for late binding
194 result.add(buildInCriteria(attribute, negative, values));
195 }
196 else
197 {
198 Iterator iter = values.iterator();
199
200 while (iter.hasNext())
201 {
202 inCollection.add(iter.next());
203 if (inCollection.size() == inLimit || !iter.hasNext())
204 {
205 result.add(buildInCriteria(attribute, negative, inCollection));
206 inCollection = new ArrayList();
207 }
208 }
209 }
210 return result;
211 }
212
213 private InCriteria buildInCriteria(Object attribute, boolean negative, Collection values)
214 {
215 if (negative)
216 {
217 // PAW
218 // return ValueCriteria.buildNotInCriteria(attribute, values, getAlias());
219 return ValueCriteria.buildNotInCriteria(attribute, values, getUserAlias(attribute));
220 }
221 else
222 {
223 // PAW
224 // return ValueCriteria.buildInCriteria(attribute, values, getAlias());
225 return ValueCriteria.buildInCriteria(attribute, values, getUserAlias(attribute));
226 }
227 }
228
229 /**
230 * Get an Enumeration with all sub criteria
231 * @return Enumeration
232 */
233 public Enumeration getElements()
234 {
235 return getCriteria().elements();
236 }
237
238 /**
239 * Get a Vector with all sub criteria
240 * @return Vector
241 */
242 protected Vector getCriteria()
243 {
244 return m_criteria;
245 }
246
247 /**
248 * Answer the type
249 * @return int
250 */
251 public int getType()
252 {
253 return m_type;
254 }
255
256 /**
257 * Set the type
258 * @param type OR, AND, NONE
259 */
260 public void setType(int type)
261 {
262 m_type = type;
263 }
264
265 /**
266 * ANDed criteria are embraced
267 * @return true if embraced,
268 */
269 public boolean isEmbraced()
270 {
271 return m_embraced;
272 }
273
274 /**
275 * Set embraced
276 * @param embraced true if criteria is to be surrounded by braces
277 */
278 public void setEmbraced(boolean embraced)
279 {
280 m_embraced = embraced;
281 }
282
283 /**
284 * Adds and equals (=) criteria,
285 * customer_id = 10034
286 *
287 * @param attribute The field name to be used
288 * @param value An object representing the value of the field
289 */
290 public void addEqualTo(String attribute, Object value)
291 {
292 // PAW
293 // addSelectionCriteria(ValueCriteria.buildEqualToCriteria(attribute, value, getAlias()));
294 addSelectionCriteria(ValueCriteria.buildEqualToCriteria(attribute, value, getUserAlias(attribute)));
295 }
296
297 /**
298 * Adds and equals (=) criteria,
299 * CUST_ID = 10034
300 * attribute will NOT be translated into column name
301 *
302 * @param column The column name to be used without translation
303 * @param value An object representing the value of the column
304 */
305 public void addColumnEqualTo(String column, Object value)
306 {
307 // PAW
308 // SelectionCriteria c = ValueCriteria.buildEqualToCriteria(column, value, getAlias());
309 SelectionCriteria c = ValueCriteria.buildEqualToCriteria(column, value, getUserAlias(column));
310 c.setTranslateAttribute(false);
311 addSelectionCriteria(c);
312 }
313
314 /**
315 * Adds and equals (=) criteria for field comparison.
316 * The field name will be translated into the appropriate columnName by SqlStatement.
317 * The attribute will NOT be translated into column name
318 *
319 * @param column The column name to be used without translation
320 * @param fieldName An object representing the value of the field
321 */
322 public void addColumnEqualToField(String column, Object fieldName)
323 {
324 // PAW
325 //SelectionCriteria c = FieldCriteria.buildEqualToCriteria(column, fieldName, getAlias());
326 SelectionCriteria c = FieldCriteria.buildEqualToCriteria(column, fieldName, getUserAlias(column));
327 c.setTranslateAttribute(false);
328 addSelectionCriteria(c);
329 }
330
331 /**
332 * Adds and equals (=) criteria for field comparison.
333 * The field name will be translated into the appropriate columnName by SqlStatement.
334 * <br>
335 * name = boss.name
336 *
337 * @param attribute The field name to be used
338 * @param fieldName The field name to compare with
339 */
340 public void addEqualToField(String attribute, String fieldName)
341 {
342 // PAW
343 // FieldCriteria c = FieldCriteria.buildEqualToCriteria(attribute, fieldName, getAlias());
344 FieldCriteria c = FieldCriteria.buildEqualToCriteria(attribute, fieldName, getUserAlias(attribute));
345 addSelectionCriteria(c);
346 }
347
348 /**
349 * Adds and equals (=) criteria for field comparison.
350 * The field name will be translated into the appropriate columnName by SqlStatement.
351 * <br>
352 * name <> boss.name
353 *
354 * @param attribute The field name to be used
355 * @param fieldName The field name to compare with
356 */
357 public void addNotEqualToField(String attribute, String fieldName)
358 {
359 // PAW
360 // SelectionCriteria c = FieldCriteria.buildNotEqualToCriteria(attribute, fieldName, getAlias());
361 SelectionCriteria c = FieldCriteria.buildNotEqualToCriteria(attribute, fieldName, getUserAlias(attribute));
362 addSelectionCriteria(c);
363 }
364
365 /**
366 * Adds and equals (<>) criteria for column comparison.
367 * The column Name will NOT be translated.
368 * <br>
369 * name <> T_BOSS.LASTNMAE
370 *
371 * @param attribute The field name to be used
372 * @param colName The name of the column to compare with
373 */
374 public void addNotEqualToColumn(String attribute, String colName)
375 {
376 // PAW
377 // FieldCriteria c = FieldCriteria.buildNotEqualToCriteria(attribute, colName, getAlias());
378 FieldCriteria c = FieldCriteria.buildNotEqualToCriteria(attribute, colName, getUserAlias(attribute));
379 c.setTranslateField(false);
380 addSelectionCriteria(c);
381 }
382
383 /**
384 * Adds and equals (=) criteria for column comparison.
385 * The column Name will NOT be translated.
386 * <br>
387 * name = T_BOSS.LASTNMAE
388 *
389 * @param attribute The field name to be used
390 * @param colName The name of the column to compare with
391 */
392 public void addEqualToColumn(String attribute, String colName)
393 {
394 // FieldCriteria c = FieldCriteria.buildEqualToCriteria(attribute, colName, getAlias());
395 FieldCriteria c = FieldCriteria.buildEqualToCriteria(attribute, colName, getUserAlias(attribute));
396 c.setTranslateField(false);
397 addSelectionCriteria(c);
398 }
399
400 /**
401 * Adds GreaterOrEqual Than (>=) criteria,
402 * customer_id >= 10034
403 *
404 * @param attribute The field name to be used
405 * @param value An object representing the value of the field
406 */
407 public void addGreaterOrEqualThan(Object attribute, Object value)
408 {
409 // PAW
410 // addSelectionCriteria(ValueCriteria.buildNotLessCriteria(attribute, value, getAlias()));
411 addSelectionCriteria(ValueCriteria.buildNotLessCriteria(attribute, value, getUserAlias(attribute)));
412 }
413
414 /**
415 * Adds GreaterOrEqual Than (>=) criteria,
416 * customer_id >= person_id
417 *
418 * @param attribute The field name to be used
419 * @param value The field name to compare with
420 */
421 public void addGreaterOrEqualThanField(String attribute, Object value)
422 {
423 // PAW
424 // addSelectionCriteria(FieldCriteria.buildNotLessCriteria(attribute, value, getAlias()));
425 addSelectionCriteria(FieldCriteria.buildNotLessCriteria(attribute, value, getUserAlias(attribute)));
426 }
427
428 /**
429 * Adds LessOrEqual Than (<=) criteria,
430 * customer_id <= 10034
431 *
432 * @param attribute The field name to be used
433 * @param value An object representing the value of the field
434 */
435 public void addLessOrEqualThan(Object attribute, Object value)
436 {
437 // PAW
438 // addSelectionCriteria(ValueCriteria.buildNotGreaterCriteria(attribute, value, getAlias()));
439 addSelectionCriteria(ValueCriteria.buildNotGreaterCriteria(attribute, value, getUserAlias(attribute)));
440 }
441
442 /**
443 * Adds LessOrEqual Than (<=) criteria,
444 * customer_id <= person_id
445 *
446 * @param attribute The field name to be used
447 * @param value The field name to compare with
448 */
449 public void addLessOrEqualThanField(String attribute, Object value)
450 {
451 // PAW
452 // addSelectionCriteria(FieldCriteria.buildNotGreaterCriteria(attribute, value, getAlias()));
453 addSelectionCriteria(FieldCriteria.buildNotGreaterCriteria(attribute, value, getUserAlias(attribute)));
454 }
455
456 /**
457 * Adds Like (LIKE) criteria,
458 * customer_name LIKE "m%ller"
459 *
460 * @see LikeCriteria
461 * @param attribute The field name to be used
462 * @param value An object representing the value of the field
463 */
464 public void addLike(Object attribute, Object value)
465 {
466 // PAW
467 // addSelectionCriteria(ValueCriteria.buildLikeCriteria(attribute, value, getAlias()));
468 addSelectionCriteria(ValueCriteria.buildLikeCriteria(attribute, value, getUserAlias(attribute)));
469 }
470
471 /**
472 * Adds Like (NOT LIKE) criteria,
473 * customer_id NOT LIKE 10034
474 *
475 * @see LikeCriteria
476 * @param attribute The field name to be used
477 * @param value An object representing the value of the field
478 */
479 public void addNotLike(String attribute, Object value)
480 {
481 // PAW
482 // addSelectionCriteria(ValueCriteria.buildNotLikeCriteria(attribute, value, getAlias()));
483 addSelectionCriteria(ValueCriteria.buildNotLikeCriteria(attribute, value, getUserAlias(attribute)));
484 }
485
486 /**
487 * Adds NotEqualTo (<>) criteria,
488 * customer_id <> 10034
489 *
490 * @param attribute The field name to be used
491 * @param value An object representing the value of the field
492 */
493 public void addNotEqualTo(Object attribute, Object value)
494 {
495 // PAW
496 // addSelectionCriteria(ValueCriteria.buildNotEqualToCriteria(attribute, value, getAlias()));
497 addSelectionCriteria(ValueCriteria.buildNotEqualToCriteria(attribute, value, getUserAlias(attribute)));
498 }
499
500 /**
501 * Adds Greater Than (>) criteria,
502 * customer_id > 10034
503 *
504 * @param attribute The field name to be used
505 * @param value An object representing the value of the field
506 */
507 public void addGreaterThan(Object attribute, Object value)
508 {
509 // PAW
510 // addSelectionCriteria(ValueCriteria.buildGreaterCriteria(attribute, value, getAlias()));
511 addSelectionCriteria(ValueCriteria.buildGreaterCriteria(attribute, value, getUserAlias(attribute)));
512 }
513
514 /**
515 * Adds Greater Than (>) criteria,
516 * customer_id > person_id
517 *
518 * @param attribute The field name to be used
519 * @param value The field to compare with
520 */
521 public void addGreaterThanField(String attribute, Object value)
522 {
523 // PAW
524 // addSelectionCriteria(FieldCriteria.buildGreaterCriteria(attribute, value, getAlias()));
525 addSelectionCriteria(FieldCriteria.buildGreaterCriteria(attribute, value, getUserAlias(attribute)));
526 }
527
528 /**
529 * Adds Less Than (<) criteria,
530 * customer_id < 10034
531 *
532 * @param attribute The field name to be used
533 * @param value An object representing the value of the field
534 */
535 public void addLessThan(Object attribute, Object value)
536 {
537 // PAW
538 // addSelectionCriteria(ValueCriteria.buildLessCriteria(attribute, value, getAlias()));
539 addSelectionCriteria(ValueCriteria.buildLessCriteria(attribute, value, getUserAlias(attribute)));
540 }
541
542 /**
543 * Adds Less Than (<) criteria,
544 * customer_id < person_id
545 *
546 * @param attribute The field name to be used
547 * @param value The field to compare with
548 */
549 public void addLessThanField(String attribute, Object value)
550 {
551 // PAW
552 // addSelectionCriteria(FieldCriteria.buildLessCriteria(attribute, value, getAlias()));
553 addSelectionCriteria(FieldCriteria.buildLessCriteria(attribute, value, getUserAlias(attribute)));
554 }
555
556 /**
557 * Adds a field for orderBy, order is ASCENDING
558 * @param fieldName The field name to be used
559 * @deprecated use #addOrderByAscending(String fieldName)
560 */
561 public void addOrderBy(String fieldName)
562 {
563 addOrderBy(fieldName, true);
564 }
565
566 /**
567 * Adds a field for orderBy
568 * @param fieldName the field name to be used
569 * @param sortAscending true for ASCENDING, false for DESCENDING
570 * @deprecated use QueryByCriteria#addOrderBy
571 */
572 public void addOrderBy(String fieldName, boolean sortAscending)
573 {
574 if (fieldName != null)
575 {
576 _getOrderby().add(new FieldHelper(fieldName, sortAscending));
577 }
578 }
579
580 /**
581 * Adds a field for orderBy
582 * @param aField the Field
583 * @deprecated use QueryByCriteria#addOrderBy
584 */
585 public void addOrderBy(FieldHelper aField)
586 {
587 if (aField != null)
588 {
589 _getOrderby().add(aField);
590 }
591 }
592
593 /**
594 * Adds a field for orderBy ASCENDING
595 * @param fieldName The field name to be used
596 * @deprecated use QueryByCriteria#addOrderByAscending
597 */
598 public void addOrderByAscending(String fieldName)
599 {
600 addOrderBy(fieldName, true);
601 }
602
603 /**
604 * Adds a field for orderBy DESCENDING
605 * @param fieldName The field name to be used
606 * @deprecated use QueryByCriteria#addOrderByDescending
607 */
608 public void addOrderByDescending(String fieldName)
609 {
610 addOrderBy(fieldName, false);
611 }
612
613 /**
614 * Answer the orderBy of all Criteria and Sub Criteria
615 * the elements are of class Criteria.FieldHelper
616 * @return List
617 */
618 List getOrderby()
619 {
620 List result = _getOrderby();
621 Iterator iter = getCriteria().iterator();
622 Object crit;
623
624 while (iter.hasNext())
625 {
626 crit = iter.next();
627 if (crit instanceof Criteria)
628 {
629 result.addAll(((Criteria) crit).getOrderby());
630 }
631 }
632
633 return result;
634 }
635
636 /**
637 * Answer the Vector with all orderBy,
638 * the elements are of class Criteria.FieldHelper
639 * @return List
640 */
641 protected List _getOrderby()
642 {
643 return orderby;
644 }
645
646 /**
647 * ORs two sets of criteria together:
648 * <pre>
649 * active = true AND balance < 0 OR active = true AND overdraft = 0
650 * </pre>
651 * @param pc criteria
652 */
653 public void addOrCriteria(Criteria pc)
654 {
655 if (!m_criteria.isEmpty())
656 {
657 pc.setEmbraced(true);
658 pc.setType(OR);
659 addCriteria(pc);
660 }
661 else
662 {
663 setEmbraced(false);
664 pc.setType(OR);
665 addCriteria(pc);
666 }
667 }
668
669 /**
670 * Adds is Null criteria,
671 * customer_id is Null
672 *
673 * @param attribute The field name to be used
674 */
675 public void addIsNull(String attribute)
676 {
677 // PAW
678 //addSelectionCriteria(ValueCriteria.buildNullCriteria(attribute, getAlias()));
679 addSelectionCriteria(ValueCriteria.buildNullCriteria(attribute, getUserAlias(attribute)));
680 }
681
682 /**
683 * Adds is Null criteria,
684 * customer_id is Null
685 * The attribute will NOT be translated into column name
686 *
687 * @param column The column name to be used without translation
688 */
689 public void addColumnIsNull(String column)
690 {
691 // PAW
692 //SelectionCriteria c = ValueCriteria.buildNullCriteria(column, getAlias());
693 SelectionCriteria c = ValueCriteria.buildNullCriteria(column, getUserAlias(column));
694 c.setTranslateAttribute(false);
695 addSelectionCriteria(c);
696 }
697
698 /**
699 * Adds not Null criteria,
700 * customer_id is not Null
701 *
702 * @param attribute The field name to be used
703 */
704 public void addNotNull(String attribute)
705 {
706 // PAW
707 //addSelectionCriteria(ValueCriteria.buildNotNullCriteria(attribute, getAlias()));
708 addSelectionCriteria(ValueCriteria.buildNotNullCriteria(attribute, getUserAlias(attribute)));
709 }
710
711 /**
712 * Adds not Null criteria,
713 * customer_id is not Null
714 * The attribute will NOT be translated into column name
715 *
716 * @param column The column name to be used without translation
717 */
718 public void addColumnNotNull(String column)
719 {
720 // PAW
721 // SelectionCriteria c = ValueCriteria.buildNotNullCriteria(column, getAlias());
722 SelectionCriteria c = ValueCriteria.buildNotNullCriteria(column, getUserAlias(column));
723 c.setTranslateAttribute(false);
724 addSelectionCriteria(c);
725 }
726
727 /**
728 * Adds BETWEEN criteria,
729 * customer_id between 1 and 10
730 *
731 * @param attribute The field name to be used
732 * @param value1 The lower boundary
733 * @param value2 The upper boundary
734 */
735 public void addBetween(Object attribute, Object value1, Object value2)
736 {
737 // PAW
738 // addSelectionCriteria(ValueCriteria.buildBeweenCriteria(attribute, value1, value2, getAlias()));
739 addSelectionCriteria(ValueCriteria.buildBeweenCriteria(attribute, value1, value2, getUserAlias(attribute)));
740 }
741
742 /**
743 * Adds NOT BETWEEN criteria,
744 * customer_id not between 1 and 10
745 *
746 * @param attribute The field name to be used
747 * @param value1 The lower boundary
748 * @param value2 The upper boundary
749 */
750 public void addNotBetween(Object attribute, Object value1, Object value2)
751 {
752 // PAW
753 // addSelectionCriteria(ValueCriteria.buildNotBeweenCriteria(attribute, value1, value2, getAlias()));
754 addSelectionCriteria(ValueCriteria.buildNotBeweenCriteria(attribute, value1, value2, getUserAlias(attribute)));
755 }
756
757 /**
758 * Adds IN criteria,
759 * customer_id in(1,10,33,44)
760 * large values are split into multiple InCriteria
761 * IN (1,10) OR IN(33, 44)
762 *
763 * @param attribute The field name to be used
764 * @param values The value Collection
765 */
766 public void addIn(String attribute, Collection values)
767 {
768 List list = splitInCriteria(attribute, values, false, IN_LIMIT);
769 int index = 0;
770 InCriteria inCrit;
771 Criteria allInCritaria;
772
773 inCrit = (InCriteria) list.get(index);
774 allInCritaria = new Criteria(inCrit);
775
776 for (index = 1; index < list.size(); index++)
777 {
778 inCrit = (InCriteria) list.get(index);
779 allInCritaria.addOrCriteria(new Criteria(inCrit));
780 }
781
782 addAndCriteria(allInCritaria);
783 }
784
785 /**
786 * Adds IN criteria,
787 * customer_id in(1,10,33,44)
788 * large values are split into multiple InCriteria
789 * IN (1,10) OR IN(33, 44) </br>
790 * The attribute will NOT be translated into column name
791 *
792 * @param column The column name to be used without translation
793 * @param values The value Collection
794 */
795 public void addColumnIn(String column, Collection values)
796 {
797 List list = splitInCriteria(column, values, false, IN_LIMIT);
798 int index = 0;
799 InCriteria inCrit;
800 Criteria allInCritaria;
801
802 inCrit = (InCriteria) list.get(index);
803 inCrit.setTranslateAttribute(false);
804 allInCritaria = new Criteria(inCrit);
805
806 for (index = 1; index < list.size(); index++)
807 {
808 inCrit = (InCriteria) list.get(index);
809 inCrit.setTranslateAttribute(false);
810 allInCritaria.addOrCriteria(new Criteria(inCrit));
811 }
812
813 addAndCriteria(allInCritaria);
814 }
815
816 /**
817 * Adds NOT IN criteria,
818 * customer_id not in(1,10,33,44)
819 * large values are split into multiple InCriteria
820 * NOT IN (1,10) AND NOT IN(33, 44)
821 *
822 * @param attribute The field name to be used
823 * @param values The value Collection
824 */
825 public void addNotIn(String attribute, Collection values)
826 {
827 List list = splitInCriteria(attribute, values, true, IN_LIMIT);
828 InCriteria inCrit;
829 for (int index = 0; index < list.size(); index++)
830 {
831 inCrit = (InCriteria) list.get(index);
832 addSelectionCriteria(inCrit);
833 }
834 }
835
836 /**
837 * IN Criteria with SubQuery
838 * @param attribute The field name to be used
839 * @param subQuery The subQuery
840 */
841 public void addIn(Object attribute, Query subQuery)
842 {
843 // PAW
844 // addSelectionCriteria(ValueCriteria.buildInCriteria(attribute, subQuery, getAlias()));
845 addSelectionCriteria(ValueCriteria.buildInCriteria(attribute, subQuery, getUserAlias(attribute)));
846 }
847
848 /**
849 * NOT IN Criteria with SubQuery
850 * @param attribute The field name to be used
851 * @param subQuery The subQuery
852 */
853 public void addNotIn(String attribute, Query subQuery)
854 {
855 // PAW
856 // addSelectionCriteria(ValueCriteria.buildNotInCriteria(attribute, subQuery, getAlias()));
857 addSelectionCriteria(ValueCriteria.buildNotInCriteria(attribute, subQuery, getUserAlias(attribute)));
858 }
859
860 /**
861 * Adds freeform SQL criteria,
862 * REVERSE(name) like 're%'
863 *
864 * @param anSqlStatment The free form SQL-Statement
865 */
866 public void addSql(String anSqlStatment)
867 {
868 addSelectionCriteria(new SqlCriteria(anSqlStatment));
869 }
870
871 /**
872 * ANDs two sets of criteria together:
873 *
874 * @param pc criteria
875 */
876 public void addAndCriteria(Criteria pc)
877 {
878 // by combining a second criteria by 'AND' the existing criteria needs to be enclosed
879 // in parenthesis
880 if (!m_criteria.isEmpty())
881 {
882 this.setEmbraced(true);
883 pc.setEmbraced(true);
884 pc.setType(AND);
885 addCriteria(pc);
886 }
887 else
888 {
889 setEmbraced(false);
890 pc.setType(AND);
891 addCriteria(pc);
892 }
893 }
894
895 /**
896 * Adds an exists(sub query)
897 *
898 * @param subQuery sub-query
899 */
900 public void addExists(Query subQuery)
901 {
902 addSelectionCriteria(new ExistsCriteria(subQuery, false));
903 }
904
905 /**
906 * Adds a not exists(sub query)
907 *
908 * @param subQuery sub-query
909 */
910 public void addNotExists(Query subQuery)
911 {
912 addSelectionCriteria(new ExistsCriteria(subQuery, true));
913 }
914
915 /**
916 * Answer true if no sub criteria available
917 * @return boolean
918 */
919 public boolean isEmpty()
920 {
921 return m_criteria.isEmpty();
922 }
923
924 /**
925 * Gets the groupby for ReportQueries of all Criteria and Sub Criteria
926 * the elements are of class FieldHelper
927 * @return List of FieldHelper
928 */
929 List getGroupby()
930 {
931 List result = _getGroupby();
932 Iterator iter = getCriteria().iterator();
933 Object crit;
934
935 while (iter.hasNext())
936 {
937 crit = iter.next();
938 if (crit instanceof Criteria)
939 {
940 result.addAll(((Criteria) crit).getGroupby());
941 }
942 }
943
944 return result;
945 }
946
947 /**
948 * Gets the groupby for ReportQueries,
949 * the elements are of class Criteria.FieldHelper
950 * @return List of Criteria.FieldHelper
951 */
952 protected List _getGroupby()
953 {
954 return groupby;
955 }
956
957 /**
958 * Adds a groupby fieldName for ReportQueries.
959 * @param fieldName The groupby to set
960 * @deprecated use QueryByCriteria#addGroupBy
961 */
962 public void addGroupBy(String fieldName)
963 {
964 if (fieldName != null)
965 {
966 _getGroupby().add(new FieldHelper(fieldName, false));
967 }
968 }
969
970 /**
971 * Adds a field for groupby
972 * @param aField the Field
973 * @deprecated use QueryByCriteria#addGroupBy
974 */
975 public void addGroupBy(FieldHelper aField)
976 {
977 if (aField != null)
978 {
979 _getGroupby().add(aField);
980 }
981 }
982
983 /**
984 * Adds an array of groupby fieldNames for ReportQueries.
985 * @param fieldNames The groupby to set
986 * @deprecated use QueryByCriteria#addGroupBy
987 */
988 public void addGroupBy(String[] fieldNames)
989 {
990 for (int i = 0; i < fieldNames.length; i++)
991 {
992 addGroupBy(fieldNames[i]);
993 }
994 }
995
996 /**
997 * Returns the prefetchedRelationships.
998 * @return List
999 */
1000 List getPrefetchedRelationships()
1001 {
1002 return prefetchedRelationships;
1003 }
1004
1005 /**
1006 * add the name of a Relationship for prefetch read
1007 * @param aName the name of the relationship
1008 * @deprecated use QueryByCriteria#addPrefetchedRelationship
1009 */
1010 public void addPrefetchedRelationship(String aName)
1011 {
1012 getPrefetchedRelationships().add(aName);
1013 }
1014
1015 /**
1016 * read the prefetchInLimit from Config based on OJB.properties
1017 */
1018 private static int getSqlInLimit()
1019 {
1020 try
1021 {
1022 PersistenceBrokerConfiguration config = (PersistenceBrokerConfiguration) PersistenceBrokerFactory
1023 .getConfigurator().getConfigurationFor(null);
1024 return config.getSqlInLimit();
1025 }
1026 catch (ConfigurationException e)
1027 {
1028 return 200;
1029 }
1030 }
1031
1032 /**
1033 * @return String
1034 */
1035 public String getAlias()
1036 {
1037 return m_alias;
1038 }
1039
1040 /**
1041 * @return String
1042 */
1043 // PAW
1044 public UserAlias getUserAlias()
1045 {
1046 return m_userAlias;
1047 }
1048
1049 // PAW
1050 /**
1051 * Retrieves or if necessary, creates a user alias to be used
1052 * by a child criteria
1053 * @param attribute The alias to set
1054 */
1055 private UserAlias getUserAlias(Object attribute)
1056 {
1057 if (m_userAlias != null)
1058 {
1059 return m_userAlias;
1060 }
1061 if (!(attribute instanceof String))
1062 {
1063 return null;
1064 }
1065 if (m_alias == null)
1066 {
1067 return null;
1068 }
1069 if (m_aliasPath == null)
1070 {
1071 boolean allPathsAliased = true;
1072 return new UserAlias(m_alias, (String)attribute, allPathsAliased);
1073 }
1074 return new UserAlias(m_alias, (String)attribute, m_aliasPath);
1075 }
1076
1077
1078 /**
1079 * Sets the alias. Empty String is regarded as null.
1080 * @param alias The alias to set
1081 */
1082 public void setAlias(String alias)
1083 {
1084 if (alias == null || alias.trim().equals(""))
1085 {
1086 m_alias = null;
1087 }
1088 else
1089 {
1090 m_alias = alias;
1091 }
1092
1093 // propagate to SelectionCriteria,not to Criteria
1094 for (int i = 0; i < m_criteria.size(); i++)
1095 {
1096 if (!(m_criteria.elementAt(i) instanceof Criteria))
1097 {
1098 ((SelectionCriteria) m_criteria.elementAt(i)).setAlias(m_alias);
1099 }
1100 }
1101 }
1102
1103 // PAW
1104 /**
1105 * Sets the alias. Empty String is regarded as null.
1106 * @param alias The alias to set
1107 * @param aliasPath The path segment(s) to which the alias applies
1108 */
1109 public void setAlias(String alias, String aliasPath)
1110 {
1111 if (alias == null || alias.trim().equals(""))
1112 {
1113 m_alias = null;
1114 }
1115 else
1116 {
1117 m_alias = alias;
1118 m_aliasPath = aliasPath;
1119 }
1120
1121 // propagate to SelectionCriteria,not to Criteria
1122 for (int i = 0; i < m_criteria.size(); i++)
1123 {
1124 if (!(m_criteria.elementAt(i) instanceof Criteria))
1125 {
1126 ((SelectionCriteria) m_criteria.elementAt(i)).setAlias(m_alias, aliasPath);
1127 }
1128 }
1129 }
1130
1131 // PAW
1132 /**
1133 * Sets the alias using a userAlias object.
1134 * @param userAlias The alias to set
1135 */
1136 public void setAlias(UserAlias userAlias)
1137 {
1138 m_alias = userAlias.getName();
1139
1140 // propagate to SelectionCriteria,not to Criteria
1141 for (int i = 0; i < m_criteria.size(); i++)
1142 {
1143 if (!(m_criteria.elementAt(i) instanceof Criteria))
1144 {
1145 ((SelectionCriteria) m_criteria.elementAt(i)).setAlias(userAlias);
1146 }
1147 }
1148 }
1149
1150
1151 /**
1152 * @return the query containing the criteria
1153 */
1154 public QueryByCriteria getQuery()
1155 {
1156 if (getParentCriteria() != null)
1157 {
1158 return getParentCriteria().getQuery();
1159 }
1160 else
1161 {
1162 return m_query;
1163 }
1164
1165 }
1166
1167 /**
1168 * @param query
1169 */
1170 void setQuery(QueryByCriteria query)
1171 {
1172 m_query = query;
1173 }
1174
1175 /**
1176 * @return the parent criteria
1177 */
1178 public Criteria getParentCriteria()
1179 {
1180 return m_parentCriteria;
1181 }
1182
1183 /**
1184 * @param criteria
1185 */
1186 void setParentCriteria(Criteria criteria)
1187 {
1188 m_parentCriteria = criteria;
1189 }
1190
1191 /**
1192 * @see Object#toString()
1193 */
1194 public String toString()
1195 {
1196 if (isNegative())
1197 {
1198 return "-" + m_criteria.toString();
1199 }
1200 else
1201 {
1202 return m_criteria.toString();
1203 }
1204 }
1205
1206 /**
1207 * @return Returns the negative.
1208 */
1209 public boolean isNegative()
1210 {
1211 return m_negative;
1212 }
1213
1214 /**
1215 * Flags the whole Criteria as negative.
1216 * @param negative The negative to set.
1217 */
1218 public void setNegative(boolean negative)
1219 {
1220 m_negative = negative;
1221 }
1222
1223 // PAW
1224 /**
1225 * Add a hint Class for a path. Used for relationships to extents.<br>
1226 * SqlStatment will use these hint classes when resolving the path.
1227 * Without these hints SqlStatment will use the base class the
1228 * relationship points to ie: Article instead of CdArticle.
1229 *
1230 * @param aPath the path segment ie: allArticlesInGroup
1231 * @param aClass the Class ie: CdArticle
1232 * @see org.apache.ojb.broker.QueryTest#testInversePathExpression()
1233 */
1234 public void addPathClass(String aPath, Class aClass)
1235 {
1236 List pathClasses = (List) m_pathClasses.get(aPath);
1237 if(pathClasses == null)
1238 {
1239 setPathClass(aPath,aClass);
1240 }
1241 else
1242 {
1243 pathClasses.add(aClass);
1244 //m_pathClasses.put(aPath, pathClasses);
1245 }
1246 }
1247
1248 /**
1249 * Set the Class for a path. Used for relationships to extents.<br>
1250 * SqlStatment will use this class when resolving the path.
1251 * Without this hint SqlStatment will use the base class the
1252 * relationship points to ie: Article instead of CdArticle.
1253 * Using this method is the same as adding just one hint
1254 *
1255 * @param aPath the path segment ie: allArticlesInGroup
1256 * @param aClass the Class ie: CdArticle
1257 * @see org.apache.ojb.broker.QueryTest#testInversePathExpression()
1258 * @see #addPathClass
1259 */
1260 public void setPathClass(String aPath, Class aClass)
1261 {
1262 List pathClasses = new ArrayList(1);
1263 pathClasses.add(aClass);
1264 m_pathClasses.put(aPath, pathClasses);
1265 }
1266
1267 /**
1268 * Get the a List of Class objects used as hints for a path
1269 *
1270 * @param aPath the path segment ie: allArticlesInGroup
1271 * @return a List o Class objects to be used in SqlStatment
1272 * @see #addPathClass
1273 * @see org.apache.ojb.broker.QueryTest#testInversePathExpression()
1274 */
1275 public List getClassesForPath(String aPath)
1276 {
1277 return (List)getPathClasses().get(aPath);
1278 }
1279
1280 /**
1281 * Gets the pathClasses.
1282 * A Map containing hints about what Class to be used for what path segment
1283 * If local instance not set, try parent Criteria's instance. If this is
1284 * the top-level Criteria, try the m_query's instance
1285 * @return Returns a Map
1286 */
1287 public Map getPathClasses()
1288 {
1289 if (m_pathClasses.isEmpty())
1290 {
1291 if (m_parentCriteria == null)
1292 {
1293 if (m_query == null)
1294 {
1295 return m_pathClasses;
1296 }
1297 else
1298 {
1299 return m_query.getPathClasses();
1300 }
1301 }
1302 else
1303 {
1304 return m_parentCriteria.getPathClasses();
1305 }
1306 }
1307 else
1308 {
1309 return m_pathClasses;
1310 }
1311 }
1312
1313
1314
1315 }