Coverage Report - org.kuali.rice.core.impl.criteria.CriteriaLookupServiceOjbImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
CriteriaLookupServiceOjbImpl
5%
7/120
3%
3/76
4.059
CriteriaLookupServiceOjbImpl$1
0%
0/1
N/A
4.059
CriteriaLookupServiceOjbImpl$UnsupportedCountFlagException
0%
0/3
N/A
4.059
CriteriaLookupServiceOjbImpl$UnsupportedPredicateException
0%
0/3
N/A
4.059
 
 1  
 package org.kuali.rice.core.impl.criteria;
 2  
 
 3  
 import org.apache.ojb.broker.query.Criteria;
 4  
 import org.apache.ojb.broker.query.Query;
 5  
 import org.apache.ojb.broker.query.QueryFactory;
 6  
 import org.joda.time.DateTime;
 7  
 import org.kuali.rice.core.api.criteria.AndPredicate;
 8  
 import org.kuali.rice.core.api.criteria.CompositePredicate;
 9  
 import org.kuali.rice.core.api.criteria.CountFlag;
 10  
 import org.kuali.rice.core.api.criteria.CriteriaDateTimeValue;
 11  
 import org.kuali.rice.core.api.criteria.CriteriaLookupService;
 12  
 import org.kuali.rice.core.api.criteria.CriteriaValue;
 13  
 import org.kuali.rice.core.api.criteria.EqualIgnoreCasePredicate;
 14  
 import org.kuali.rice.core.api.criteria.EqualPredicate;
 15  
 import org.kuali.rice.core.api.criteria.GenericQueryResults;
 16  
 import org.kuali.rice.core.api.criteria.GreaterThanOrEqualPredicate;
 17  
 import org.kuali.rice.core.api.criteria.GreaterThanPredicate;
 18  
 import org.kuali.rice.core.api.criteria.InIgnoreCasePredicate;
 19  
 import org.kuali.rice.core.api.criteria.InPredicate;
 20  
 import org.kuali.rice.core.api.criteria.LessThanOrEqualPredicate;
 21  
 import org.kuali.rice.core.api.criteria.LessThanPredicate;
 22  
 import org.kuali.rice.core.api.criteria.LikePredicate;
 23  
 import org.kuali.rice.core.api.criteria.LookupCustomizer;
 24  
 import org.kuali.rice.core.api.criteria.MultiValuedPredicate;
 25  
 import org.kuali.rice.core.api.criteria.NotEqualIgnoreCasePredicate;
 26  
 import org.kuali.rice.core.api.criteria.NotEqualPredicate;
 27  
 import org.kuali.rice.core.api.criteria.NotInIgnoreCasePredicate;
 28  
 import org.kuali.rice.core.api.criteria.NotInPredicate;
 29  
 import org.kuali.rice.core.api.criteria.NotLikePredicate;
 30  
 import org.kuali.rice.core.api.criteria.NotNullPredicate;
 31  
 import org.kuali.rice.core.api.criteria.NullPredicate;
 32  
 import org.kuali.rice.core.api.criteria.OrPredicate;
 33  
 import org.kuali.rice.core.api.criteria.Predicate;
 34  
 import org.kuali.rice.core.api.criteria.PropertyPathPredicate;
 35  
 import org.kuali.rice.core.api.criteria.QueryByCriteria;
 36  
 import org.kuali.rice.core.api.criteria.SingleValuedPredicate;
 37  
 import org.kuali.rice.core.framework.persistence.ojb.dao.PlatformAwareDaoBaseOjb;
 38  
 
 39  
 import java.sql.Timestamp;
 40  
 import java.util.ArrayList;
 41  
 import java.util.HashSet;
 42  
 import java.util.List;
 43  
 import java.util.Set;
 44  
 
 45  2
 public class CriteriaLookupServiceOjbImpl extends PlatformAwareDaoBaseOjb implements CriteriaLookupService {
 46  
 
 47  
     @Override
 48  
     public <T> GenericQueryResults<T> lookup(final Class<T> queryClass, final QueryByCriteria criteria) {
 49  2
         return lookup(queryClass, criteria, LookupCustomizer.Builder.<T>create().build());
 50  
     }
 51  
 
 52  
     @Override
 53  
     public <T> GenericQueryResults<T> lookup(final Class<T> queryClass, final QueryByCriteria criteria, LookupCustomizer<T> customizer) {
 54  2
         if (queryClass == null) {
 55  1
             throw new IllegalArgumentException("queryClass is null");
 56  
         }
 57  
 
 58  1
         if (criteria == null) {
 59  1
             throw new IllegalArgumentException("criteria is null");
 60  
         }
 61  
 
 62  0
         if (customizer == null) {
 63  0
             throw new IllegalArgumentException("customizer is null");
 64  
         }
 65  
 
 66  0
         final Criteria parent = new Criteria();
 67  
 
 68  0
         if (criteria.getPredicate() != null) {
 69  0
             addPredicate(criteria.getPredicate(), parent, customizer.getPredicateTransform());
 70  
         }
 71  
 
 72  0
         switch (criteria.getCountFlag()) {
 73  
             case ONLY:
 74  0
                 return forCountOnly(queryClass, criteria, parent);
 75  
             case NONE:
 76  0
                 return forRowResults(queryClass, criteria, parent, criteria.getCountFlag(), customizer.getResultTransform());
 77  
             case INCLUDE:
 78  0
                 return forRowResults(queryClass, criteria, parent, criteria.getCountFlag(), customizer.getResultTransform());
 79  0
             default: throw new UnsupportedCountFlagException(criteria.getCountFlag());
 80  
         }
 81  
     }
 82  
 
 83  
     /** gets results where the actual rows are requested. */
 84  
     private <T> GenericQueryResults<T> forRowResults(final Class<T> queryClass, final QueryByCriteria criteria, final Criteria ojbCriteria, CountFlag flag, LookupCustomizer.Transform<T, T> transform) {
 85  0
         final Query ojbQuery = QueryFactory.newQuery(queryClass, ojbCriteria);
 86  0
         final GenericQueryResults.Builder<T> results = GenericQueryResults.Builder.<T>create();
 87  
 
 88  0
         if (flag == CountFlag.INCLUDE) {
 89  0
             results.setTotalRowCount(getPersistenceBrokerTemplate().getCount(ojbQuery));
 90  
         }
 91  
 
 92  
         //ojb's is 1 based, our query api is zero based
 93  0
         final int startAtIndex = criteria.getStartAtIndex() != null ? criteria.getStartAtIndex() + 1 : 1;
 94  0
         ojbQuery.setStartAtIndex(startAtIndex);
 95  
 
 96  0
         if (criteria.getMaxResults() != null) {
 97  
             //not subtracting one from MaxResults in order to retrieve
 98  
             //one extra row so that the MoreResultsAvailable field can be set
 99  0
             ojbQuery.setEndAtIndex(criteria.getMaxResults() + startAtIndex);
 100  
         }
 101  
 
 102  
         @SuppressWarnings("unchecked")
 103  0
         final List<T> rows = new ArrayList<T>(getPersistenceBrokerTemplate().getCollectionByQuery(ojbQuery));
 104  
 
 105  0
         if (criteria.getMaxResults() != null && rows.size() > criteria.getMaxResults()) {
 106  0
             results.setMoreResultsAvailable(true);
 107  
             //remove the extra row that was returned
 108  0
             rows.remove(criteria.getMaxResults().intValue());
 109  
         }
 110  
 
 111  0
         results.setResults(transformResults(rows, transform));
 112  0
         return results.build();
 113  
     }
 114  
 
 115  
     private static <T> List<T> transformResults(List<T> results, LookupCustomizer.Transform<T, T> transform) {
 116  0
         final List<T> list = new ArrayList<T>();
 117  0
         for (T r : results) {
 118  0
             list.add(transform.apply(r));
 119  
         }
 120  0
         return list;
 121  
     }
 122  
 
 123  
     /** gets results where only the count is requested. */
 124  
     private <T> GenericQueryResults<T> forCountOnly(final Class<T> queryClass, final QueryByCriteria criteria, final Criteria ojbCriteria) {
 125  0
         final Query ojbQuery = QueryFactory.newQuery(queryClass, ojbCriteria);
 126  0
         final GenericQueryResults.Builder<T> results = GenericQueryResults.Builder.<T>create();
 127  0
         results.setTotalRowCount(getPersistenceBrokerTemplate().getCount(ojbQuery));
 128  
 
 129  0
         return results.build();
 130  
     }
 131  
 
 132  
     /** adds a predicate to a Criteria.*/
 133  
     private void addPredicate(Predicate p, Criteria parent, LookupCustomizer.Transform<Predicate, Predicate> transform) {
 134  0
         p = transform.apply(p);
 135  
 
 136  0
         if (p instanceof PropertyPathPredicate) {
 137  0
             final String pp = ((PropertyPathPredicate) p).getPropertyPath();
 138  0
             if (p instanceof NotNullPredicate) {
 139  0
                 parent.addNotNull(pp);
 140  0
             } else if (p instanceof NullPredicate) {
 141  0
                 parent.addIsNull(pp);
 142  0
             } else if (p instanceof SingleValuedPredicate) {
 143  0
                 addSingleValuePredicate((SingleValuedPredicate) p, parent);
 144  0
             } else if (p instanceof MultiValuedPredicate) {
 145  0
                 addMultiValuePredicate((MultiValuedPredicate) p, parent);
 146  
             } else {
 147  0
                 throw new UnsupportedPredicateException(p);
 148  
             }
 149  0
         } else if (p instanceof CompositePredicate) {
 150  0
             addCompositePredicate((CompositePredicate) p, parent, transform);
 151  
         } else {
 152  0
             throw new UnsupportedPredicateException(p);
 153  
         }
 154  0
     }
 155  
 
 156  
     /** adds a single valued predicate to a Criteria. */
 157  
     private void addSingleValuePredicate(SingleValuedPredicate p, Criteria parent) {
 158  0
         final Object value = getVal(p.getValue());
 159  0
         final String pp = p.getPropertyPath();
 160  0
         if (p instanceof EqualPredicate) {
 161  0
             parent.addEqualTo(pp, value);
 162  0
         } else if (p instanceof EqualIgnoreCasePredicate) {
 163  0
             parent.addEqualTo(genUpperFunc(pp), ((String) value).toUpperCase());
 164  0
         } else if (p instanceof GreaterThanOrEqualPredicate) {
 165  0
             parent.addGreaterOrEqualThan(pp, value);
 166  0
         } else if (p instanceof GreaterThanPredicate) {
 167  0
             parent.addGreaterThan(pp, value);
 168  0
         } else if (p instanceof LessThanOrEqualPredicate) {
 169  0
             parent.addLessOrEqualThan(pp, value);
 170  0
         } else if (p instanceof LessThanPredicate) {
 171  0
             parent.addLessThan(pp, value);
 172  0
         } else if (p instanceof LikePredicate) {
 173  
             //no need to convert * or ? since ojb handles the conversion/escaping
 174  0
             parent.addLike(pp, value);
 175  0
         } else if (p instanceof NotEqualPredicate) {
 176  0
             parent.addNotEqualTo(pp, value);
 177  0
         } else if (p instanceof NotEqualIgnoreCasePredicate) {
 178  0
             parent.addNotEqualTo(genUpperFunc(pp), ((String) value).toUpperCase());
 179  0
         } else if (p instanceof NotLikePredicate) {
 180  0
             parent.addNotLike(pp, value);
 181  
         } else {
 182  0
             throw new UnsupportedPredicateException(p);
 183  
         }
 184  0
     }
 185  
 
 186  
     /** adds a multi valued predicate to a Criteria. */
 187  
     private void addMultiValuePredicate(MultiValuedPredicate p, Criteria parent) {
 188  0
         final String pp = p.getPropertyPath();
 189  0
         if (p instanceof InPredicate) {
 190  0
             final Set<?> values = getVals(p.getValues());
 191  0
             parent.addIn(pp, values);
 192  0
         } else if (p instanceof InIgnoreCasePredicate) {
 193  0
             final Set<String> values = toUpper(getValsUnsafe(((InIgnoreCasePredicate) p).getValues()));
 194  0
             parent.addIn(genUpperFunc(pp), values);
 195  0
         } else if (p instanceof NotInPredicate) {
 196  0
             final Set<?> values = getVals(p.getValues());
 197  0
             parent.addNotIn(pp, values);
 198  0
         } else if (p instanceof NotInIgnoreCasePredicate) {
 199  0
             final Set<String> values = toUpper(getValsUnsafe(((NotInIgnoreCasePredicate) p).getValues()));
 200  0
             parent.addNotIn(genUpperFunc(pp), values);
 201  0
         } else {
 202  0
             throw new UnsupportedPredicateException(p);
 203  
         }
 204  0
     }
 205  
 
 206  
     /** adds a composite predicate to a Criteria. */
 207  
     private void addCompositePredicate(final CompositePredicate p, final Criteria parent,  LookupCustomizer.Transform<Predicate, Predicate> transform) {
 208  0
         for (Predicate ip : p.getPredicates()) {
 209  0
             final Criteria inner = new Criteria();
 210  0
             addPredicate(ip, inner, transform);
 211  0
             if (p instanceof AndPredicate) {
 212  0
                 parent.addAndCriteria(inner);
 213  0
             } else if (p instanceof OrPredicate) {
 214  0
                 parent.addOrCriteria(inner);
 215  
             } else {
 216  0
                 throw new UnsupportedPredicateException(p);
 217  
             }
 218  0
         }
 219  0
     }
 220  
 
 221  
     private static <U extends CriteriaValue<?>> Object getVal(U toConv) {
 222  0
         Object o = toConv.getValue();
 223  0
         if (o instanceof DateTime) {
 224  0
             return new Timestamp(((DateTime) o).getMillis());
 225  
         }
 226  0
         return o;
 227  
     }
 228  
 
 229  
     //this is unsafe b/c values could be converted resulting in a classcast exception
 230  
     @SuppressWarnings("unchecked")
 231  
     private static <T, U extends CriteriaValue<T>> Set<T> getValsUnsafe(Set<? extends U> toConv) {
 232  0
         return (Set<T>) getVals(toConv);
 233  
     }
 234  
 
 235  
     private static Set<?> getVals(Set<? extends CriteriaValue<?>> toConv) {
 236  0
         final Set<Object> values = new HashSet<Object>();
 237  0
         for (CriteriaValue<?> value : toConv) {
 238  0
             values.add(getVal(value));
 239  
         }
 240  0
         return values;
 241  
     }
 242  
 
 243  
     //eliding performance for function composition....
 244  
     private static Set<String> toUpper(Set<String> strs) {
 245  0
         final Set<String> values = new HashSet<String>();
 246  0
         for (String value : strs) {
 247  0
             values.add(value.toUpperCase());
 248  
         }
 249  0
         return values;
 250  
     }
 251  
 
 252  
     private String getUpperFunction() {
 253  0
         return getDbPlatform().getUpperCaseFunction();
 254  
     }
 255  
 
 256  
     private String genUpperFunc(String pp) {
 257  0
         return new StringBuilder(getUpperFunction()).append("(").append(pp).append(")").toString();
 258  
     }
 259  
 
 260  
     /** this is a fatal error since this implementation should support all known predicates. */
 261  0
     private static class UnsupportedPredicateException extends RuntimeException {
 262  
         private UnsupportedPredicateException(Predicate predicate) {
 263  0
             super("Unsupported predicate [" + String.valueOf(predicate) + "]");
 264  0
         }
 265  
     }
 266  
 
 267  
     /** this is a fatal error since this implementation should support all known count flags. */
 268  0
     private static class UnsupportedCountFlagException extends RuntimeException {
 269  
         private UnsupportedCountFlagException(CountFlag flag) {
 270  0
             super("Unsupported predicate [" + String.valueOf(flag) + "]");
 271  0
         }
 272  
     }
 273  
 }