View Javadoc

1   /**
2    * Copyright 2005-2011 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.krad.datadictionary.validation;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.datetime.DateTimeService;
20  import org.kuali.rice.core.api.uif.DataType;
21  import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
22  
23  import java.math.BigDecimal;
24  import java.text.ParseException;
25  import java.util.Collection;
26  import java.util.Date;
27  
28  /**
29   * Inherited from Kuali Student and adapted extensively, this class provides static utility methods for validation processing. 
30   * 
31   * @author Kuali Rice Team (rice.collab@kuali.org)
32   */
33  public class ValidationUtils {
34  
35  	public static String buildPath(String attributePath, String attributeName) {
36  		if (StringUtils.isNotBlank(attributeName)) {
37  			if (StringUtils.isNotBlank(attributePath)) 
38  				return new StringBuilder(attributePath).append(".").append(attributeName).toString();
39  		
40  			return attributeName;
41  		}
42  		return attributePath;
43  	}
44  	
45  	/**
46  	 * Used to get the rightmost index value of an attribute path.
47  	 *  
48  	 * @param attributePath
49  	 * @return the right index of value of attribute path, -1 if path has no index
50  	 */
51  	public static int getLastPathIndex(String attributePath){
52  	    int index = -1;
53  	    
54  	    int leftBracket = attributePath.lastIndexOf("[");
55  	    int rightBracket = attributePath.lastIndexOf("]");
56  	    
57  	    if (leftBracket > 0 && rightBracket > leftBracket){
58  	        String indexString = attributePath.substring(leftBracket +1, rightBracket);
59  	        try {
60                  index = Integer.valueOf(indexString).intValue();
61              } catch (NumberFormatException e) {
62                  // Will just return -1
63              }
64  	    }
65  	    
66  	    return index;
67  	}
68  	
69  	public static boolean compareValues(Object value1, Object value2,
70  			DataType dataType, String operator, boolean isCaseSensitive, DateTimeService dateTimeService) {
71  
72  		boolean result = false;
73  		Integer compareResult = null;
74  
75  		if("has_value".equalsIgnoreCase(operator)){
76  			if(value1==null){
77  				return "false".equals(value2.toString().toLowerCase());
78  			}
79  			if (value1 instanceof String && ((String) value1).isEmpty()){
80  			    return "false".equals(value2.toString().toLowerCase());			    
81  			}
82  			if(value1 instanceof Collection && ((Collection<?>) value1).isEmpty()){
83  				return "false".equals(value2.toString().toLowerCase());
84  			}
85  			return "true".equals(value2.toString().toLowerCase());
86  		}		
87  		// Convert objects into appropriate data types
88  		if (null != dataType) {
89  			if (DataType.STRING.equals(dataType)) {
90  			    String v1 = getString(value1);
91  				String v2 = getString(value2);
92  
93  				if(!isCaseSensitive) {
94  				    v1 = v1.toUpperCase();
95  				    v2 = v2.toUpperCase();
96  				}
97  				
98  				compareResult = v1.compareTo(v2);
99  			} else if (DataType.INTEGER.equals(dataType)) {
100 				Integer v1 = getInteger(value1);
101 				Integer v2 = getInteger(value2);
102 				compareResult = v1.compareTo(v2);
103 			} else if (DataType.LONG.equals(dataType)) {
104 				Long v1 = getLong(value1);
105 				Long v2 = getLong(value2);
106 				compareResult = v1.compareTo(v2);
107 			} else if (DataType.DOUBLE.equals(dataType)) {
108 				Double v1 = getDouble(value1);
109 				Double v2 = getDouble(value2);
110 				compareResult = v1.compareTo(v2);
111 			} else if (DataType.FLOAT.equals(dataType)) {
112 				Float v1 = getFloat(value1);
113 				Float v2 = getFloat(value2);
114 				compareResult = v1.compareTo(v2);
115 			} else if (DataType.BOOLEAN.equals(dataType)) {
116 				Boolean v1 = getBoolean(value1);
117 				Boolean v2 = getBoolean(value2);
118 				compareResult = v1.compareTo(v2);
119 			} else if (DataType.DATE.equals(dataType)) {
120 				Date v1 = getDate(value1, dateTimeService);
121 				Date v2 = getDate(value2, dateTimeService);
122 				compareResult = v1.compareTo(v2);
123 			}
124 		}
125 
126 		if (null != compareResult) {
127 			if (("equals".equalsIgnoreCase(operator)
128 					|| "greater_than_equal".equalsIgnoreCase(operator) || "less_than_equal"
129 					.equalsIgnoreCase(operator))
130 					&& 0 == compareResult) {
131 				result = true;
132 			}
133 
134 			if (("not_equal".equalsIgnoreCase (operator)
135      || "greater_than".equalsIgnoreCase(operator)) && compareResult >= 1) {
136 				result = true;
137 			}
138 
139 			if (("not_equal".equalsIgnoreCase (operator)
140      || "less_than".equalsIgnoreCase(operator)) && compareResult <= -1) {
141 				result = true;
142 			}
143 		}
144 
145 		return result;
146 	}
147 
148 	public static Integer getInteger(Object o) {
149 		Integer result = null;
150 		if (o instanceof Integer)
151 			return (Integer) o;
152 		if (o == null)
153 			return null;
154 		if (o instanceof Number)
155 			return ((Number) o).intValue();
156 		String s = o.toString();
157 		if (s != null && s.trim().length() > 0) {
158 			result = Integer.valueOf(s.trim());
159 		}
160 		return result;
161 	}
162 
163 	public static Long getLong(Object o) {
164 		Long result = null;
165 		if (o instanceof Long)
166 			return (Long) o;
167 		if (o == null)
168 			return null;
169 		if (o instanceof Number)
170 			return ((Number) o).longValue();
171 		String s = o.toString();
172 		if (s != null && s.trim().length() > 0) {
173 			result = Long.valueOf(s.trim());
174 		}
175 		return result;
176 	}
177 
178 	public static Float getFloat(Object o) {
179 		Float result = null;
180 		if (o instanceof Float)
181 			return (Float) o;
182 		if (o == null)
183 			return null;
184 		if (o instanceof Number)
185 			return ((Number) o).floatValue();
186 		String s = o.toString();
187 		if (s != null && s.trim().length() > 0) {
188 			result = Float.valueOf(s.trim());
189 		}
190 		return result;
191 	}
192 
193 	public static Double getDouble(Object o) {
194 		Double result = null;
195 		if (o instanceof BigDecimal)
196 			return ((BigDecimal) o).doubleValue();
197 		if (o instanceof Double)
198 			return (Double) o;
199 		if (o == null)
200 			return null;
201 		if (o instanceof Number)
202 			return ((Number) o).doubleValue();
203 		String s = o.toString();
204 		if (s != null && s.trim().length() > 0) {
205 			result = Double.valueOf(s.trim());
206 		}
207 		return result;
208 	}
209 
210 	public static Date getDate(Object o, DateTimeService dateTimeService) throws IllegalArgumentException {
211 		Date result = null;
212 		if (o instanceof Date)
213 			return (Date) o;
214 		if (o == null)
215 			return null;
216 		String s = o.toString();
217 		if (s != null && s.trim().length() > 0) {
218 			try {
219 				result = dateTimeService.convertToDate(s.trim());
220 			} catch (ParseException e) {
221 				throw new IllegalArgumentException(e);
222 			} 
223 		}
224 		return result;
225 	}
226 
227 	public static String getString(Object o) {
228 		if (o instanceof String)
229 			return (String) o;
230 		if (o == null)
231 			return null;
232 		return o.toString();
233 	}
234 
235 	public static Boolean getBoolean(Object o) {
236 		Boolean result = null;
237 		if (o instanceof Boolean)
238 			return (Boolean) o;
239 		if (o == null)
240 			return null;
241 		String s = o.toString();
242 		if (s != null && s.trim().length() > 0) {
243 			result = Boolean.parseBoolean(s.trim());
244 		}
245 		return result;
246 	}	
247 	
248 
249     public static boolean hasText(String string) {
250 
251         if (string == null || string.length() < 1) {
252             return false;
253         }
254         int stringLength = string.length();
255 
256         for (int i = 0; i < stringLength; i++) {
257             char currentChar = string.charAt(i);
258             if (' ' != currentChar || '\t' != currentChar || '\n' != currentChar) {
259                 return true;
260             }
261         }
262 
263         return false;
264     }
265     
266     public static boolean isNullOrEmpty(Object value) {
267     	return value == null || (value instanceof String && StringUtils.isBlank(((String) value).trim()));
268     }
269     
270 	
271 	public static enum Result { VALID, INVALID, UNDEFINED };
272 	
273 	public static Object convertToDataType(Object value, DataType dataType, DateTimeService dateTimeService) throws AttributeValidationException {
274 		Object returnValue = value;
275 		
276 		if (null == value)
277 			return null;
278 		
279 		switch (dataType) {
280 		case BOOLEAN:
281 			if (! (value instanceof Boolean)) {
282 				returnValue = Boolean.valueOf(value.toString());
283 				
284 				// Since the Boolean.valueOf is exceptionally loose - it basically takes any string and makes it false
285 				if (!value.toString().equalsIgnoreCase("TRUE") && !value.toString().equalsIgnoreCase("FALSE"))
286 					throw new AttributeValidationException("Value " + value.toString() + " is not a boolean!");
287 			}
288 			break;
289 		case INTEGER:
290 			if (! (value instanceof Number)) {
291 				returnValue = Integer.valueOf(value.toString());
292 			}
293 			break;
294 		case LONG:
295 			if (! (value instanceof Number)) {
296 				returnValue = Long.valueOf(value.toString());
297 			}
298 			break;
299 		case DOUBLE:
300 			if (! (value instanceof Number)) {
301 				returnValue = Double.valueOf(value.toString());
302 			}
303 			if (((Double)returnValue).isNaN())
304 				throw new AttributeValidationException("Infinite Double values are not valid!");		
305 			if (((Double)returnValue).isInfinite())
306 				throw new AttributeValidationException("Infinite Double values are not valid!");
307 			break;
308 		case FLOAT:
309 			if (! (value instanceof Number)) {
310 				returnValue = Float.valueOf(value.toString());
311 			}
312 			if (((Float)returnValue).isNaN())
313 				throw new AttributeValidationException("NaN Float values are not valid!");
314 			if (((Float)returnValue).isInfinite())
315 				throw new AttributeValidationException("Infinite Float values are not valid!");
316 			break;
317 		case TRUNCATED_DATE:
318 		case DATE:
319 			if (! (value instanceof Date)) {
320 				try {
321 					returnValue = dateTimeService.convertToDate(value.toString());
322 				} catch (ParseException pe) {
323 					throw new AttributeValidationException("Value " + value.toString() + " is not a date!");
324 				}
325 			}
326 			break;
327 		case STRING:
328 		}
329 		
330 		return returnValue;
331 	}
332 	
333 	public static <T> Result isGreaterThan(T value, Comparable<T> limit) {
334 		return limit == null ? Result.UNDEFINED : ( limit.compareTo(value) < 0 ? Result.VALID : Result.INVALID );
335 	}
336 	
337 	public static <T> Result isGreaterThanOrEqual(T value, Comparable<T> limit) {
338 		return limit == null ? Result.UNDEFINED : ( limit.compareTo(value) <= 0 ? Result.VALID : Result.INVALID );
339 	}
340 	
341 	public static <T> Result isLessThan(T value, Comparable<T> limit) {
342 		return limit == null ? Result.UNDEFINED : ( limit.compareTo(value) > 0 ? Result.VALID : Result.INVALID );
343 	}
344 	
345 	public static <T> Result isLessThanOrEqual(T value, Comparable<T> limit) {
346 		return limit == null ? Result.UNDEFINED : ( limit.compareTo(value) >= 0 ? Result.VALID : Result.INVALID );
347 	}
348 	
349 	
350     public static String[] getPathTokens(String fieldPath) {
351         return (fieldPath != null && fieldPath.contains(".") ? fieldPath.split("\\.") : new String[]{fieldPath});
352     }
353 
354 }
355