Coverage Report - org.kuali.rice.core.api.criteria.PredicateFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
PredicateFactory
79%
31/39
66%
12/18
1.864
PredicateFactory$DynPredicateException
0%
0/4
N/A
1.864
 
 1  
 package org.kuali.rice.core.api.criteria;
 2  
 
 3  
 import org.apache.commons.collections.CollectionUtils;
 4  
 import org.apache.commons.lang.StringUtils;
 5  
 
 6  
 import java.lang.reflect.InvocationTargetException;
 7  
 import java.lang.reflect.Method;
 8  
 import java.util.HashSet;
 9  
 import java.util.Set;
 10  
 
 11  
 /**
 12  
  * This is a factory class to construct {@link Predicate Predicates}.
 13  
  *
 14  
  * <p>
 15  
  *    For more readable predicate construction it is recommended that this class
 16  
  *    is statically imported.
 17  
  * <code>
 18  
  *    import static org.kuali.rice.core.api.criteria.PredicateFactory.*;
 19  
  * </code>
 20  
  * </p>
 21  
  *
 22  
  * to create a simple predicate where the property
 23  
  * foo.bar equals "baz" do the following:
 24  
  * <code>
 25  
  *     Predicate simple = equals("foo.bar", "baz");
 26  
  * </code>
 27  
  *
 28  
  * to create a compound predicate where the property
 29  
  * foo.bar equals "baz" and foo.id equals 1 do the following:
 30  
  * <code>
 31  
  *     Predicate compound = and(equals("foo.bar", "baz"), equals("foo.id", 1))
 32  
  * </code>
 33  
  *
 34  
  * to create a deeply nested predicate where lots of
 35  
  * properties are evaluated do the following:
 36  
  *
 37  
  * Predicate deep =
 38  
  *  and(
 39  
  *      like("display", "*Eric*"),
 40  
  *                greaterThan("birthDate", gtBirthDate),
 41  
  *                 lessThan("birthDate", ltBirthDate),
 42  
  *      or(
 43  
  *         equal("name.first", "Eric"),
 44  
  *         equal("name.last", "Westfall")))
 45  
  *
 46  
  * <p>
 47  
  *     <strong>WARNING:</strong> this class does automatic reductions
 48  
  *     such that you cannot assume the concrete {@link Predicate} type
 49  
  *     returned from this factory.
 50  
  * </p>
 51  
  *
 52  
  * @see QueryByCriteria
 53  
  */
 54  
 public final class PredicateFactory {
 55  0
     private PredicateFactory() {
 56  0
         throw new IllegalArgumentException("do not call");
 57  
     }
 58  
 
 59  
     /**
 60  
          * Creates an predicate representing equals comparison.  Defines that the property
 61  
      * represented by the given path should be equal to the specified value.
 62  
          *
 63  
          * <p>Supports the following types of values:
 64  
          *
 65  
          * <ul>
 66  
          *   <li>character data</li>
 67  
          *   <li>decimals</li>
 68  
          *   <li>integers</li>
 69  
          *   <li>date-time</li>
 70  
          * </ul>
 71  
          *
 72  
          * @param propertyPath the path to the property which should be evaluated
 73  
          * @param value the value to compare with the property value located at the
 74  
          * propertyPath
 75  
          *
 76  
          * @return a predicate
 77  
          *
 78  
          * @throws IllegalArgumentException if the propertyPath is null
 79  
          * @throws IllegalArgumentException if the value is null or of an invalid type
 80  
          */
 81  
         public static Predicate equal(String propertyPath, Object value) {
 82  22
                 return new EqualPredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValue(value));
 83  
         }
 84  
 
 85  
         /**
 86  
          * Creates a predicate representing not equals comparison.  Defines that the property
 87  
      * represented by the given path should <strong>not</strong> be
 88  
          * equal to the specified value.
 89  
          *
 90  
          * <p>Supports the following types of values:
 91  
          *
 92  
          * <ul>
 93  
          *   <li>character data</li>
 94  
          *   <li>decimals</li>
 95  
          *   <li>integers</li>
 96  
          *   <li>date-time</li>
 97  
          * </ul>
 98  
          *
 99  
          * @param propertyPath the path to the property which should be evaluated
 100  
          * @param value the value to compare with the property value located at the
 101  
          * propertyPath
 102  
          *
 103  
          * @return a predicate
 104  
          *
 105  
          * @throws IllegalArgumentException if the propertyPath is null
 106  
          * @throws IllegalArgumentException if the value is null or of an invalid type
 107  
          */
 108  
         public static Predicate notEqual(String propertyPath, Object value) {
 109  9
                 return new NotEqualPredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValue(value));
 110  
         }
 111  
 
 112  
     /**
 113  
          * Creates an equals ignore case predicate.  Defines that the property
 114  
      * represented by the given path should be equal to the specified value ignoring
 115  
      * the case of the value.
 116  
          *
 117  
          * <p>Supports the following types of values:
 118  
          *
 119  
          * <ul>
 120  
          *   <li>character data</li>
 121  
          * </ul>
 122  
          *
 123  
          * @param propertyPath the path to the property which should be evaluated
 124  
          * @param value the value to compare with the property value located at the
 125  
          * propertyPath
 126  
          *
 127  
          * @return a predicate
 128  
          *
 129  
          * @throws IllegalArgumentException if the propertyPath is null
 130  
          * @throws IllegalArgumentException if the value is null or of an invalid type
 131  
          */
 132  
         public static Predicate equalIgnoreCase(String propertyPath, CharSequence value) {
 133  2
                 return new EqualIgnoreCasePredicate(propertyPath, new CriteriaStringValue(value));
 134  
         }
 135  
 
 136  
         /**
 137  
          * Creates a not equals ignore case predicate.  Defines that the property
 138  
      * represented by the given path should <strong>not</strong> be
 139  
          * equal to the specified value ignoring the case of the value.
 140  
          *
 141  
          * <p>Supports the following types of values:
 142  
          *
 143  
          * <ul>
 144  
          *   <li>character data</li>
 145  
          * </ul>
 146  
          *
 147  
          * @param propertyPath the path to the property which should be evaluated
 148  
          * @param value the value to compare with the property value located at the
 149  
          * propertyPath
 150  
          *
 151  
          * @return a predicate
 152  
          *
 153  
          * @throws IllegalArgumentException if the propertyPath is null
 154  
          * @throws IllegalArgumentException if the value is null or of an invalid type
 155  
          */
 156  
         public static Predicate notEqualIgnoreCase(String propertyPath, CharSequence value) {
 157  2
                 return new NotEqualIgnoreCasePredicate(propertyPath, new CriteriaStringValue(value));
 158  
         }
 159  
 
 160  
         /**
 161  
          * Creates a like predicate.  Defines that the property
 162  
      * represented by the given path should match the specified value,
 163  
          * but supports the use of wildcards in the given value.
 164  
          *
 165  
          * <p>The supported wildcards include:
 166  
          *
 167  
          * <ul>
 168  
          *   <li><strong>?</strong> - matches on any single character</li>
 169  
          *   <li><strong>*</strong> - matches any string of any length (including zero length)</li>
 170  
          * </ul>
 171  
          *
 172  
          * <p>Because of this, the like predicate only supports character data
 173  
          * for the passed-in value.
 174  
          *
 175  
          * @param propertyPath the path to the property which should be evaluated
 176  
          * @param value the value to compare with the property value located at the
 177  
          * propertyPath
 178  
          *
 179  
          * @return a predicate
 180  
          *
 181  
          * @throws IllegalArgumentException if the propertyPath is null
 182  
          * @throws IllegalArgumentException if the value is null
 183  
          */
 184  
         public static Predicate like(String propertyPath, CharSequence value) {
 185  8
                 return new LikePredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValue(value));
 186  
         }
 187  
 
 188  
     /**
 189  
          * Creates a not like predicate.  Defines that the property
 190  
      * represented by the given path should <strong>not</strong> match the specified value,
 191  
          * but supports the use of wildcards in the given value.
 192  
          *
 193  
          * <p>The supported wildcards include:
 194  
          *
 195  
          * <ul>
 196  
          *   <li><strong>?</strong> - matches on any single character</li>
 197  
          *   <li><strong>*</strong> - matches any string of any length (including zero length)</li>
 198  
          * </ul>
 199  
          *
 200  
          * <p>Because of this, the like predicate only supports character data
 201  
          * for the passed-in value.
 202  
          *
 203  
          * @param propertyPath the path to the property which should be evaluated
 204  
          * @param value the value to compare with the property value located at the
 205  
          * propertyPath
 206  
          *
 207  
          * @return a predicate
 208  
          *
 209  
          * @throws IllegalArgumentException if the propertyPath is null
 210  
          * @throws IllegalArgumentException if the value is null
 211  
          */
 212  
         public static Predicate notLike(String propertyPath, CharSequence value) {
 213  5
                 return new NotLikePredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValue(value));
 214  
         }
 215  
 
 216  
         /**
 217  
          * Create an in predicate.  Defines that the property
 218  
      * represented by the given path should be contained within the
 219  
          * specified list of values.
 220  
          *
 221  
          * <p>Supports any of the valid types of value in the value list, with the
 222  
          * restriction that all items in the list of values must be of the same type.
 223  
          *
 224  
          * @param propertyPath the path to the property which should be evaluated
 225  
          * @param values the values to compare with the property value located at the
 226  
          * propertyPath
 227  
          *
 228  
          * @return a predicate
 229  
          *
 230  
          * @throws IllegalArgumentException if the propertyPath is null
 231  
          * @throws IllegalArgumentException if the values list is null, empty,
 232  
          * contains object of different types, or includes objects of an invalid type
 233  
          */
 234  
         public static <T> Predicate in(String propertyPath, T... values) {
 235  10
                 return new InPredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValueList(values));
 236  
         }
 237  
 
 238  
         /**
 239  
          * Create a not in predicate.  Defines that the property
 240  
      * represented by the given path should <strong>not</strong> be
 241  
          * contained within the specified list of values.
 242  
          *
 243  
          * <p>Supports any of the valid types of value in the value list, with the
 244  
          * restriction that all items in the list of values must be of the same type.
 245  
          *
 246  
          * @param propertyPath the path to the property which should be evaluated
 247  
          * @param values the values to compare with the property value located at the
 248  
          * propertyPath
 249  
          *
 250  
          * @return a predicate
 251  
          *
 252  
          * @throws IllegalArgumentException if the propertyPath is null
 253  
          * @throws IllegalArgumentException if the values list is null, empty,
 254  
          * contains object of different types, or includes objects of an invalid type
 255  
          */
 256  
         public static <T> Predicate notIn(String propertyPath, T... values) {
 257  7
                 return new NotInPredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValueList(values));
 258  
         }
 259  
 
 260  
     /**
 261  
          * Create an in ignore case predicate.  Defines that the property
 262  
      * represented by the given path should be contained within the
 263  
          * specified list of values ignoring the case of the values.
 264  
          *
 265  
          * <p>Supports any of CharSequence value in the value list, with the
 266  
          * restriction that all items in the list of values must be of the same type.
 267  
          *
 268  
          * @param propertyPath the path to the property which should be evaluated
 269  
          * @param values the values to compare with the property value located at the
 270  
          * propertyPath
 271  
          *
 272  
          * @return a predicate
 273  
          *
 274  
          * @throws IllegalArgumentException if the propertyPath is null
 275  
          * @throws IllegalArgumentException if the values list is null, empty,
 276  
          * contains object of different types, or includes objects of an invalid type
 277  
          */
 278  
         public static <T extends CharSequence> Predicate inIgnoreCase(String propertyPath, T... values) {
 279  2
                 return new InIgnoreCasePredicate(propertyPath, CriteriaSupportUtils.createCriteriaStringValueList(values));
 280  
         }
 281  
 
 282  
         /**
 283  
          * Create a not in ignore case.  Defines that the property
 284  
      * represented by the given path should <strong>not</strong> be
 285  
          * contained within the specified list of values ignoring the case of the values.
 286  
          *
 287  
          * <p>Supports any CharSequence value in the value list, with the
 288  
          * restriction that all items in the list of values must be of the same type.
 289  
          *
 290  
          * @param propertyPath the path to the property which should be evaluated
 291  
          * @param values the values to compare with the property value located at the
 292  
          * propertyPath
 293  
          *
 294  
          * @return a predicate
 295  
          *
 296  
          * @throws IllegalArgumentException if the propertyPath is null
 297  
          * @throws IllegalArgumentException if the values list is null, empty,
 298  
          * contains object of different types, or includes objects of an invalid type
 299  
          */
 300  
         public static <T extends CharSequence> Predicate notInIgnoreCase(String propertyPath, T... values) {
 301  2
                 return new NotInIgnoreCasePredicate(propertyPath, CriteriaSupportUtils.createCriteriaStringValueList(values));
 302  
         }
 303  
 
 304  
         /**
 305  
          * Creates a greater than predicate.  Defines that the property
 306  
      * represented by the given path should be greater than the specified value.
 307  
          *
 308  
          * <p>Supports the following types of values:
 309  
          *
 310  
          * <ul>
 311  
          *   <li>decimals</li>
 312  
          *   <li>integers</li>
 313  
          *   <li>date-time</li>
 314  
          * </ul>
 315  
          *
 316  
          * @param propertyPath the path to the property which should be evaluated
 317  
          * @param value the value to compare with the property value located at the
 318  
          * propertyPath
 319  
          *
 320  
          * @return a predicate
 321  
          *
 322  
          * @throws IllegalArgumentException if the propertyPath is null
 323  
          * @throws IllegalArgumentException if the value is null or of an invalid type
 324  
          */
 325  
         public static Predicate greaterThan(String propertyPath, Object value) {
 326  11
                 return new GreaterThanPredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValue(value));
 327  
         }
 328  
 
 329  
         /**
 330  
          * Creates a greater than or equal predicate.  Defines that the
 331  
      * property represented by the given path should be greater than
 332  
          * or equal to the specified value.
 333  
          *
 334  
          * <p>Supports the following types of values:
 335  
          *
 336  
          * <ul>
 337  
          *   <li>decimals</li>
 338  
          *   <li>integers</li>
 339  
          *   <li>date-time</li>
 340  
          * </ul>
 341  
          *
 342  
          * @param propertyPath the path to the property which should be evaluated
 343  
          * @param value the value to compare with the property value located at the
 344  
          * propertyPath
 345  
          *
 346  
          * @return a predicate
 347  
          *
 348  
          * @throws IllegalArgumentException if the propertyPath is null
 349  
          * @throws IllegalArgumentException if the value is null or of an invalid type
 350  
          */
 351  
         public static Predicate greaterThanOrEqual(String propertyPath, Object value) {
 352  5
                 return new GreaterThanOrEqualPredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValue(value));
 353  
         }
 354  
 
 355  
         /**
 356  
          * Creates a less than predicate.  Defines that the property
 357  
      * represented by the given path should be less than the specified value.
 358  
          *
 359  
          * <p>Supports the following types of values:
 360  
          *
 361  
          * <ul>
 362  
          *   <li>decimals</li>
 363  
          *   <li>integers</li>
 364  
          *   <li>date-time</li>
 365  
          * </ul>
 366  
          *
 367  
          * @param propertyPath the path to the property which should be evaluated
 368  
          * @param value the value to compare with the property value located at the
 369  
          * propertyPath
 370  
          *
 371  
          * @return a predicate
 372  
          *
 373  
          * @throws IllegalArgumentException if the propertyPath is null
 374  
          * @throws IllegalArgumentException if the value is null or of an invalid type
 375  
          */
 376  
         public static Predicate lessThan(String propertyPath, Object value) {
 377  7
                 return new LessThanPredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValue(value));
 378  
         }
 379  
 
 380  
         /**
 381  
          * Creates a less than or equal predicate.  Defines that the
 382  
      * property represented by the given path should be less than
 383  
          * or equal to the specified value.
 384  
          *
 385  
          * <p>Supports the following types of values:
 386  
          *
 387  
          * <ul>
 388  
          *   <li>decimals</li>
 389  
          *   <li>integers</li>
 390  
          *   <li>date-time</li>
 391  
          * </ul>
 392  
          *
 393  
          * @param propertyPath the path to the property which should be evaluated
 394  
          * @param value the value to compare with the property value located at the
 395  
          * propertyPath
 396  
          *
 397  
          * @return a predicate
 398  
          *
 399  
          * @throws IllegalArgumentException if the propertyPath is null
 400  
          * @throws IllegalArgumentException if the value is null or of an invalid type
 401  
          */
 402  
         public static Predicate lessThanOrEqual(String propertyPath, Object value) {
 403  5
                 return new LessThanOrEqualPredicate(propertyPath, CriteriaSupportUtils.determineCriteriaValue(value));
 404  
         }
 405  
 
 406  
         /**
 407  
          * Creates an is null predicate.  Defines that the
 408  
          * property represented by the given path should be null.
 409  
          *
 410  
          * @param propertyPath the path to the property which should be evaluated
 411  
          *
 412  
          * @return a predicate
 413  
          *
 414  
          * @throws IllegalArgumentException if the propertyPath is null
 415  
          */
 416  
         public static Predicate isNull(String propertyPath) {
 417  6
                 return new NullPredicate(propertyPath);
 418  
         }
 419  
 
 420  
         /**
 421  
          * Creates an is not null predicate.  Defines that the property
 422  
      * represented by the given path should <strong>not</strong> be null.
 423  
          *
 424  
          * @param propertyPath the path to the property which should be evaluated
 425  
          *
 426  
          * @return a predicate
 427  
          *
 428  
          * @throws IllegalArgumentException if the propertyPath is null
 429  
          */
 430  
         public static Predicate isNotNull(String propertyPath) {
 431  6
                 return new NotNullPredicate(propertyPath);
 432  
         }
 433  
 
 434  
         /**
 435  
          * Creates an and predicate that is used to "and" predicates together.
 436  
          *
 437  
          * <p>An "and" predicate will evaluate the truth value of of it's
 438  
          * internal predicates and, if all of them evaluate to true, then
 439  
          * the and predicate itself should evaluate to true.  The implementation
 440  
      * of an and predicate may short-circuit.
 441  
      *
 442  
      * <p>
 443  
      *     This factory method does automatic reductions.
 444  
      * </p>
 445  
          *
 446  
      * @param predicates to "and" together
 447  
      *
 448  
          * @return a predicate
 449  
          */
 450  
         public static Predicate and(Predicate... predicates) {
 451  
         //reduce single item compound
 452  18
         if (predicates != null && predicates.length == 1 && predicates[0] != null) {
 453  9
             return predicates[0];
 454  
         }
 455  9
         final Set<Predicate> predicateSet = new HashSet<Predicate>();
 456  9
         CollectionUtils.addAll(predicateSet, predicates);
 457  9
         return new AndPredicate(predicateSet);
 458  
         }
 459  
 
 460  
         /**
 461  
          * Creates an  or predicate that is used to "or" predicate together.
 462  
          *
 463  
          * <p>An "or" predicate will evaluate the truth value of of it's
 464  
          * internal predicates and, if any one of them evaluate to true, then
 465  
          * the or predicate itself should evaluate to true.  If all predicates
 466  
          * contained within the "or" evaluate to false, then the or iself will
 467  
          * evaluate to false.   The implementation of an or predicate may
 468  
      * short-circuit.
 469  
          *
 470  
      * <p>
 471  
      *     This factory method does automatic reductions.
 472  
      * </p>
 473  
      * @param predicates to "or" together
 474  
      *
 475  
          * @return a predicate
 476  
          */
 477  
         public static Predicate or(Predicate... predicates) {
 478  
         //reduce single item compound
 479  8
         if (predicates != null && predicates.length == 1 && predicates[0] != null) {
 480  2
             return predicates[0];
 481  
         }
 482  
 
 483  6
         final Set<Predicate> predicateSet = new HashSet<Predicate>();
 484  6
         CollectionUtils.addAll(predicateSet, predicates);
 485  6
                 return new OrPredicate(predicateSet);
 486  
         }
 487  
 
 488  
     /**
 489  
      * This method will construct a predicate based on the predicate name.
 490  
      *
 491  
      * ex: "or", Or, "OrPredicate" passing the arguments to the construction method.
 492  
      *
 493  
      * @param name the name of the predicate to create.
 494  
      * @param args the args required to construct the predicate
 495  
      * @return the Predicate
 496  
      */
 497  
     public static Predicate dynConstruct(String name, Object... args) {
 498  38
         if (StringUtils.isBlank(name)) {
 499  0
             throw new IllegalArgumentException("name is blank");
 500  
         }
 501  
 
 502  38
         final String correctedName = CriteriaSupportUtils.findDynName(name);
 503  369
         for (Method m : PredicateFactory.class.getMethods()) {
 504  
 
 505  
             //currently this class does NOT overload therefore this method doesn't have to worry about
 506  
             //overload resolution - just get the Method handle based on the passed in name
 507  369
             if (m.getName().equals(correctedName)) {
 508  
                 try {
 509  38
                     return (Predicate) m.invoke(null, args);
 510  0
                 } catch (InvocationTargetException e) {
 511  0
                     throw new DynPredicateException(e);
 512  0
                 } catch (IllegalAccessException e) {
 513  0
                     throw new DynPredicateException(e);
 514  
                 }
 515  
             }
 516  
         }
 517  
 
 518  0
         throw new DynPredicateException("predicate: " + name + " doesn't exist");
 519  
     }
 520  
 
 521  
     //this is really a fatal error (programming error)
 522  
     //and therefore is just a private exception not really meant to be caught
 523  
     private static class DynPredicateException extends RuntimeException {
 524  
         DynPredicateException(Throwable t) {
 525  0
             super(t);
 526  0
         }
 527  
 
 528  
         DynPredicateException(String s) {
 529  0
             super(s);
 530  0
         }
 531  
     }
 532  
 }