Coverage Report - org.kuali.student.common.validator.DefaultValidatorImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultValidatorImpl
55%
298/537
41%
179/434
7.2
 
 1  
 /**
 2  
  * Copyright 2010 The Kuali Foundation Licensed under the Educational Community License, Version 2.0 (the "License"); you may
 3  
  * not use this file except in compliance with the License. You may obtain a copy of the License at
 4  
  * http://www.osedu.org/licenses/ECL-2.0 Unless required by applicable law or agreed to in writing, software distributed
 5  
  * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 6  
  * implied. See the License for the specific language governing permissions and limitations under the License.
 7  
  */
 8  
 
 9  
 package org.kuali.student.common.validator;
 10  
 
 11  
 import java.lang.reflect.InvocationTargetException;
 12  
 import java.util.ArrayList;
 13  
 import java.util.Collection;
 14  
 import java.util.Date;
 15  
 import java.util.HashMap;
 16  
 import java.util.Iterator;
 17  
 import java.util.List;
 18  
 import java.util.Map;
 19  
 import java.util.Stack;
 20  
 
 21  
 import org.apache.commons.beanutils.PropertyUtils;
 22  
 import org.apache.log4j.Logger;
 23  
 import org.kuali.student.common.dictionary.dto.CaseConstraint;
 24  
 import org.kuali.student.common.dictionary.dto.CommonLookupParam;
 25  
 import org.kuali.student.common.dictionary.dto.Constraint;
 26  
 import org.kuali.student.common.dictionary.dto.DataType;
 27  
 import org.kuali.student.common.dictionary.dto.FieldDefinition;
 28  
 import org.kuali.student.common.dictionary.dto.LookupConstraint;
 29  
 import org.kuali.student.common.dictionary.dto.MustOccurConstraint;
 30  
 import org.kuali.student.common.dictionary.dto.ObjectStructureDefinition;
 31  
 import org.kuali.student.common.dictionary.dto.RequiredConstraint;
 32  
 import org.kuali.student.common.dictionary.dto.ValidCharsConstraint;
 33  
 import org.kuali.student.common.dictionary.dto.WhenConstraint;
 34  
 import org.kuali.student.common.messages.dto.Message;
 35  
 import org.kuali.student.common.messages.service.MessageService;
 36  
 import org.kuali.student.common.search.dto.SearchParam;
 37  
 import org.kuali.student.common.search.dto.SearchRequest;
 38  
 import org.kuali.student.common.search.dto.SearchResult;
 39  
 import org.kuali.student.common.search.service.SearchDispatcher;
 40  
 import org.kuali.student.common.util.MessageUtils;
 41  
 import org.kuali.student.common.validation.dto.ValidationResultInfo;
 42  
 import org.kuali.student.common.validation.dto.ValidationResultInfo.ErrorLevel;
 43  
 import org.springframework.beans.BeanUtils;
 44  
 
 45  18
 public class DefaultValidatorImpl extends BaseAbstractValidator {
 46  1
     final static Logger LOG = Logger.getLogger(DefaultValidatorImpl.class);
 47  
 
 48  18
     private MessageService messageService = null;
 49  
 
 50  
     private SearchDispatcher searchDispatcher;
 51  
 
 52  18
     private String messageLocaleKey = "en";
 53  
 
 54  18
     private String messageGroupKey = "validation";
 55  
 
 56  18
     private DateParser dateParser = new ServerDateParser();
 57  
 
 58  18
     private boolean serverSide = true;
 59  
 
 60  
     public MessageService getMessageService() {
 61  0
         return messageService;
 62  
     }
 63  
 
 64  
     public void setMessageService(MessageService messageService) {
 65  9
         this.messageService = messageService;
 66  9
     }
 67  
 
 68  
     public String getMessageLocaleKey() {
 69  0
         return messageLocaleKey;
 70  
     }
 71  
 
 72  
     public void setMessageLocaleKey(String messageLocaleKey) {
 73  0
         this.messageLocaleKey = messageLocaleKey;
 74  0
     }
 75  
 
 76  
     public String getMessageGroupKey() {
 77  0
         return messageGroupKey;
 78  
     }
 79  
 
 80  
     public void setMessageGroupKey(String messageGroupKey) {
 81  0
         this.messageGroupKey = messageGroupKey;
 82  0
     }
 83  
 
 84  
     public void setDateParser(DateParser dateParser) {
 85  9
         this.dateParser = dateParser;
 86  9
     }
 87  
 
 88  
         /**
 89  
      * @return the serverSide
 90  
      */
 91  
     public boolean isServerSide() {
 92  0
         return serverSide;
 93  
     }
 94  
 
 95  
     /**
 96  
      * @param serverSide
 97  
      *            the serverSide to set
 98  
      */
 99  
     public void setServerSide(boolean serverSide) {
 100  0
         this.serverSide = serverSide;
 101  0
     }
 102  
 
 103  
     /**
 104  
      * @return the dateParser
 105  
      */
 106  
     public DateParser getDateParser() {
 107  0
         return dateParser;
 108  
     }
 109  
 
 110  
     /**
 111  
      * Validate Object and all its nested child objects for given type and state
 112  
      *
 113  
      * @param data
 114  
      * @param objStructure
 115  
      * @return
 116  
      */
 117  
     public List<ValidationResultInfo> validateObject(Object data, ObjectStructureDefinition objStructure) {
 118  
 
 119  12
         List<ValidationResultInfo> results = new ArrayList<ValidationResultInfo>();
 120  12
             Stack<String> elementStack = new Stack<String>();
 121  
 
 122  12
        validateObject(results, data, objStructure, elementStack, data, objStructure, true);
 123  
        
 124  12
        return results;
 125  
     }
 126  
 
 127  
     private void validateObject(List<ValidationResultInfo> results, Object data, ObjectStructureDefinition objStructure, Stack<String> elementStack,  Object rootData, ObjectStructureDefinition rootObjStructure, boolean isRoot) {
 128  
 
 129  17
         ConstraintDataProvider dataProvider = new BeanConstraintDataProvider();
 130  17
         dataProvider.initialize(data);
 131  
 
 132  
         // Push object structure to the top of the stack
 133  17
         StringBuilder objXPathElement = new StringBuilder(dataProvider.getPath());
 134  
 
 135  17
         if(!isRoot && !objXPathElement.toString().isEmpty()){
 136  0
                 elementStack.push(objXPathElement.toString());
 137  
         }
 138  
 
 139  
         /*
 140  
          * Do nothing if the object to be validated is not type/state or if the objectstructure with constraints is not
 141  
          * provided
 142  
          */
 143  17
         if (null == objStructure) {
 144  0
             return;
 145  
         }
 146  
 
 147  17
         for (FieldDefinition f : objStructure.getAttributes()) {
 148  83
             validateField(results, f, objStructure, dataProvider, elementStack, rootData, rootObjStructure);
 149  
 
 150  
             // Use Custom Validators
 151  83
             if (f.getCustomValidatorClass() != null || f.isServerSide() && serverSide) {
 152  0
                     Validator customValidator = validatorFactory.getValidator(f.getCustomValidatorClass());
 153  0
                     if(customValidator==null){
 154  0
                             throw new RuntimeException("Custom Validator "+f.getCustomValidatorClass()+" was not configured in this context");
 155  
                     }
 156  0
                     List<ValidationResultInfo> l = customValidator.validateObject(f,data, objStructure,elementStack);
 157  0
                     results.addAll(l);
 158  83
             }
 159  
         }
 160  17
         if(!isRoot && !objXPathElement.toString().isEmpty()){
 161  0
                 elementStack.pop();
 162  
         }
 163  
 
 164  
         /* All Field validations are returned right now */
 165  
         // List<ValidationResultInfo> resultsBuffer = new
 166  
         // ArrayList<ValidationResultInfo>();
 167  
         // for (ValidationResultContainer vc : results) {
 168  
         // if (skipFields.contains(vc.getElement()) == false) {
 169  
         // resultsBuffer.add(vc);
 170  
         // }
 171  
         // }
 172  
         // results = resultsBuffer;
 173  17
     }
 174  
 
 175  
     public void validateField(List<ValidationResultInfo> results, FieldDefinition field, ObjectStructureDefinition objStruct, ConstraintDataProvider dataProvider, Stack<String> elementStack,  Object rootData, ObjectStructureDefinition rootObjectStructure) {
 176  
 
 177  83
         Object value = dataProvider.getValue(field.getName());
 178  
 
 179  
         // Handle null values in field
 180  83
         if (value == null || "".equals(value.toString().trim())) {
 181  29
             processConstraint(results, field, objStruct, value, dataProvider, elementStack, rootData, rootObjectStructure);
 182  29
             return; //no need to do further processing
 183  
         }
 184  
 
 185  
         /*
 186  
          * For complex object structures only the following constraints apply 1. TypeStateCase 2. MinOccurs 3. MaxOccurs
 187  
          */
 188  54
         if (DataType.COMPLEX.equals(field.getDataType())) {
 189  5
             ObjectStructureDefinition nestedObjStruct = null;
 190  
 
 191  5
             if (null != field.getDataObjectStructure()) {
 192  5
                 nestedObjStruct = field.getDataObjectStructure();
 193  
             }
 194  
 
 195  5
             elementStack.push(field.getName());
 196  
 //                   beanPathStack.push(field.isDynamic()?"attributes("+field.getName()+")":field.getName());
 197  
 
 198  5
             if (value instanceof Collection) {
 199  
 
 200  5
                 String xPathForCollection = getElementXpath(elementStack) + "/*";
 201  
 
 202  5
                 int i=0;
 203  5
                 for (Object o : (Collection<?>) value) {
 204  5
                         elementStack.push(Integer.toString(i));
 205  
 //                        beanPathStack.push(!beanPathStack.isEmpty()?beanPathStack.pop():""+"["+i+"]");
 206  5
                     processNestedObjectStructure(results, o, nestedObjStruct, field, elementStack, rootData, rootObjectStructure);
 207  
 //                    beanPathStack.pop();
 208  
 //                    beanPathStack.push(field.isDynamic()?"attributes("+field.getName()+")":field.getName());
 209  5
                     elementStack.pop();
 210  5
                     i++;
 211  
                 }
 212  5
                 if (field.getMinOccurs() != null && field.getMinOccurs() > ((Collection<?>) value).size()) {
 213  0
                     ValidationResultInfo valRes = new ValidationResultInfo(xPathForCollection, value);
 214  0
                     valRes.setError(MessageUtils.interpolate(getMessage("validation.minOccurs"), toMap(field)));
 215  0
                     results.add(valRes);
 216  
                 }
 217  
 
 218  5
                 Integer maxOccurs = tryParse(field.getMaxOccurs());
 219  5
                 if (maxOccurs != null && maxOccurs < ((Collection<?>) value).size()) {
 220  0
                     ValidationResultInfo valRes = new ValidationResultInfo(xPathForCollection, value);
 221  0
                     valRes.setError(MessageUtils.interpolate(getMessage("validation.maxOccurs"), toMap(field)));
 222  0
                     results.add(valRes);
 223  
                 }
 224  5
             } else {
 225  0
                 if (null != value) {
 226  0
                     processNestedObjectStructure(results, value, nestedObjStruct, field, elementStack, rootData, rootObjectStructure);
 227  
                 } else {
 228  0
                     if (field.getMinOccurs() != null && field.getMinOccurs() > 0) {
 229  0
                         ValidationResultInfo val = new ValidationResultInfo(getElementXpath(elementStack), value);
 230  0
                         if(field.getLabelKey()!=null){
 231  0
                                 val.setError(getMessage(field.getLabelKey()));
 232  
                         } else {
 233  0
                                 val.setError(getMessage("validation.required"));
 234  
                         }
 235  0
                         results.add(val);
 236  
                     }
 237  
                 }
 238  
             }
 239  
             
 240  
 //            beanPathStack.pop();
 241  5
             elementStack.pop();
 242  
 
 243  5
         } else { // If non complex data type
 244  
 
 245  49
             if (value instanceof Collection) {
 246  
 
 247  0
                 if(((Collection<?>)value).isEmpty()){
 248  0
                     processConstraint(results, field, objStruct, "", dataProvider, elementStack, rootData, rootObjectStructure);
 249  
                 }
 250  
 
 251  0
                     int i = 0;
 252  0
                 for (Object o : (Collection<?>) value) {
 253  
                         //This is tricky, change the field name to the index in the elementStack(this is for lists of non complex types)
 254  0
                         elementStack.push(field.getName());
 255  0
                         FieldDefinition tempField = new FieldDefinition();
 256  0
                         BeanUtils.copyProperties(field, tempField);
 257  0
                         tempField.setName(Integer.toBinaryString(i));
 258  0
                         processConstraint(results, tempField, objStruct, o, dataProvider, elementStack, rootData, rootObjectStructure);
 259  0
                         elementStack.pop();
 260  0
                     i++;
 261  0
                 }
 262  
 
 263  0
                 String xPath = getElementXpath(elementStack) + "/" + field.getName() + "/*";
 264  0
                 if (field.getMinOccurs() != null && field.getMinOccurs() > ((Collection<?>) value).size()) {
 265  0
                     ValidationResultInfo valRes = new ValidationResultInfo(xPath, value);
 266  0
                     valRes.setError(MessageUtils.interpolate(getMessage("validation.minOccurs"), toMap(field)));
 267  0
                     results.add(valRes);
 268  
                 }
 269  
 
 270  0
                 Integer maxOccurs = tryParse(field.getMaxOccurs());
 271  0
                 if (maxOccurs != null && maxOccurs < ((Collection<?>) value).size()) {
 272  0
                     ValidationResultInfo valRes = new ValidationResultInfo(xPath, value);
 273  0
                     valRes.setError(MessageUtils.interpolate(getMessage("validation.maxOccurs"), toMap(field)));
 274  0
                     results.add(valRes);
 275  
                 }
 276  0
             } else {
 277  49
                 processConstraint(results, field, objStruct, value, dataProvider, elementStack, rootData, rootObjectStructure);
 278  
             }
 279  
 
 280  
         }
 281  54
     }
 282  
 
 283  
     protected Integer tryParse(String s) {
 284  46
         Integer result = null;
 285  46
         if (s != null) {
 286  
             try {
 287  40
                 result = Integer.valueOf(s);
 288  0
             } catch (NumberFormatException e) {
 289  
                 // do nothing
 290  40
             }
 291  
         }
 292  46
         return result;
 293  
     }
 294  
 
 295  
     protected void processNestedObjectStructure(List<ValidationResultInfo> results, Object value, ObjectStructureDefinition nestedObjStruct, FieldDefinition field, Stack<String> elementStack,  Object rootData, ObjectStructureDefinition rootObjStructure) {
 296  5
         validateObject(results, value, nestedObjStruct, elementStack, rootData, rootObjStructure, false);
 297  5
     }
 298  
 
 299  
     protected void processConstraint(List<ValidationResultInfo> valResults, FieldDefinition field, ObjectStructureDefinition objStructure, Object value, ConstraintDataProvider dataProvider, Stack<String> elementStack,  Object rootData, ObjectStructureDefinition rootObjStructure) {
 300  
 
 301  
         // Process Case Constraint
 302  
         // Case Constraint are only evaluated on the field. Nested case constraints are currently ignored
 303  78
         Constraint caseConstraint = processCaseConstraint(valResults, field.getCaseConstraint(), objStructure, value, dataProvider, elementStack, rootData, rootObjStructure);
 304  
 
 305  78
         Constraint constraint = (null != caseConstraint) ? caseConstraint : field;
 306  
 
 307  78
         processBaseConstraints(valResults, constraint, field, value, elementStack);
 308  
         
 309  
         // Stop other checks if value is null
 310  78
         if (value == null || "".equals(value.toString().trim())) {
 311  29
             return;
 312  
         }
 313  
 
 314  49
         String elementPath = getElementXpath(elementStack) + "/" + field.getName();
 315  
 
 316  
         // Process Valid Chars
 317  49
         if (null != constraint.getValidChars()) {
 318  21
             ValidationResultInfo val = processValidCharConstraint(elementPath, constraint.getValidChars(), dataProvider, value);
 319  21
             if (null != val) {
 320  3
                 valResults.add(val);
 321  
             }
 322  
         }
 323  
 
 324  
         // Process Require Constraints (only if this field has value)
 325  49
         if (value != null && !"".equals(value.toString().trim())) {
 326  49
             if (null != constraint.getRequireConstraint() && constraint.getRequireConstraint().size() > 0) {
 327  5
                 for (RequiredConstraint rc : constraint.getRequireConstraint()) {
 328  5
                     ValidationResultInfo val = processRequireConstraint(elementPath, rc, field, objStructure, dataProvider);
 329  5
                     if (null != val) {
 330  1
                         valResults.add(val);
 331  
                         //FIXME: For clarity, might be better to handle this in the processRequireConstraint method instead.
 332  1
                         processCrossFieldWarning(valResults, rc, val.getErrorLevel(), field.getName());
 333  
                     }
 334  5
                 }
 335  
             }
 336  
         }
 337  
 
 338  
         // Process Occurs Constraint
 339  49
         if (null != constraint.getOccursConstraint() && constraint.getOccursConstraint().size() > 0) {
 340  0
             for (MustOccurConstraint oc : constraint.getOccursConstraint()) {
 341  0
                 ValidationResultInfo val = processOccursConstraint(elementPath, oc, field, objStructure, dataProvider);
 342  0
                 if (null != val) {
 343  0
                     valResults.add(val); 
 344  
                 }
 345  0
             }
 346  
         }
 347  
 
 348  
         // Process lookup Constraint
 349  49
         if (null != constraint.getLookupDefinition()) {
 350  4
             processLookupConstraint(valResults, constraint.getLookupDefinition(), field, elementStack, dataProvider,objStructure, rootData, rootObjStructure, value);
 351  
         }
 352  49
     }
 353  
 
 354  
     protected ValidationResultInfo processRequireConstraint(String element, RequiredConstraint constraint, FieldDefinition field, ObjectStructureDefinition objStructure, ConstraintDataProvider dataProvider) {
 355  
 
 356  5
         ValidationResultInfo val = null;
 357  
 
 358  5
         String fieldName = constraint.getFieldPath();// TODO parse fieldname from here
 359  5
         Object fieldValue = dataProvider.getValue(fieldName);
 360  
 
 361  5
         boolean result = true;
 362  
 
 363  5
         if (fieldValue instanceof java.lang.String) {
 364  5
             result = hasText((String) fieldValue);
 365  0
         } else if (fieldValue instanceof Collection) {
 366  0
             result = (((Collection<?>) fieldValue).size() > 0);
 367  
         } else {
 368  0
             result = (null != fieldValue) ? true : false;
 369  
         }
 370  
 
 371  5
         if (!result) {
 372  1
             Map<String, Object> rMap = new HashMap<String, Object>();
 373  1
             rMap.put("field1", field.getName());
 374  1
             rMap.put("field2", fieldName);
 375  1
             val = new ValidationResultInfo(element, fieldValue);
 376  1
             val.setMessage(MessageUtils.interpolate(getMessage("validation.requiresField"), rMap));
 377  1
             val.setLevel(constraint.getErrorLevel());                       
 378  
         }
 379  
 
 380  5
         return val;
 381  
     }
 382  
 
 383  
     /**
 384  
      * Process caseConstraint tag and sets any of the base constraint items if any of the when condition matches
 385  
      *
 386  
      * @param caseConstraint
 387  
      * @param caseConstraint
 388  
      * @param field
 389  
      */
 390  
     protected Constraint processCaseConstraint(List<ValidationResultInfo> valResults, CaseConstraint caseConstraint, ObjectStructureDefinition objStructure, Object value, ConstraintDataProvider dataProvider, Stack<String> elementStack,  Object rootData, ObjectStructureDefinition rootObjStructure) {
 391  
 
 392  80
         if (null == caseConstraint) {
 393  56
             return null;
 394  
         }
 395  
 
 396  24
         String operator = (hasText(caseConstraint.getOperator())) ? caseConstraint.getOperator() : "EQUALS";
 397  24
         FieldDefinition caseField = null;
 398  24
         boolean absolutePath = false;
 399  24
         if(hasText(caseConstraint.getFieldPath())){
 400  24
                 if(caseConstraint.getFieldPath().startsWith("/")){
 401  0
                         absolutePath = true;
 402  0
                         caseField = ValidatorUtils.getField(caseConstraint.getFieldPath().substring(1), rootObjStructure);
 403  
                 }else{
 404  24
                         caseField = ValidatorUtils.getField(caseConstraint.getFieldPath(), objStructure); 
 405  
                 }
 406  
         }
 407  
 
 408  
         // TODO: What happens when the field is not in the dataProvider?
 409  24
         Object fieldValue = value;
 410  24
         if(caseField!=null){
 411  7
                 if(absolutePath){
 412  
                         try {
 413  0
                                 if(caseField.isDynamic()){
 414  
                                         //Pull the value from the dynamic attribute map
 415  
                                         //TODO There needs to be some mapping from PropertyUtils to the KS path
 416  
                                         //Until then, this will only work for root level properties
 417  0
                                         Map<String,String> attributes = (Map<String,String>) PropertyUtils.getNestedProperty(rootData, "attributes");
 418  0
                                         if(attributes!=null){
 419  0
                                                 fieldValue = attributes.get(caseConstraint.getFieldPath().substring(1));
 420  
                                         }
 421  0
                                 }else{
 422  0
                                         fieldValue = PropertyUtils.getNestedProperty(rootData, caseConstraint.getFieldPath().substring(1));
 423  
                                 }
 424  0
                                 } catch (IllegalAccessException e) {
 425  0
                                 } catch (InvocationTargetException e) {
 426  0
                                 } catch (NoSuchMethodException e) {
 427  0
                                 }
 428  
                 }else{
 429  7
                     fieldValue = dataProvider.getValue(caseField.getName());
 430  
                 }
 431  
         }
 432  24
         DataType fieldDataType = (null != caseField ? caseField.getDataType():null);
 433  
 
 434  
         // If fieldValue is null then skip Case check
 435  24
         if(null == fieldValue) {
 436  11
             return null;
 437  
         }
 438  
 
 439  
         // Extract value for field Key
 440  13
         for (WhenConstraint wc : caseConstraint.getWhenConstraint()) {
 441  
 
 442  19
                 if(hasText(wc.getValuePath())){
 443  0
                         Object whenValue = null;
 444  0
                         if(wc.getValuePath().startsWith("/")){
 445  
                                 try {
 446  0
                                         whenValue = PropertyUtils.getNestedProperty(rootData, wc.getValuePath().substring(1));
 447  0
                                         } catch (IllegalAccessException e) {
 448  0
                                         } catch (InvocationTargetException e) {
 449  0
                                         } catch (NoSuchMethodException e) {
 450  0
                                         }
 451  
                         }else{
 452  0
                                 whenValue = dataProvider.getValue(wc.getValuePath());
 453  
                         }
 454  0
                         if (ValidatorUtils.compareValues(fieldValue, whenValue, fieldDataType, operator, caseConstraint.isCaseSensitive(), dateParser) && null != wc.getConstraint()) {                    
 455  0
                                 Constraint constraint = wc.getConstraint();
 456  0
                                 if (constraint.getCaseConstraint() != null){
 457  0
                                         return processCaseConstraint(valResults, constraint.getCaseConstraint(), objStructure, value, dataProvider, elementStack, rootData, rootObjStructure);
 458  
                                 } else {
 459  0
                                         processCrossFieldWarning(valResults, caseConstraint, constraint, value, constraint.getErrorLevel());
 460  0
                                         return constraint;
 461  
                                 }
 462  
                 }
 463  0
                 }else{
 464  19
                         List<Object> whenValueList = wc.getValues();
 465  
             
 466  19
                     for (Object whenValue : whenValueList) {
 467  21
                         if (ValidatorUtils.compareValues(fieldValue, whenValue, fieldDataType, operator, caseConstraint.isCaseSensitive(), dateParser) && null != wc.getConstraint()) {
 468  3
                                         Constraint constraint = wc.getConstraint();
 469  3
                                         if (constraint.getCaseConstraint() != null){
 470  2
                                                 return processCaseConstraint(valResults, constraint.getCaseConstraint(), objStructure, value, dataProvider, elementStack, rootData, rootObjStructure);
 471  
                                         } else {
 472  1
                                                 processCrossFieldWarning(valResults, caseConstraint, constraint, value, constraint.getErrorLevel());                                                
 473  1
                                                 return constraint;
 474  
                                         }
 475  
                         }
 476  
                     }
 477  16
                 }
 478  
         }
 479  
 
 480  10
         return null;
 481  
     }
 482  
 
 483  
     public ValidationResultInfo processValidCharConstraint(String element, ValidCharsConstraint vcConstraint, ConstraintDataProvider dataProvider, Object value) {
 484  
 
 485  21
         ValidationResultInfo val = null;
 486  
 
 487  21
         StringBuilder fieldValue = new StringBuilder();
 488  21
         String validChars = vcConstraint.getValue();
 489  
 
 490  21
         fieldValue.append(ValidatorUtils.getString(value));
 491  
 
 492  21
         int typIdx = validChars.indexOf(":");
 493  21
         String processorType = "regex";
 494  21
         if (-1 == typIdx) {
 495  0
             validChars = "[" + validChars + "]*";
 496  
         } else {
 497  21
             processorType = validChars.substring(0, typIdx);
 498  21
             validChars = validChars.substring(typIdx + 1);
 499  
         }
 500  
 
 501  21
         if ("regex".equalsIgnoreCase(processorType)) {
 502  21
             if (fieldValue == null || !fieldValue.toString().matches(validChars)) {
 503  3
                     val = new ValidationResultInfo(element, fieldValue);
 504  3
                 if(vcConstraint.getLabelKey()!=null){
 505  0
                         val.setError(getMessage(vcConstraint.getLabelKey()));
 506  
                 }else{
 507  3
                         val.setError(getMessage("validation.validCharsFailed"));
 508  
                 }
 509  
             }
 510  
         }
 511  
 
 512  21
         return val;
 513  
     }
 514  
 
 515  
     /**
 516  
      * Computes if all the filed required in the occurs clause are between the min and max
 517  
      *
 518  
      * @param valResults
 519  
      * @param constraint
 520  
      * @param field
 521  
      * @param type
 522  
      * @param state
 523  
      * @param objStructure
 524  
      * @param dataProvider
 525  
      * @return
 526  
      */
 527  
     protected ValidationResultInfo processOccursConstraint(String element, MustOccurConstraint constraint, FieldDefinition field, ObjectStructureDefinition objStructure, ConstraintDataProvider dataProvider) {
 528  
 
 529  0
         boolean result = false;
 530  0
         int trueCount = 0;
 531  
 
 532  0
         ValidationResultInfo val = null;
 533  
 
 534  0
         for (RequiredConstraint rc : constraint.getRequiredFields()) {
 535  0
             trueCount += (processRequireConstraint("", rc, field, objStructure, dataProvider) != null) ? 1 : 0;
 536  
         }
 537  
 
 538  0
         for (MustOccurConstraint oc : constraint.getOccurs()) {
 539  0
             trueCount += (processOccursConstraint("", oc, field, objStructure, dataProvider) != null) ? 1 : 0;
 540  
         }
 541  
 
 542  0
         result = (trueCount >= constraint.getMin() && trueCount <= constraint.getMax()) ? true : false;
 543  
 
 544  0
         if (!result) {
 545  
          // TODO: figure out what data should go here instead of null
 546  0
             val = new ValidationResultInfo(element, null);
 547  0
             val.setMessage(getMessage("validation.occurs"));
 548  0
             val.setLevel(constraint.getErrorLevel());
 549  
         }
 550  
 
 551  0
         return val;
 552  
     }
 553  
 
 554  
     // TODO: Implement lookup constraint
 555  
     protected void processLookupConstraint(List<ValidationResultInfo> valResults, LookupConstraint lookupConstraint, FieldDefinition field, Stack<String> elementStack, ConstraintDataProvider dataProvider, ObjectStructureDefinition objStructure, Object rootData, ObjectStructureDefinition rootObjStructure, Object value) {
 556  4
         if (lookupConstraint == null) {
 557  0
             return;
 558  
         }
 559  
 
 560  
         // Create search params based on the param mapping
 561  4
         List<SearchParam> params = new ArrayList<SearchParam>();
 562  
 
 563  4
         for (CommonLookupParam paramMapping : lookupConstraint.getParams()) {
 564  
                 //Skip params that are the search param id key
 565  8
             if(lookupConstraint.getSearchParamIdKey()!=null&&lookupConstraint.getSearchParamIdKey().equals(paramMapping.getKey())){
 566  0
                     continue;
 567  
             }
 568  
                 
 569  8
             SearchParam param = new SearchParam();
 570  
 
 571  8
             param.setKey(paramMapping.getKey());
 572  
 
 573  
             // If the value of the search param comes form another field then get it
 574  8
             if (paramMapping.getFieldPath() != null && !paramMapping.getFieldPath().isEmpty()) {
 575  4
                 FieldDefinition lookupField = null;
 576  4
                     boolean absolutePath = false;
 577  4
                 if(hasText(paramMapping.getFieldPath())){
 578  4
                         if(paramMapping.getFieldPath().startsWith("/")){
 579  0
                                 absolutePath = true;
 580  0
                                 lookupField = ValidatorUtils.getField(paramMapping.getFieldPath().substring(1), rootObjStructure);
 581  
                         }else{
 582  4
                                 lookupField = ValidatorUtils.getField(paramMapping.getFieldPath(), objStructure); 
 583  
                         }
 584  
                 }
 585  4
                 Object fieldValue = null;
 586  4
                 if(lookupField!=null){
 587  4
                         if(absolutePath){
 588  
                                 try {
 589  0
                                         if(lookupField.isDynamic()){
 590  
                                                 //Pull the value from the dynamic attribute map
 591  
                                                 //Until then, this will only work for root level properties
 592  0
                                                 Map<String,String> attributes = (Map<String,String>) PropertyUtils.getNestedProperty(rootData, "attributes");
 593  0
                                                 if(attributes!=null){
 594  0
                                                         fieldValue = attributes.get(paramMapping.getFieldPath().substring(1));
 595  
                                                 }
 596  0
                                         }else{
 597  0
                                                 fieldValue = PropertyUtils.getNestedProperty(rootData, paramMapping.getFieldPath().substring(1));
 598  
                                         }
 599  0
                                         } catch (IllegalAccessException e) {
 600  0
                                         } catch (InvocationTargetException e) {
 601  0
                                         } catch (NoSuchMethodException e) {
 602  0
                                         }
 603  
                         }else{
 604  4
                             fieldValue = dataProvider.getValue(lookupField.getName());
 605  
                         }
 606  
                 }else{
 607  0
                         fieldValue = dataProvider.getValue(paramMapping.getFieldPath());
 608  
                 }
 609  
                 
 610  4
                 if (fieldValue instanceof String) {
 611  4
                     param.setValue((String) fieldValue);
 612  0
                 } else if (fieldValue instanceof List<?>) {
 613  0
                     param.setValue((List<String>) fieldValue);
 614  
                 }
 615  4
             } else if (paramMapping.getDefaultValueString() != null) {
 616  4
                 param.setValue(paramMapping.getDefaultValueString());
 617  
             } else {
 618  0
                 param.setValue(paramMapping.getDefaultValueList());
 619  
             }
 620  8
             params.add(param);
 621  8
         }
 622  
 
 623  4
         if(lookupConstraint.getSearchParamIdKey()!=null){
 624  0
                 SearchParam param = new SearchParam();
 625  0
                 param.setKey(lookupConstraint.getSearchParamIdKey());
 626  0
             if (value instanceof String) {
 627  0
                 param.setValue((String) value);
 628  0
             } else if (value instanceof List<?>) {
 629  0
                 param.setValue((List<String>) value);
 630  
             }
 631  0
                 params.add(param);
 632  
         }
 633  
         
 634  4
         SearchRequest searchRequest = new SearchRequest();
 635  4
         searchRequest.setMaxResults(1);
 636  4
         searchRequest.setStartAt(0);
 637  4
         searchRequest.setNeededTotalResults(false);
 638  4
         searchRequest.setSearchKey(lookupConstraint.getSearchTypeId());
 639  4
         searchRequest.setParams(params);
 640  
 
 641  4
         SearchResult searchResult = null;
 642  
         try {
 643  4
             searchResult = searchDispatcher.dispatchSearch(searchRequest);
 644  2
         } catch (Exception e) {
 645  2
             LOG.info("Error calling Search", e);
 646  2
         }
 647  
         //If there are no search results then make a validation result
 648  4
         if (searchResult == null || searchResult.getRows() == null || searchResult.getRows().isEmpty()) {
 649  4
             ValidationResultInfo val = new ValidationResultInfo(getElementXpath(elementStack) + "/" + field.getName(), value);
 650  4
             val.setLevel(lookupConstraint.getErrorLevel());
 651  4
             val.setMessage(getMessage("validation.lookup"));
 652  4
             valResults.add(val);
 653  4
                 processCrossFieldWarning(valResults, lookupConstraint, lookupConstraint.getErrorLevel());
 654  
         }
 655  4
     }
 656  
 
 657  
     protected void processBaseConstraints(List<ValidationResultInfo> valResults, Constraint constraint, FieldDefinition field, Object value, Stack<String> elementStack) {
 658  78
             DataType dataType = field.getDataType();
 659  78
             String name = field.getName();
 660  
 
 661  78
             if (value == null || "".equals(value.toString().trim())) {
 662  29
             if (constraint.getMinOccurs() != null && constraint.getMinOccurs() > 0) {
 663  7
                 ValidationResultInfo val = new ValidationResultInfo(getElementXpath(elementStack) + "/" + name, value);
 664  7
                 if(constraint.getLabelKey()!=null){
 665  0
                         val.setError(getMessage(constraint.getLabelKey()));
 666  
                 } else {
 667  7
                         val.setMessage(getMessage("validation.required"));
 668  
                 }
 669  7
                 val.setLevel(constraint.getErrorLevel());
 670  7
                 valResults.add(val);
 671  
             }
 672  29
             return;
 673  
         }
 674  
 
 675  49
         String elementPath = getElementXpath(elementStack) + "/" + name;
 676  
 
 677  49
         if (DataType.STRING.equals(dataType)) {
 678  41
             validateString(value, constraint, elementPath, valResults);
 679  8
         } else if (DataType.INTEGER.equals(dataType)) {
 680  0
             validateInteger(value, constraint, elementPath, valResults);
 681  8
         } else if (DataType.LONG.equals(dataType)) {
 682  0
             validateLong(value, constraint, elementPath, valResults);
 683  8
         } else if (DataType.DOUBLE.equals(dataType)) {
 684  1
             validateDouble(value, constraint, elementPath, valResults);
 685  7
         } else if (DataType.FLOAT.equals(dataType)) {
 686  0
             validateFloat(value, constraint, elementPath, valResults);
 687  7
         } else if (DataType.BOOLEAN.equals(dataType)) {
 688  0
             validateBoolean(value, constraint, elementPath, valResults);
 689  7
         } else if (DataType.DATE.equals(dataType)) {
 690  7
             validateDate(value, constraint, elementPath, valResults, dateParser);
 691  
         }
 692  49
     }
 693  
     
 694  
     /**
 695  
      * This adds a warning on the related field when a processed case-constraint results in a warning
 696  
      * 
 697  
      * @param valResults
 698  
      * @param crossConstraint
 699  
      * @param field
 700  
      */
 701  
     protected void processCrossFieldWarning(List<ValidationResultInfo> valResults, CaseConstraint crossConstraint, Constraint constraint, Object value, ErrorLevel errorLevel){
 702  1
             if ((ErrorLevel.WARN == errorLevel || ErrorLevel.ERROR == errorLevel) && (value == null || "".equals(value.toString().trim()))) {
 703  1
             if (constraint.getMinOccurs() != null && constraint.getMinOccurs() > 0) {
 704  
 
 705  1
                     String crossFieldPath = crossConstraint.getFieldPath();
 706  1
                     String crossFieldMessageId = crossConstraint.getFieldPathMessageId() == null ? 
 707  
                                     "validation.required":crossConstraint.getFieldPathMessageId();            
 708  1
                     addCrossFieldWarning(valResults, crossFieldPath, getMessage(crossFieldMessageId), errorLevel);
 709  
             }
 710  
             }
 711  1
     }
 712  
 
 713  
     /**
 714  
      * This adds a warning on the related field when a processed case-constraint results in a warning
 715  
      * 
 716  
      * @param valResults
 717  
      * @param requiredConstraint
 718  
      * @param field
 719  
      */
 720  
     protected void processCrossFieldWarning(List<ValidationResultInfo> valResults, RequiredConstraint requiredConstraint, ErrorLevel errorLevel, String field){
 721  1
             if ((ErrorLevel.WARN == errorLevel || ErrorLevel.ERROR == errorLevel) && requiredConstraint != null){
 722  1
             String crossFieldPath = requiredConstraint.getFieldPath();
 723  1
             String crossFieldMessageId = requiredConstraint.getFieldPathMessageId() == null ? 
 724  
                             "validation.required":requiredConstraint.getFieldPathMessageId();
 725  1
             addCrossFieldWarning(valResults, crossFieldPath, getMessage(crossFieldMessageId), errorLevel);
 726  
             }
 727  1
     }
 728  
 
 729  
     /**
 730  
      * This adds a warning on the related field when a processed lookup-constraint results in a warning
 731  
      * 
 732  
      * @param valResults
 733  
      * @param lookupConstraint
 734  
      */
 735  
     protected void processCrossFieldWarning(List<ValidationResultInfo> valResults, LookupConstraint lookupConstraint, ErrorLevel errorLevel){
 736  4
             if ((ErrorLevel.WARN == errorLevel || ErrorLevel.ERROR == errorLevel) && lookupConstraint != null){
 737  4
                     for(CommonLookupParam param:lookupConstraint.getParams()){
 738  8
                             if(param.getFieldPath()!=null && !param.getFieldPath().isEmpty()){
 739  4
                             String crossFieldPath = param.getFieldPath();
 740  4
                             String crossFieldMessageId = param.getFieldPathMessageId() == null ? 
 741  
                                             "validation.lookup.cause":param.getFieldPathMessageId();
 742  4
                             addCrossFieldWarning(valResults, crossFieldPath, getMessage(crossFieldMessageId), errorLevel);
 743  8
                             }
 744  
                     }
 745  
             }
 746  4
     }
 747  
     
 748  
     protected void addCrossFieldWarning(List<ValidationResultInfo> valResults, String crossFieldPath, String message, ErrorLevel errorLevel){
 749  
             //Check to see if the exact same validation message already exists on referenced field
 750  6
             boolean warnAlreadyExists = false;
 751  6
             for (ValidationResultInfo vr:valResults){
 752  9
                     if (vr.getElement().equals(crossFieldPath) && vr.getMessage().equals(message)){
 753  0
                             warnAlreadyExists = true;
 754  
                     }
 755  
             }
 756  
             
 757  
             //Only add this warning, if it hasn't been already added
 758  6
             if (!warnAlreadyExists){
 759  6
                     ValidationResultInfo val = new ValidationResultInfo(crossFieldPath, null);
 760  6
                         val.setMessage(message);
 761  6
                 val.setLevel(errorLevel);
 762  6
                 valResults.add(val);
 763  
             }
 764  6
     }
 765  
     
 766  
     protected void validateBoolean(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 767  0
         if (!(value instanceof Boolean)) {
 768  
             try {
 769  0
                 Boolean.valueOf(value.toString());
 770  0
             } catch (Exception e) {
 771  0
                 ValidationResultInfo val = new ValidationResultInfo(element, value);
 772  0
                 val.setError(getMessage("validation.mustBeBoolean"));
 773  0
                 results.add(val);
 774  0
             }
 775  
         }
 776  0
     }
 777  
 
 778  
     protected void validateDouble(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 779  1
         Double v = null;
 780  
 
 781  1
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 782  
 
 783  1
         if (value instanceof Number) {
 784  1
             v = ((Number) value).doubleValue();
 785  
         } else {
 786  
             try {
 787  0
                 v = Double.valueOf(value.toString());
 788  0
             } catch (Exception e) {
 789  0
                 val.setError(getMessage("validation.mustBeDouble"));
 790  0
             }
 791  
         }
 792  
 
 793  1
         if (val.isOk()) {
 794  1
             Double maxValue = ValidatorUtils.getDouble(constraint.getInclusiveMax());
 795  1
             Double minValue = ValidatorUtils.getDouble(constraint.getExclusiveMin());
 796  
 
 797  1
             if (maxValue != null && minValue != null) {
 798  
                 // validate range
 799  1
                 if (v > maxValue || v < minValue) {
 800  1
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 801  
                 }
 802  0
             } else if (maxValue != null) {
 803  0
                 if (v > maxValue) {
 804  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 805  
                 }
 806  0
             } else if (minValue != null) {
 807  0
                 if (v < minValue) {
 808  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 809  
                 }
 810  
             }
 811  
         }
 812  
 
 813  1
         if (!val.isOk()) {
 814  1
             results.add(val);
 815  
         }
 816  1
     }
 817  
 
 818  
     protected void validateFloat(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 819  0
         Float v = null;
 820  
 
 821  0
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 822  0
         if (value instanceof Number) {
 823  0
             v = ((Number) value).floatValue();
 824  
         } else {
 825  
             try {
 826  0
                 v = Float.valueOf(value.toString());
 827  0
             } catch (Exception e) {
 828  0
                 val.setError(getMessage("validation.mustBeFloat"));
 829  0
             }
 830  
         }
 831  
 
 832  0
         if (val.isOk()) {
 833  0
             Float maxValue = ValidatorUtils.getFloat(constraint.getInclusiveMax());
 834  0
             Float minValue = ValidatorUtils.getFloat(constraint.getExclusiveMin());
 835  
 
 836  0
             if (maxValue != null && minValue != null) {
 837  
                 // validate range
 838  0
                 if (v > maxValue || v < minValue) {
 839  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 840  
                 }
 841  0
             } else if (maxValue != null) {
 842  0
                 if (v > maxValue) {
 843  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 844  
                 }
 845  0
             } else if (minValue != null) {
 846  0
                 if (v < minValue) {
 847  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 848  
                 }
 849  
             }
 850  
         }
 851  
 
 852  0
         if (!val.isOk()) {
 853  0
             results.add(val);
 854  
         }
 855  0
     }
 856  
 
 857  
     protected void validateLong(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 858  0
         Long v = null;
 859  
 
 860  0
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 861  0
         if (value instanceof Number) {
 862  0
             v = ((Number) value).longValue();
 863  
         } else {
 864  
             try {
 865  0
                 v = Long.valueOf(value.toString());
 866  0
             } catch (Exception e) {
 867  0
                 val.setError(getMessage("validation.mustBeLong"));
 868  0
             }
 869  
         }
 870  
 
 871  0
         if (val.isOk()) {
 872  0
             Long maxValue = ValidatorUtils.getLong(constraint.getInclusiveMax());
 873  0
             Long minValue = ValidatorUtils.getLong(constraint.getExclusiveMin());
 874  
 
 875  0
             if (maxValue != null && minValue != null) {
 876  
                 // validate range
 877  0
                 if (v > maxValue || v < minValue) {
 878  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 879  
                 }
 880  0
             } else if (maxValue != null) {
 881  0
                 if (v > maxValue) {
 882  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 883  
                 }
 884  0
             } else if (minValue != null) {
 885  0
                 if (v < minValue) {
 886  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 887  
                 }
 888  
             }
 889  
         }
 890  
 
 891  0
         if (!val.isOk()) {
 892  0
             results.add(val);
 893  
         }
 894  
 
 895  0
     }
 896  
 
 897  
     protected void validateInteger(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 898  0
         Integer v = null;
 899  
 
 900  0
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 901  
 
 902  0
         if (value instanceof Number) {
 903  0
             v = ((Number) value).intValue();
 904  
         } else {
 905  
             try {
 906  0
                 v = Integer.valueOf(value.toString());
 907  0
             } catch (Exception e) {
 908  0
                 val.setError(getMessage("validation.mustBeInteger"));
 909  0
             }
 910  
         }
 911  
 
 912  0
         if (val.isOk()) {
 913  0
             Integer maxValue = ValidatorUtils.getInteger(constraint.getInclusiveMax());
 914  0
             Integer minValue = ValidatorUtils.getInteger(constraint.getExclusiveMin());
 915  
 
 916  0
             if (maxValue != null && minValue != null) {
 917  
                 // validate range
 918  0
                 if (v > maxValue || v < minValue) {
 919  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 920  
                 }
 921  0
             } else if (maxValue != null) {
 922  0
                 if (v > maxValue) {
 923  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 924  
                 }
 925  0
             } else if (minValue != null) {
 926  0
                 if (v < minValue) {
 927  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 928  
                 }
 929  
             }
 930  
         }
 931  
 
 932  0
         if (!val.isOk()) {
 933  0
             results.add(val);
 934  
         }
 935  0
     }
 936  
 
 937  
     protected void validateDate(Object value, Constraint constraint, String element, List<ValidationResultInfo> results, DateParser dateParser) {
 938  7
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 939  
 
 940  7
         Date v = null;
 941  
 
 942  7
         if (value instanceof Date) {
 943  7
             v = (Date) value;
 944  
         } else {
 945  
             try {
 946  0
                 v = dateParser.parseDate(value.toString());
 947  0
             } catch (Exception e) {
 948  0
                 val.setError(getMessage("validation.mustBeDate"));
 949  0
             }
 950  
         }
 951  
 
 952  7
         if (val.isOk()) {
 953  7
             Date maxValue = ValidatorUtils.getDate(constraint.getInclusiveMax(), dateParser);
 954  7
             Date minValue = ValidatorUtils.getDate(constraint.getExclusiveMin(), dateParser);
 955  
 
 956  7
             if (maxValue != null && minValue != null) {
 957  
                 // validate range
 958  0
                 if (v.getTime() > maxValue.getTime() || v.getTime() < minValue.getTime()) {
 959  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 960  
                 }
 961  7
             } else if (maxValue != null) {
 962  0
                 if (v.getTime() > maxValue.getTime()) {
 963  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 964  
                 }
 965  7
             } else if (minValue != null) {
 966  7
                 if (v.getTime() < minValue.getTime()) {
 967  1
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 968  
                 }
 969  
             }
 970  
         }
 971  
 
 972  7
         if (!val.isOk()) {
 973  1
             results.add(val);
 974  
         }
 975  7
     }
 976  
 
 977  
     protected void validateString(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 978  
 
 979  41
         if (value == null) {
 980  0
             value = "";
 981  
         }
 982  41
         String s = value.toString().trim();
 983  
 
 984  41
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 985  
 
 986  41
         Integer maxLength = tryParse(constraint.getMaxLength());
 987  41
         if (maxLength != null && constraint.getMinLength() != null && constraint.getMinLength() > 0) {
 988  39
             if (s.length() > maxLength || s.length() < constraint.getMinLength()) {
 989  1
                 val.setError(MessageUtils.interpolate(getMessage("validation.lengthOutOfRange"), toMap(constraint)));
 990  
             }
 991  2
         } else if (maxLength != null) {
 992  1
             if (s.length() > Integer.parseInt(constraint.getMaxLength())) {
 993  1
                 val.setError(MessageUtils.interpolate(getMessage("validation.maxLengthFailed"), toMap(constraint)));
 994  
             }
 995  1
         } else if (constraint.getMinLength() != null && constraint.getMinLength() > 0) {
 996  1
             if (s.length() < constraint.getMinLength()) {
 997  1
                 val.setError(MessageUtils.interpolate(getMessage("validation.minLengthFailed"), toMap(constraint)));
 998  
             }
 999  
         }
 1000  
 
 1001  41
         if (!val.isOk()) {
 1002  3
             results.add(val);
 1003  
         }
 1004  41
     }
 1005  
 
 1006  
     protected String getMessage(String messageId) {
 1007  26
         if (null == messageService) {
 1008  26
             return messageId;
 1009  
         }
 1010  
 
 1011  0
         Message msg = messageService.getMessage(messageLocaleKey, messageGroupKey, messageId);
 1012  
 
 1013  0
         return msg.getValue();
 1014  
     }
 1015  
 
 1016  
     protected String getElementXpath(Stack<String> elementStack) {
 1017  114
         StringBuilder xPath = new StringBuilder();
 1018  114
         Iterator<String> itr = elementStack.iterator();
 1019  247
         while (itr.hasNext()) {
 1020  133
             xPath.append(itr.next());
 1021  133
             if(itr.hasNext()){
 1022  64
                     xPath.append("/");
 1023  
             }
 1024  
         }
 1025  
 
 1026  114
         return xPath.toString();
 1027  
     }
 1028  
 
 1029  
     /*
 1030  
      * Homemade has text so we dont need outside libs.
 1031  
      */
 1032  
     protected boolean hasText(String string) {
 1033  
 
 1034  76
         if (string == null || string.length() < 1) {
 1035  20
             return false;
 1036  
         }
 1037  56
         int stringLength = string.length();
 1038  
 
 1039  56
         for (int i = 0; i < stringLength; i++) {
 1040  56
             char currentChar = string.charAt(i);
 1041  56
             if (' ' != currentChar || '\t' != currentChar || '\n' != currentChar) {
 1042  56
                 return true;
 1043  
             }
 1044  
         }
 1045  
 
 1046  0
         return false;
 1047  
     }
 1048  
 
 1049  
     protected Map<String, Object> toMap(Constraint c) {
 1050  5
         Map<String, Object> result = new HashMap<String, Object>();
 1051  5
         result.put("minOccurs", c.getMinOccurs());
 1052  5
         result.put("maxOccurs", c.getMaxOccurs());
 1053  5
         result.put("minLength", c.getMinLength());
 1054  5
         result.put("maxLength", c.getMaxLength());
 1055  5
         result.put("minValue", c.getExclusiveMin());
 1056  5
         result.put("maxValue", c.getInclusiveMax());
 1057  
         // result.put("dataType", c.getDataType());
 1058  
 
 1059  5
         return result;
 1060  
     }
 1061  
 
 1062  
     public SearchDispatcher getSearchDispatcher() {
 1063  0
         return searchDispatcher;
 1064  
     }
 1065  
 
 1066  
     public void setSearchDispatcher(SearchDispatcher searchDispatcher) {
 1067  1
         this.searchDispatcher = searchDispatcher;
 1068  1
     }
 1069  
 
 1070  
         @Override
 1071  
         public List<ValidationResultInfo> validateObject(FieldDefinition field,
 1072  
                         Object o, ObjectStructureDefinition objStructure,Stack<String> elementStack) {
 1073  0
                 return null;
 1074  
         }
 1075  
 }