001 /**
002 * Copyright 2005-2011 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.krad.datadictionary.validation;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.kuali.rice.core.api.datetime.DateTimeService;
020 import org.kuali.rice.core.api.uif.DataType;
021 import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
022
023 import java.math.BigDecimal;
024 import java.text.ParseException;
025 import java.util.Collection;
026 import java.util.Date;
027
028 /**
029 * Inherited from Kuali Student and adapted extensively, this class provides static utility methods for validation processing.
030 *
031 * @author Kuali Rice Team (rice.collab@kuali.org)
032 */
033 public class ValidationUtils {
034
035 public static String buildPath(String attributePath, String attributeName) {
036 if (StringUtils.isNotBlank(attributeName)) {
037 if (StringUtils.isNotBlank(attributePath))
038 return new StringBuilder(attributePath).append(".").append(attributeName).toString();
039
040 return attributeName;
041 }
042 return attributePath;
043 }
044
045 /**
046 * Used to get the rightmost index value of an attribute path.
047 *
048 * @param attributePath
049 * @return the right index of value of attribute path, -1 if path has no index
050 */
051 public static int getLastPathIndex(String attributePath){
052 int index = -1;
053
054 int leftBracket = attributePath.lastIndexOf("[");
055 int rightBracket = attributePath.lastIndexOf("]");
056
057 if (leftBracket > 0 && rightBracket > leftBracket){
058 String indexString = attributePath.substring(leftBracket +1, rightBracket);
059 try {
060 index = Integer.valueOf(indexString).intValue();
061 } catch (NumberFormatException e) {
062 // Will just return -1
063 }
064 }
065
066 return index;
067 }
068
069 public static boolean compareValues(Object value1, Object value2,
070 DataType dataType, String operator, boolean isCaseSensitive, DateTimeService dateTimeService) {
071
072 boolean result = false;
073 Integer compareResult = null;
074
075 if("has_value".equalsIgnoreCase(operator)){
076 if(value1==null){
077 return "false".equals(value2.toString().toLowerCase());
078 }
079 if (value1 instanceof String && ((String) value1).isEmpty()){
080 return "false".equals(value2.toString().toLowerCase());
081 }
082 if(value1 instanceof Collection && ((Collection<?>) value1).isEmpty()){
083 return "false".equals(value2.toString().toLowerCase());
084 }
085 return "true".equals(value2.toString().toLowerCase());
086 }
087 // Convert objects into appropriate data types
088 if (null != dataType) {
089 if (DataType.STRING.equals(dataType)) {
090 String v1 = getString(value1);
091 String v2 = getString(value2);
092
093 if(!isCaseSensitive) {
094 v1 = v1.toUpperCase();
095 v2 = v2.toUpperCase();
096 }
097
098 compareResult = v1.compareTo(v2);
099 } 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