Coverage Report - org.apache.ojb.broker.query.QueryByCriteria
 
Classes in this File Line Coverage Branch Coverage Complexity
QueryByCriteria
N/A
N/A
1.486
 
 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.HashMap;
 21  
 import java.util.HashSet;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 
 25  
 import org.apache.ojb.broker.metadata.ClassDescriptor;
 26  
 import org.apache.ojb.broker.metadata.FieldDescriptor;
 27  
 import org.apache.ojb.broker.metadata.FieldHelper;
 28  
 import org.apache.ojb.broker.metadata.MetadataManager;
 29  
 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
 30  
 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
 31  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 32  
 
 33  
 /**
 34  
  * represents a search by criteria.
 35  
  * "find all articles where article.price > 100"
 36  
  * could be represented as:
 37  
  *
 38  
  * Criteria crit = new Criteria();
 39  
  * crit.addGreaterThan("price", new Double(100));
 40  
  * Query qry = new QueryByCriteria(Article.class, crit);
 41  
  *
 42  
  * The PersistenceBroker can retrieve Objects by Queries as follows:
 43  
  *
 44  
  * PersistenceBroker broker = PersistenceBrokerFactory.createPersistenceBroker();
 45  
  * Collection col = broker.getCollectionByQuery(qry);
 46  
  *
 47  
  * Creation date: (24.01.2001 21:45:46)
 48  
  * @author Thomas Mahler
 49  
  * @version $Id: QueryByCriteria.java,v 1.1 2007-08-24 22:17:36 ewestfal Exp $
 50  
  */
 51  
 public class QueryByCriteria extends AbstractQueryImpl
 52  
 {
 53  
     private Criteria m_criteria;
 54  
     private boolean m_distinct = false;
 55  
     private Map m_pathClasses;
 56  
     private Criteria m_havingCriteria;
 57  
         private String m_objectProjectionAttribute;
 58  
 
 59  
     // holding FieldHelper for orderBy and groupBy
 60  
     private List m_orderby = null;
 61  
     private List m_groupby = null;
 62  
 
 63  
     // list of names of prefetchable relationships
 64  
     private List m_prefetchedRelationships = null;
 65  
 
 66  
     private Collection m_pathOuterJoins = null;
 67  
 
 68  
     /**
 69  
      * handy criteria that can be used to select all instances of
 70  
      * a class.
 71  
      */
 72  
     public static final Criteria CRITERIA_SELECT_ALL = null;
 73  
 
 74  
     /**
 75  
      * Build a Query for class targetClass with criteria.
 76  
      * Criteriy may be null (will result in a query returning ALL objects from a table)
 77  
      */
 78  
     public QueryByCriteria(Class targetClass, Criteria whereCriteria, Criteria havingCriteria, boolean distinct)
 79  
     {
 80  
         super (targetClass);
 81  
 
 82  
         setCriteria(whereCriteria);
 83  
         setHavingCriteria(havingCriteria);
 84  
 
 85  
         m_distinct = distinct;
 86  
         m_pathClasses = new HashMap();
 87  
         m_groupby = new ArrayList();
 88  
         m_orderby = new ArrayList();
 89  
         m_prefetchedRelationships = new ArrayList();
 90  
         m_pathOuterJoins = new HashSet();
 91  
     }
 92  
 
 93  
     /**
 94  
      * Build a Query for class targetClass with criteria.
 95  
      * Criteriy may be null (will result in a query returning ALL objects from a table)
 96  
      */
 97  
     public QueryByCriteria(Class targetClass, Criteria whereCriteria, Criteria havingCriteria)
 98  
     {
 99  
         this(targetClass, whereCriteria, havingCriteria, false);
 100  
     }
 101  
 
 102  
 
 103  
     /**
 104  
      * Build a Query for class targetClass with criteria.
 105  
      * Criteriy may be null (will result in a query returning ALL objects from a table)
 106  
      */
 107  
     public QueryByCriteria(Class targetClass, Criteria criteria)
 108  
     {
 109  
         this(targetClass, criteria, false);
 110  
     }
 111  
 
 112  
     /**
 113  
      * Build a Query for class targetClass with criteria.
 114  
      * Criteriy may be null (will result in a query returning ALL objects from a table)
 115  
      */
 116  
     public QueryByCriteria(Class targetClass, Criteria criteria, boolean distinct)
 117  
     {
 118  
         this(targetClass, criteria, null, distinct);
 119  
     }
 120  
 
 121  
     /**
 122  
      * Build a Query based on anObject <br>
 123  
      * all non null values are used as EqualToCriteria
 124  
      */
 125  
     public QueryByCriteria(Object anObject, boolean distinct)
 126  
     {
 127  
         this(anObject.getClass(), buildCriteria(anObject), distinct);
 128  
     }
 129  
 
 130  
     /**
 131  
      * Build a Query based on anObject <br>
 132  
      * all non null values are used as EqualToCriteria
 133  
      */
 134  
     public QueryByCriteria(Object anObject)
 135  
     {
 136  
         this(anObject.getClass(), buildCriteria(anObject));
 137  
     }
 138  
 
 139  
     /**
 140  
      * Build a Query based on a Class Object. This
 141  
      * Query will return all instances of the given class.
 142  
      * @param aClassToSearchFrom the class to search from
 143  
      */
 144  
     public QueryByCriteria(Class aClassToSearchFrom)
 145  
     {
 146  
         this(aClassToSearchFrom, CRITERIA_SELECT_ALL);
 147  
     }
 148  
 
 149  
     /**
 150  
      * Build Criteria based on example object<br>
 151  
      * all non null values are used as EqualToCriteria
 152  
      */
 153  
     private static Criteria buildCriteria(Object anExample)
 154  
     {
 155  
         Criteria criteria = new Criteria();
 156  
         ClassDescriptor cld = MetadataManager.getInstance().getRepository().getDescriptorFor(anExample.getClass());
 157  
         FieldDescriptor[] fds = cld.getFieldDescriptions();
 158  
         PersistentField f;
 159  
         Object value;
 160  
 
 161  
         for (int i = 0; i < fds.length; i++)
 162  
         {
 163  
             try
 164  
             {
 165  
                 f = fds[i].getPersistentField();
 166  
                 value = f.get(anExample);
 167  
                 if (value != null)
 168  
                 {
 169  
                     criteria.addEqualTo(f.getName(), value);
 170  
                 }
 171  
             }
 172  
             catch (Throwable ex)
 173  
             {
 174  
                 LoggerFactory.getDefaultLogger().error(ex);
 175  
             }
 176  
         }
 177  
 
 178  
         return criteria;
 179  
     }
 180  
 
 181  
     /**
 182  
      * Add a hint Class for a path. Used for relationships to extents.<br>
 183  
      * SqlStatment will use these hint classes when resolving the path.
 184  
      * Without these hints SqlStatment will use the base class the
 185  
      * relationship points to ie: Article instead of CdArticle.
 186  
      *
 187  
      * @param aPath the path segment ie: allArticlesInGroup
 188  
      * @param aClass the Class ie: CdArticle
 189  
      * @see org.apache.ojb.broker.QueryTest#testInversePathExpression()
 190  
      */
 191  
     public void addPathClass(String aPath, Class aClass)
 192  
     {
 193  
         List pathClasses = (List) m_pathClasses.get(aPath);
 194  
         if(pathClasses == null)
 195  
         {
 196  
             setPathClass(aPath, aClass);
 197  
         }
 198  
         else
 199  
         {
 200  
             pathClasses.add(aClass);
 201  
         }
 202  
     }
 203  
 
 204  
     /**
 205  
      * Set the Class for a path. Used for relationships to extents.<br>
 206  
      * SqlStatment will use this class when resolving the path.
 207  
      * Without this hint SqlStatment will use the base class the
 208  
      * relationship points to ie: Article instead of CdArticle.
 209  
      * Using this method is the same as adding just one hint
 210  
      *
 211  
      * @param aPath the path segment ie: allArticlesInGroup
 212  
      * @param aClass the Class ie: CdArticle
 213  
      * @see org.apache.ojb.broker.QueryTest#testInversePathExpression()
 214  
      * @see #addPathClass
 215  
      */
 216  
     public void setPathClass(String aPath, Class aClass)
 217  
     {
 218  
         List pathClasses = new ArrayList();
 219  
         pathClasses.add(aClass);
 220  
         m_pathClasses.put(aPath, pathClasses);
 221  
     }
 222  
 
 223  
     /**
 224  
      * Get the a List of Class objects used as hints for a path
 225  
      *
 226  
      * @param aPath the path segment ie: allArticlesInGroup
 227  
      * @return a List o Class objects to be used in SqlStatment
 228  
      * @see #addPathClass
 229  
      * @see org.apache.ojb.broker.QueryTest#testInversePathExpression()
 230  
      */
 231  
     public List getClassesForPath(String aPath)
 232  
     {
 233  
         return (List)m_pathClasses.get(aPath);
 234  
     }
 235  
 
 236  
     /**
 237  
      * Answer true if outer join for path should be used.
 238  
      * @param aPath the path to query the outer join setting for
 239  
      * @return true for outer join
 240  
      */
 241  
     public boolean isPathOuterJoin(String aPath)
 242  
     {
 243  
         return getOuterJoinPaths().contains(aPath);
 244  
     }
 245  
 
 246  
     /**
 247  
      * Force outer join for the last segment of the path.
 248  
      * ie. path = 'a.b.c' the outer join will be applied only to the relationship from B to C.
 249  
      * if multiple segments need an outer join, setPathOuterJoin needs to be called for each segement.
 250  
      * @param aPath force outer join to the last segment of this path
 251  
      */
 252  
     public void setPathOuterJoin(String aPath)
 253  
     {
 254  
         getOuterJoinPaths().add(aPath);
 255  
     }
 256  
 
 257  
     /* (non-Javadoc)
 258  
      * @see org.apache.ojb.broker.query.Query#getCriteria()
 259  
      */
 260  
     public Criteria getCriteria()
 261  
     {
 262  
         return m_criteria;
 263  
     }
 264  
 
 265  
     /* (non-Javadoc)
 266  
      * @see org.apache.ojb.broker.query.Query#getHavingCriteria()
 267  
      */
 268  
     public Criteria getHavingCriteria()
 269  
     {
 270  
         return m_havingCriteria;
 271  
     }
 272  
 
 273  
     /**
 274  
      * Insert the method's description here.
 275  
      * Creation date: (07.02.2001 22:01:55)
 276  
      * @return java.lang.String
 277  
      */
 278  
     public String toString()
 279  
     {
 280  
         StringBuffer buf = new StringBuffer("QueryByCriteria from ");
 281  
         buf.append(getSearchClass()).append(" ");
 282  
         if (getCriteria() != null && !getCriteria().isEmpty())
 283  
         {
 284  
             buf.append(" where ").append(getCriteria());
 285  
         }
 286  
         return buf.toString();
 287  
     }
 288  
 
 289  
     /**
 290  
      * Gets the distinct.
 291  
      * @return Returns a boolean
 292  
      */
 293  
     public boolean isDistinct()
 294  
     {
 295  
         return m_distinct;
 296  
     }
 297  
 
 298  
     /**
 299  
      * Sets the distinct.
 300  
      * @param distinct The distinct to set
 301  
      */
 302  
     public void setDistinct(boolean distinct)
 303  
     {
 304  
         this.m_distinct = distinct;
 305  
     }
 306  
 
 307  
     /**
 308  
      * Gets the pathClasses.
 309  
      * A Map containing hints about what Class to be used for what path segment
 310  
      * @return Returns a Map
 311  
      */
 312  
     public Map getPathClasses()
 313  
     {
 314  
         return m_pathClasses;
 315  
     }
 316  
 
 317  
         /**
 318  
          * Sets the criteria.
 319  
          * @param criteria The criteria to set
 320  
          */
 321  
         public void setCriteria(Criteria criteria)
 322  
         {
 323  
                 m_criteria = criteria;
 324  
         if (m_criteria != null)
 325  
         {
 326  
             m_criteria.setQuery(this);
 327  
         }
 328  
         }
 329  
 
 330  
         /**
 331  
          * Sets the havingCriteria.
 332  
          * @param havingCriteria The havingCriteria to set
 333  
          */
 334  
         public void setHavingCriteria(Criteria havingCriteria)
 335  
         {
 336  
                 m_havingCriteria = havingCriteria;
 337  
         if (m_havingCriteria != null)
 338  
         {
 339  
             m_havingCriteria.setQuery(this);
 340  
         }
 341  
         }
 342  
 
 343  
     /**
 344  
      * Adds a groupby fieldName for ReportQueries.
 345  
      * @param fieldName The groupby to set
 346  
      */
 347  
     public void addGroupBy(String fieldName)
 348  
     {
 349  
         if (fieldName != null)
 350  
         {
 351  
             m_groupby.add(new FieldHelper(fieldName, false));
 352  
         }
 353  
     }
 354  
 
 355  
     /**
 356  
      * Adds a field for groupby
 357  
      * @param aField
 358  
      */
 359  
     public void addGroupBy(FieldHelper aField)
 360  
     {
 361  
         if (aField != null)
 362  
         {
 363  
             m_groupby.add(aField);
 364  
         }
 365  
     }
 366  
 
 367  
     /**
 368  
      * Adds an array of groupby fieldNames for ReportQueries.
 369  
      * @param fieldNames The groupby to set
 370  
      */
 371  
     public void addGroupBy(String[] fieldNames)
 372  
     {
 373  
         for (int i = 0; i < fieldNames.length; i++)
 374  
         {
 375  
             addGroupBy(fieldNames[i]);
 376  
         }
 377  
     }
 378  
 
 379  
         /**
 380  
          * @see org.apache.ojb.broker.query.Query#getGroupBy()
 381  
          */
 382  
         public List getGroupBy()
 383  
         {
 384  
         // BRJ:
 385  
         // combine data from query and criteria
 386  
         // TODO: to be removed when Criteria#addGroupBy is removed
 387  
         ArrayList temp = new ArrayList();
 388  
         temp.addAll(m_groupby);
 389  
 
 390  
         if (getCriteria() != null)
 391  
         {
 392  
             temp.addAll(getCriteria().getGroupby());
 393  
         }
 394  
 
 395  
         return temp;
 396  
         }
 397  
 
 398  
     /**
 399  
      * Adds a field for orderBy
 400  
      * @param  fieldName    The field name to be used
 401  
      * @param  sortAscending    true for ASCENDING, false for DESCENDING
 402  
      */
 403  
     public void addOrderBy(String fieldName, boolean sortAscending)
 404  
     {
 405  
         if (fieldName != null)
 406  
         {
 407  
             m_orderby.add(new FieldHelper(fieldName, sortAscending));
 408  
         }
 409  
     }
 410  
 
 411  
     /**
 412  
      * Adds a field for orderBy, order is ASCENDING
 413  
      * @param  fieldName    The field name to be used
 414  
      * @deprecated use #addOrderByAscending(String fieldName)
 415  
      */
 416  
     public void addOrderBy(String fieldName)
 417  
     {
 418  
         addOrderBy(fieldName, true);
 419  
     }
 420  
 
 421  
     /**
 422  
      * Adds a field for orderBy
 423  
      * @param aField
 424  
      */
 425  
     public void addOrderBy(FieldHelper aField)
 426  
     {
 427  
         if (aField != null)
 428  
         {
 429  
             m_orderby.add(aField);
 430  
         }
 431  
     }
 432  
 
 433  
     /**
 434  
      * Adds a field for orderBy ASCENDING
 435  
      * @param  fieldName    The field name to be used
 436  
      */
 437  
     public void addOrderByAscending(String fieldName)
 438  
     {
 439  
         addOrderBy(fieldName, true);
 440  
     }
 441  
 
 442  
     /**
 443  
      * Adds a field for orderBy DESCENDING
 444  
      * @param  fieldName    The field name to be used
 445  
      */
 446  
     public void addOrderByDescending(String fieldName)
 447  
     {
 448  
         addOrderBy(fieldName, false);
 449  
     }
 450  
 
 451  
         /**
 452  
          * @see org.apache.ojb.broker.query.Query#getOrderBy()
 453  
          */
 454  
         public List getOrderBy()
 455  
         {
 456  
         // BRJ:
 457  
         // combine data from query and criteria
 458  
         // TODO: to be removed when Criteria#addOrderBy is removed
 459  
         ArrayList temp = new ArrayList();
 460  
         temp.addAll(m_orderby);
 461  
 
 462  
         if (getCriteria() != null)
 463  
         {
 464  
             temp.addAll(getCriteria().getOrderby());
 465  
         }
 466  
 
 467  
         return temp;
 468  
         }
 469  
 
 470  
     /**
 471  
      * add the name of aRelationship for prefetched read
 472  
      */
 473  
     public void addPrefetchedRelationship(String aName)
 474  
     {
 475  
         m_prefetchedRelationships.add(aName);
 476  
     }
 477  
 
 478  
         /* (non-Javadoc)
 479  
          * @see org.apache.ojb.broker.query.Query#getPrefetchedRelationships()
 480  
          */
 481  
         public List getPrefetchedRelationships()
 482  
         {
 483  
         // BRJ:
 484  
         // combine data from query and criteria
 485  
         // TODO: to be removed when Criteria#addPrefetchedRelationship is removed
 486  
         ArrayList temp = new ArrayList();
 487  
         temp.addAll(m_prefetchedRelationships);
 488  
 
 489  
         if (getCriteria() != null)
 490  
         {
 491  
             temp.addAll(getCriteria().getPrefetchedRelationships());
 492  
         }
 493  
 
 494  
         return temp;
 495  
     }
 496  
 
 497  
         /**
 498  
      * Get a Collection containing all Paths having an Outer-Joins-Setting
 499  
      * @return a Collection containing the Paths (Strings)
 500  
          */
 501  
     public Collection getOuterJoinPaths()
 502  
     {
 503  
         return m_pathOuterJoins;
 504  
     }
 505  
 
 506  
     public String getObjectProjectionAttribute()
 507  
     {
 508  
         return m_objectProjectionAttribute;
 509  
     }
 510  
 
 511  
     /**
 512  
      * Use this method to query some related class by object references,
 513  
      * for example query.setObjectProjectionAttribute("ref1.ref2.ref3");
 514  
      */
 515  
     public void setObjectProjectionAttribute(String objectProjectionAttribute)
 516  
     {
 517  
         ClassDescriptor baseCld = MetadataManager.getInstance().getRepository().getDescriptorFor(m_baseClass);
 518  
         ArrayList descs = baseCld.getAttributeDescriptorsForPath(objectProjectionAttribute);
 519  
         int pathLen = descs.size();
 520  
 
 521  
         if ((pathLen > 0) && (descs.get(pathLen - 1) instanceof ObjectReferenceDescriptor))
 522  
         {
 523  
             ObjectReferenceDescriptor ord =
 524  
                     ((ObjectReferenceDescriptor) descs.get(pathLen - 1));
 525  
             setObjectProjectionAttribute(objectProjectionAttribute,
 526  
                                          ord.getItemClass());
 527  
         }
 528  
     }
 529  
 
 530  
     public void setObjectProjectionAttribute(String objectProjectionAttribute,
 531  
                                              Class objectProjectionClass)
 532  
     {
 533  
         m_objectProjectionAttribute = objectProjectionAttribute;
 534  
         m_searchClass = objectProjectionClass;
 535  
         }
 536  
 }