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