View Javadoc
1   /**
2    * Copyright 2005-2015 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 static org.kuali.rice.core.api.criteria.PredicateFactory.and;
19  import static org.kuali.rice.core.api.criteria.PredicateFactory.between;
20  import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
21  import static org.kuali.rice.core.api.criteria.PredicateFactory.equalIgnoreCase;
22  import static org.kuali.rice.core.api.criteria.PredicateFactory.greaterThan;
23  import static org.kuali.rice.core.api.criteria.PredicateFactory.greaterThanOrEqual;
24  import static org.kuali.rice.core.api.criteria.PredicateFactory.isNotNull;
25  import static org.kuali.rice.core.api.criteria.PredicateFactory.isNull;
26  import static org.kuali.rice.core.api.criteria.PredicateFactory.lessThan;
27  import static org.kuali.rice.core.api.criteria.PredicateFactory.lessThanOrEqual;
28  import static org.kuali.rice.core.api.criteria.PredicateFactory.likeIgnoreCase;
29  import static org.kuali.rice.core.api.criteria.PredicateFactory.notEqualIgnoreCase;
30  import static org.kuali.rice.core.api.criteria.PredicateFactory.notLikeIgnoreCase;
31  import static org.kuali.rice.core.api.criteria.PredicateFactory.or;
32  
33  import java.util.ArrayList;
34  import java.util.Arrays;
35  import java.util.List;
36  import java.util.Map;
37  
38  import org.apache.commons.lang.StringUtils;
39  import org.kuali.rice.core.api.search.SearchOperator;
40  
41  public final class PredicateUtils {
42  
43      private PredicateUtils() {
44          throw new UnsupportedOperationException("do not call");
45      }
46  
47      public static Predicate convertObjectMapToPredicate(Map<String, Object> criteria) {
48          List<Predicate> p = new ArrayList<Predicate>();
49          for (Map.Entry<String, Object> entry : criteria.entrySet()) {
50              if (entry.getValue() != null) {
51                  if (entry.getValue() instanceof String) {
52                      p.add(equalIgnoreCase(entry.getKey(), (String)entry.getValue()));
53                  } else {
54                      p.add(equal(entry.getKey(), entry.getValue()));
55                  }
56  
57              }
58          }
59          //wrap everything in an 'and'
60          return and(p.toArray(new Predicate[p.size()]));
61      }
62  
63  
64      /*
65       * Method to assist in converting a map of values for a lookup
66       */
67      public static Predicate convertMapToPredicate(Map<String, String> criteria) {
68          List<Predicate> p = new ArrayList<Predicate>();
69          for (Map.Entry<String, String> entry : criteria.entrySet()) {
70              if (StringUtils.isNotBlank(entry.getValue())) {
71                  List<String> values = new ArrayList<String>();
72                  getValueRecursive(entry.getValue(), values);
73                  List<Predicate> tempPredicates = new ArrayList<Predicate>();
74                  p.addAll(tempPredicates);
75  
76                  // TODO: how to handle different types of data when everything comes in as string....
77                  for (String value : values) {
78                      tempPredicates.add(parsePredicate(entry.getKey(), value));
79                  }
80                  if (entry.getValue().contains(SearchOperator.AND.op())) {
81                      p.add(and(tempPredicates.toArray(new Predicate[tempPredicates.size()])));
82                  } else if (entry.getValue().contains(SearchOperator.OR.op())) {
83                      p.add(or(tempPredicates.toArray(new Predicate[tempPredicates.size()])));
84                  } else {
85                      p.addAll(tempPredicates);
86                  }
87              }
88          }
89          //wrap everything in an 'and'
90          return and(p.toArray(new Predicate[p.size()]));
91      }
92  
93      /**
94       * sort of parses a predicate out of a value
95       * @param key the map entry key
96       * @param value the expression value
97       * @return a parsed predicate or null if unable to parse expression
98       */
99      private static Predicate parsePredicate(String key, String value) {
100         if (value.contains(SearchOperator.NULL.op())) {
101             if (isNot(value)) {
102                 return isNotNull(key);
103             } else {
104                 return isNull(key);
105             }
106         } else if (value.contains(SearchOperator.BETWEEN_EXCLUSIVE_UPPER.op())) {
107             String[] betweenVals = StringUtils.split(value, SearchOperator.BETWEEN_EXCLUSIVE_UPPER.op());
108             if (betweenVals.length == 2) {
109                 return between(key, betweenVals[0], betweenVals[1], SearchOperator.BETWEEN_EXCLUSIVE_UPPER);
110             } // else ?
111             return null;
112         } else if (value.contains(SearchOperator.BETWEEN.op())) {
113             String[] betweenVals = StringUtils.split(value, SearchOperator.BETWEEN.op());
114             if (betweenVals.length == 2) {
115                 return between(key, betweenVals[0], betweenVals[1]);
116             } // else ?
117             return null;
118         } else if (value.contains(SearchOperator.GREATER_THAN_EQUAL.op())) {
119             return greaterThanOrEqual(key, StringUtils.replace(value, SearchOperator.GREATER_THAN_EQUAL.op(), ""));
120         } else if (value.contains(SearchOperator.LESS_THAN_EQUAL.op())) {
121             return lessThanOrEqual(key, StringUtils.replace(value, SearchOperator.LESS_THAN_EQUAL.op(), ""));
122         } else if (value.contains(SearchOperator.GREATER_THAN.op())) {
123             return greaterThan(key, StringUtils.replace(value, SearchOperator.GREATER_THAN.op(), ""));
124         } else if (value.contains(SearchOperator.LESS_THAN.op())) {
125             return lessThan(key, StringUtils.replace(value, SearchOperator.LESS_THAN.op(), ""));
126         } else if (value.contains(SearchOperator.LIKE_MANY.op()) || (value.contains(SearchOperator.LIKE_ONE.op()))) {
127             if (isNot(value)) {
128                 return notLikeIgnoreCase(key, stripNot(value));
129             } else {
130                 return likeIgnoreCase(key, value);
131             }
132         } else {
133             if (isNot(value)) {
134                 return notEqualIgnoreCase(key, stripNot(value));
135             } else {
136                 return equalIgnoreCase(key, value);
137             }
138         }
139     }
140 
141     private static void getValueRecursive(String valueEntered, List<String> lRet) {
142  		if(valueEntered == null) {
143  			return;
144  		}
145 
146  		valueEntered = valueEntered.trim();
147         valueEntered = valueEntered.replaceAll("%", "*");
148  		if(lRet == null){
149  			throw new NullPointerException("The list passed in is by reference and should never be null.");
150  		}
151 
152  		if (StringUtils.contains(valueEntered, SearchOperator.OR.op())) {
153  			List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.OR.op()));
154  			for(String value : l){
155  				getValueRecursive(value, lRet);
156  			}
157  			return;
158  		}
159  		if (StringUtils.contains(valueEntered, SearchOperator.AND.op())) {
160  			//splitValueList.addAll(Arrays.asList(StringUtils.split(valueEntered, KRADConstants.AND.op())));
161  			List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.AND.op()));
162  			for(String value : l){
163  				getValueRecursive(value, lRet);
164  			}
165  			return;
166  		}
167 
168  		// lRet is pass by ref and should NEVER be null
169  		lRet.add(valueEntered);
170     }
171 
172     private static boolean isNot(String value) {
173         if (value == null) {
174             return false;
175         }
176         return value.contains(SearchOperator.NOT.op());
177     }
178 
179     // oh so hacky
180     private static String stripNot(String value) {
181         if (value.trim().startsWith(SearchOperator.NOT.op())) {
182             value = value.trim().replaceFirst(SearchOperator.NOT.op(), "");
183         }
184         return value;
185     }
186 }
187 
188