View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.core.api.criteria;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.search.SearchOperator;
20  
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.List;
24  import java.util.Map;
25  
26  import static org.kuali.rice.core.api.criteria.PredicateFactory.and;
27  import static org.kuali.rice.core.api.criteria.PredicateFactory.between;
28  import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
29  import static org.kuali.rice.core.api.criteria.PredicateFactory.equalIgnoreCase;
30  import static org.kuali.rice.core.api.criteria.PredicateFactory.greaterThan;
31  import static org.kuali.rice.core.api.criteria.PredicateFactory.greaterThanOrEqual;
32  import static org.kuali.rice.core.api.criteria.PredicateFactory.isNotNull;
33  import static org.kuali.rice.core.api.criteria.PredicateFactory.isNull;
34  import static org.kuali.rice.core.api.criteria.PredicateFactory.lessThan;
35  import static org.kuali.rice.core.api.criteria.PredicateFactory.lessThanOrEqual;
36  import static org.kuali.rice.core.api.criteria.PredicateFactory.likeIgnoreCase;
37  import static org.kuali.rice.core.api.criteria.PredicateFactory.notEqualIgnoreCase;
38  import static org.kuali.rice.core.api.criteria.PredicateFactory.notLike;
39  import static org.kuali.rice.core.api.criteria.PredicateFactory.or;
40  /**
41   * Duplicate override to fix wildcard searching not ignoring case. (used to work in OJB days) See line 136
42   * See
43   * https://jira.kuali.org/browse/KSENROLL-12762
44   * https://jira.kuali.org/browse/KULRICE-12642
45   *
46   */
47  public final class PredicateUtils {
48  
49      private PredicateUtils() {
50          throw new UnsupportedOperationException("do not call");
51      }
52  
53      public static Predicate convertObjectMapToPredicate(Map<String, Object> criteria) {
54          List<Predicate> p = new ArrayList<Predicate>();
55          for (Map.Entry<String, Object> entry : criteria.entrySet()) {
56              if (entry.getValue() != null) {
57                  if (entry.getValue() instanceof String) {
58                      p.add(equalIgnoreCase(entry.getKey(), (String)entry.getValue()));
59                  } else {
60                      p.add(equal(entry.getKey(), (String)entry.getValue()));
61                  }
62  
63              }
64          }
65          //wrap everything in an 'and'
66          return and(p.toArray(new Predicate[p.size()]));
67      }
68  
69  
70      /*
71       * Method to assist in converting a map of values for a lookup 
72       */
73      public static Predicate convertMapToPredicate(Map<String, String> criteria) {
74          List<Predicate> p = new ArrayList<Predicate>();
75          for (Map.Entry<String, String> entry : criteria.entrySet()) {
76              if (StringUtils.isNotBlank(entry.getValue())) {
77                  List<String> values = new ArrayList<String>();
78                  getValueRecursive(entry.getValue(), values);
79                  List<Predicate> tempPredicates = new ArrayList<Predicate>();
80                  p.addAll(tempPredicates);
81  
82                  // TODO: how to handle different types of data when everything comes in as string....
83                  for (String value : values) {
84                      tempPredicates.add(parsePredicate(entry.getKey(), value));
85                  }
86                  if (entry.getValue().contains(SearchOperator.AND.op())) {
87                      p.add(and(tempPredicates.toArray(new Predicate[tempPredicates.size()])));
88                  } else if (entry.getValue().contains(SearchOperator.OR.op())) {
89                      p.add(or(tempPredicates.toArray(new Predicate[tempPredicates.size()])));
90                  } else {
91                      p.addAll(tempPredicates);
92                  }
93              }
94          }
95          //wrap everything in an 'and'
96          return and(p.toArray(new Predicate[p.size()]));
97      }
98  
99      /**
100      * sort of parses a predicate out of a value
101      * @param key the map entry key
102      * @param value the expression value
103      * @return a parsed predicate or null if unable to parse expression
104      */
105     private static Predicate parsePredicate(String key, String value) {
106         if (value.contains(SearchOperator.NULL.op())) {
107             if (isNot(value)) {
108                 return isNotNull(key);
109             } else {
110                 return isNull(key);
111             }
112         } else if (value.contains(SearchOperator.BETWEEN_EXCLUSIVE_UPPER.op())) {
113             String[] betweenVals = StringUtils.split(value, SearchOperator.BETWEEN_EXCLUSIVE_UPPER.op());
114             if (betweenVals.length == 2) {
115                 return between(key, betweenVals[0], betweenVals[1], SearchOperator.BETWEEN_EXCLUSIVE_UPPER);
116             } // else ?
117             return null;
118         } else if (value.contains(SearchOperator.BETWEEN.op())) {
119             String[] betweenVals = StringUtils.split(value, SearchOperator.BETWEEN.op());
120             if (betweenVals.length == 2) {
121                 return between(key, betweenVals[0], betweenVals[1]);
122             } // else ?
123             return null;
124         } else if (value.contains(SearchOperator.GREATER_THAN_EQUAL.op())) {
125             return greaterThanOrEqual(key, StringUtils.replace(value, SearchOperator.GREATER_THAN_EQUAL.op(), ""));
126         } else if (value.contains(SearchOperator.LESS_THAN_EQUAL.op())) {
127             return lessThanOrEqual(key, StringUtils.replace(value, SearchOperator.LESS_THAN_EQUAL.op(), ""));
128         } else if (value.contains(SearchOperator.GREATER_THAN.op())) {
129             return greaterThan(key, StringUtils.replace(value, SearchOperator.GREATER_THAN.op(), ""));
130         } else if (value.contains(SearchOperator.LESS_THAN.op())) {
131             return lessThan(key, StringUtils.replace(value, SearchOperator.LESS_THAN.op(), ""));
132         } else if (value.contains(SearchOperator.LIKE_MANY.op()) || (value.contains(SearchOperator.LIKE_ONE.op()))) {
133             if (isNot(value)) {
134                 return notLike(key, stripNot(value));
135             } else {
136                 return likeIgnoreCase(key, value);//THIS IS THE LINE THAT CHANGED
137             }
138         } else {
139             if (isNot(value)) {
140                 return notEqualIgnoreCase(key, stripNot(value));
141             } else {
142                 return equalIgnoreCase(key, value);
143             }
144         }
145     }
146 
147     private static void getValueRecursive(String valueEntered, List<String> lRet) {
148         if(valueEntered == null) {
149             return;
150         }
151 
152         valueEntered = valueEntered.trim();
153         valueEntered = valueEntered.replaceAll("%", "*");
154         if(lRet == null){
155             throw new NullPointerException("The list passed in is by reference and should never be null.");
156         }
157 
158         if (StringUtils.contains(valueEntered, SearchOperator.OR.op())) {
159             List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.OR.op()));
160             for(String value : l){
161                 getValueRecursive(value, lRet);
162             }
163             return;
164         }
165         if (StringUtils.contains(valueEntered, SearchOperator.AND.op())) {
166             //splitValueList.addAll(Arrays.asList(StringUtils.split(valueEntered, KRADConstants.AND.op())));
167             List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.AND.op()));
168             for(String value : l){
169                 getValueRecursive(value, lRet);
170             }
171             return;
172         }
173 
174         // lRet is pass by ref and should NEVER be null
175         lRet.add(valueEntered);
176     }
177 
178     private static boolean isNot(String value) {
179         if (value == null) {
180             return false;
181         }
182         return value.contains(SearchOperator.NOT.op());
183     }
184 
185     // oh so hacky
186     private static String stripNot(String value) {
187         if (value.trim().startsWith(SearchOperator.NOT.op())) {
188             value = value.trim().replaceFirst(SearchOperator.NOT.op(), "");
189         }
190         return value;
191     }
192 }
193 
194