001    package org.apache.ojb.broker.query;
002    
003    /* Copyright 2002-2005 The Apache Software Foundation
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    import java.util.ArrayList;
019    import java.util.Collection;
020    import java.util.Enumeration;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    import java.util.Vector;
026    
027    import org.apache.ojb.broker.PersistenceBrokerFactory;
028    import org.apache.ojb.broker.metadata.FieldHelper;
029    import org.apache.ojb.broker.core.PersistenceBrokerConfiguration;
030    import org.apache.ojb.broker.util.configuration.ConfigurationException;
031    
032    /**
033     * Persistent Criteria can be used to retrieve sets of objects based on their attributes
034     * Normally each attribute is ANDed together, an OR can be performed by creating a new
035     * PersistentCriteria and adding it.
036     * <P>
037     * Criteria are used, rather than a simple string, because they can be precompiled for
038     * efficiency.
039     *
040     * This code is based on stuff from
041     * COBRA - Java Object Persistence Layer
042     * Copyright (C) 1997, 1998    DB Harvey-George
043     * eMail: cobra@lowrent.org
044     *
045     * @author <a href="mailto:jbraeuchi@gmx.ch">Jakob Braeuchi</a>
046     * @version $Id: Criteria.java,v 1.1 2007-08-24 22:17:36 ewestfal Exp $
047     */
048    public class Criteria implements java.io.Serializable
049    {
050        static final long serialVersionUID = 7384550404778187808L;
051    
052        /** criteria is OR-ed with it's parent */
053        public static final int OR = 0;
054        /** criteria is AND-ed with it's parent */
055        public static final int AND = 1;
056        /** criteria has no parent */
057        public static final int NONE = 9;
058    
059        /** prefix to identify attributes referencing enclosing query */
060        public static final String PARENT_QUERY_PREFIX = "parentQuery.";
061    
062        private Vector m_criteria;
063        private int m_type;
064        private boolean m_embraced;
065        private boolean m_negative = false;
066    
067        // holding CriteriaFields for orderBy and groupBy
068        private List orderby = null;
069        private List groupby = null;
070        private List prefetchedRelationships = null;
071    
072            // an optional alias to be used for this criteria
073            private String m_alias = null;
074    
075            // PAW
076            // an aliasPath to be used for this criteria
077            private String m_aliasPath = null;
078    
079            // holds the path segment(s) to which the alias applies
080            private UserAlias m_userAlias = null;
081    
082            /** the max. number of parameters in a IN-statement */
083        protected static final int IN_LIMIT = getSqlInLimit();
084    
085        private QueryByCriteria m_query;
086        private Criteria m_parentCriteria;
087    
088        // PAW
089            // hint classes for paths of this criteria
090            private Map m_pathClasses;
091    
092        /**
093         * Constructor declaration
094         */
095        public Criteria()
096        {
097            m_criteria = new Vector();
098            groupby = new ArrayList();
099            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    }