001/**
002 * Copyright 2005-2016 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 */
016package org.kuali.rice.krad.datadictionary.validation;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.datetime.DateTimeService;
020import org.kuali.rice.core.api.uif.DataType;
021import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
022
023import java.math.BigDecimal;
024import java.text.ParseException;
025import java.util.Collection;
026import 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 */
033public 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) || "not_equals".equalsIgnoreCase (operator)
135     || "greater_than".equalsIgnoreCase(operator)) && compareResult >= 1) {
136                                result = true;
137                        }
138
139                        if (("not_equal".equalsIgnoreCase (operator) || "not_equals".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