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