View Javadoc

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