Coverage Report - org.kuali.student.common.validator.DefaultValidatorImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultValidatorImpl
56%
240/425
40%
138/344
6.306
 
 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.util.ArrayList;
 12  
 import java.util.Collection;
 13  
 import java.util.Date;
 14  
 import java.util.HashMap;
 15  
 import java.util.Iterator;
 16  
 import java.util.List;
 17  
 import java.util.Map;
 18  
 import java.util.Stack;
 19  
 
 20  
 import org.apache.log4j.Logger;
 21  
 import org.kuali.student.common.util.MessageUtils;
 22  
 import org.kuali.student.core.dictionary.dto.CaseConstraint;
 23  
 import org.kuali.student.core.dictionary.dto.CommonLookupParam;
 24  
 import org.kuali.student.core.dictionary.dto.Constraint;
 25  
 import org.kuali.student.core.dictionary.dto.DataType;
 26  
 import org.kuali.student.core.dictionary.dto.FieldDefinition;
 27  
 import org.kuali.student.core.dictionary.dto.LookupConstraint;
 28  
 import org.kuali.student.core.dictionary.dto.MustOccurConstraint;
 29  
 import org.kuali.student.core.dictionary.dto.ObjectStructureDefinition;
 30  
 import org.kuali.student.core.dictionary.dto.RequiredConstraint;
 31  
 import org.kuali.student.core.dictionary.dto.ValidCharsConstraint;
 32  
 import org.kuali.student.core.dictionary.dto.WhenConstraint;
 33  
 import org.kuali.student.core.messages.dto.Message;
 34  
 import org.kuali.student.core.messages.service.MessageService;
 35  
 import org.kuali.student.core.search.dto.SearchParam;
 36  
 import org.kuali.student.core.search.dto.SearchRequest;
 37  
 import org.kuali.student.core.search.dto.SearchResult;
 38  
 import org.kuali.student.core.search.service.SearchDispatcher;
 39  
 import org.kuali.student.core.validation.dto.ValidationResultInfo;
 40  
 
 41  8
 public class DefaultValidatorImpl extends BaseAbstractValidator {
 42  1
     final static Logger LOG = Logger.getLogger(DefaultValidatorImpl.class);
 43  
 
 44  8
     private MessageService messageService = null;
 45  
 
 46  
     private SearchDispatcher searchDispatcher;
 47  
 
 48  8
     private String messageLocaleKey = "en";
 49  
 
 50  8
     private String messageGroupKey = "validation";
 51  
 
 52  8
     private DateParser dateParser = new ServerDateParser();
 53  
 
 54  8
     private boolean serverSide = true;
 55  
 
 56  
     public MessageService getMessageService() {
 57  0
         return messageService;
 58  
     }
 59  
 
 60  
     public void setMessageService(MessageService messageService) {
 61  8
         this.messageService = messageService;
 62  8
     }
 63  
 
 64  
     public String getMessageLocaleKey() {
 65  0
         return messageLocaleKey;
 66  
     }
 67  
 
 68  
     public void setMessageLocaleKey(String messageLocaleKey) {
 69  0
         this.messageLocaleKey = messageLocaleKey;
 70  0
     }
 71  
 
 72  
     public String getMessageGroupKey() {
 73  0
         return messageGroupKey;
 74  
     }
 75  
 
 76  
     public void setMessageGroupKey(String messageGroupKey) {
 77  0
         this.messageGroupKey = messageGroupKey;
 78  0
     }
 79  
 
 80  
     public void setDateParser(DateParser dateParser) {
 81  8
         this.dateParser = dateParser;
 82  8
     }
 83  
 
 84  
         /**
 85  
      * @return the serverSide
 86  
      */
 87  
     public boolean isServerSide() {
 88  0
         return serverSide;
 89  
     }
 90  
 
 91  
     /**
 92  
      * @param serverSide
 93  
      *            the serverSide to set
 94  
      */
 95  
     public void setServerSide(boolean serverSide) {
 96  0
         this.serverSide = serverSide;
 97  0
     }
 98  
 
 99  
     /**
 100  
      * @return the dateParser
 101  
      */
 102  
     public DateParser getDateParser() {
 103  0
         return dateParser;
 104  
     }
 105  
 
 106  
     /**
 107  
      * Validate Object and all its nested child objects for given type and state
 108  
      *
 109  
      * @param data
 110  
      * @param objStructure
 111  
      * @return
 112  
      */
 113  
     public List<ValidationResultInfo> validateObject(Object data, ObjectStructureDefinition objStructure) {
 114  
 
 115  10
         Stack<String> elementStack = new Stack<String>();
 116  10
         return validateObject(data, objStructure, elementStack, true);
 117  
     }
 118  
 
 119  
     private List<ValidationResultInfo> validateObject(Object data, ObjectStructureDefinition objStructure, Stack<String> elementStack, boolean isRoot) {
 120  
 
 121  13
        List<ValidationResultInfo> results = new ArrayList<ValidationResultInfo>();
 122  
 
 123  13
         ConstraintDataProvider dataProvider = new BeanConstraintDataProvider();
 124  13
         dataProvider.initialize(data);
 125  
 
 126  
         // Push object structure to the top of the stack
 127  13
         StringBuilder objXPathElement = new StringBuilder(dataProvider.getPath());
 128  
 
 129  13
         if(!isRoot && !objXPathElement.toString().isEmpty()){
 130  0
                 elementStack.push(objXPathElement.toString());
 131  
         }
 132  
 
 133  
         /*
 134  
          * Do nothing if the object to be validated is not type/state or if the objectstructure with constraints is not
 135  
          * provided
 136  
          */
 137  13
         if (null == objStructure) {
 138  0
             return results;
 139  
         }
 140  
 
 141  13
         for (FieldDefinition f : objStructure.getAttributes()) {
 142  58
             List<ValidationResultInfo> l = validateField(f, objStructure, dataProvider, elementStack);
 143  
 
 144  58
             results.addAll(l);
 145  
 
 146  
             // Use Custom Validators
 147  58
             if (f.getCustomValidatorClass() != null || f.isServerSide() && serverSide) {
 148  0
                     Validator customValidator = validatorFactory.getValidator(f.getCustomValidatorClass());
 149  0
                     if(customValidator==null){
 150  0
                             throw new RuntimeException("Custom Validator "+f.getCustomValidatorClass()+" was not configured in this context");
 151  
                     }
 152  0
                     l = customValidator.validateObject(f,data, objStructure,elementStack);
 153  0
                     results.addAll(l);
 154  
             }
 155  58
         }
 156  13
         if(!isRoot && !objXPathElement.toString().isEmpty()){
 157  0
                 elementStack.pop();
 158  
         }
 159  
 
 160  
         /* All Field validations are returned right now */
 161  
         // List<ValidationResultInfo> resultsBuffer = new
 162  
         // ArrayList<ValidationResultInfo>();
 163  
         // for (ValidationResultContainer vc : results) {
 164  
         // if (skipFields.contains(vc.getElement()) == false) {
 165  
         // resultsBuffer.add(vc);
 166  
         // }
 167  
         // }
 168  
         // results = resultsBuffer;
 169  13
         return results;
 170  
     }
 171  
 
 172  
     public List<ValidationResultInfo> validateField(FieldDefinition field, ObjectStructureDefinition objStruct, ConstraintDataProvider dataProvider, Stack<String> elementStack) {
 173  
 
 174  58
         Object value = dataProvider.getValue(field.getName());
 175  58
         List<ValidationResultInfo> results = new ArrayList<ValidationResultInfo>();
 176  
 
 177  
         // Handle null values in field
 178  58
         if (value == null || "".equals(value.toString().trim())) {
 179  25
             processConstraint(results, field, objStruct, value, dataProvider, elementStack);
 180  25
             return results;
 181  
         }
 182  
 
 183  
         /*
 184  
          * For complex object structures only the following constraints apply 1. TypeStateCase 2. MinOccurs 3. MaxOccurs
 185  
          */
 186  33
         if (DataType.COMPLEX.equals(field.getDataType())) {
 187  3
             ObjectStructureDefinition nestedObjStruct = null;
 188  
 
 189  3
             if (null != field.getDataObjectStructure()) {
 190  3
                 nestedObjStruct = field.getDataObjectStructure();
 191  
             }
 192  
 
 193  3
             elementStack.push(field.getName());
 194  
 
 195  3
             if (value instanceof Collection) {
 196  
 
 197  3
                 String xPathForCollection = getElementXpath(elementStack) + "/*";
 198  
 
 199  3
                 int i=0;
 200  3
                 for (Object o : (Collection<?>) value) {
 201  3
                         elementStack.push(Integer.toString(i));
 202  3
                     processNestedObjectStructure(results, o, nestedObjStruct, field, elementStack);
 203  3
                     elementStack.pop();
 204  3
                     i++;
 205  
                 }
 206  3
                 if (field.getMinOccurs() != null && field.getMinOccurs() > ((Collection<?>) value).size()) {
 207  0
                     ValidationResultInfo valRes = new ValidationResultInfo(xPathForCollection, value);
 208  0
                     valRes.setError(MessageUtils.interpolate(getMessage("validation.minOccurs"), toMap(field)));
 209  0
                     results.add(valRes);
 210  
                 }
 211  
 
 212  3
                 Integer maxOccurs = tryParse(field.getMaxOccurs());
 213  3
                 if (maxOccurs != null && maxOccurs < ((Collection<?>) value).size()) {
 214  0
                     ValidationResultInfo valRes = new ValidationResultInfo(xPathForCollection, value);
 215  0
                     valRes.setError(MessageUtils.interpolate(getMessage("validation.maxOccurs"), toMap(field)));
 216  0
                     results.add(valRes);
 217  
                 }
 218  3
             } else {
 219  0
                 if (null != value) {
 220  0
                     processNestedObjectStructure(results, value, nestedObjStruct, field, elementStack);
 221  
                 } else {
 222  0
                     if (field.getMinOccurs() != null && field.getMinOccurs() > 0) {
 223  0
                         ValidationResultInfo val = new ValidationResultInfo(getElementXpath(elementStack), value);
 224  0
                         val.setError(getMessage("validation.required"));
 225  0
                         results.add(val);
 226  
                     }
 227  
                 }
 228  
             }
 229  
 
 230  3
             elementStack.pop();
 231  
 
 232  3
         } else { // If non complex data type
 233  
 
 234  30
             if (value instanceof Collection) {
 235  
 
 236  0
                 if(((Collection<?>)value).isEmpty()){
 237  0
                     processConstraint(results, field, objStruct, "", dataProvider, elementStack);
 238  
                 }
 239  
 
 240  0
                     int i = 0;
 241  0
                 for (Object o : (Collection<?>) value) {
 242  0
                         elementStack.push(Integer.toBinaryString(i));
 243  0
                     processConstraint(results, field, objStruct, o, dataProvider, elementStack);
 244  0
                     elementStack.pop();
 245  0
                     i++;
 246  
                 }
 247  
 
 248  0
                 String xPath = getElementXpath(elementStack) + "/" + field.getName() + "/*";
 249  0
                 if (field.getMinOccurs() != null && field.getMinOccurs() > ((Collection<?>) value).size()) {
 250  0
                     ValidationResultInfo valRes = new ValidationResultInfo(xPath, value);
 251  0
                     valRes.setError(MessageUtils.interpolate(getMessage("validation.minOccurs"), toMap(field)));
 252  0
                     results.add(valRes);
 253  
                 }
 254  
 
 255  0
                 Integer maxOccurs = tryParse(field.getMaxOccurs());
 256  0
                 if (maxOccurs != null && maxOccurs < ((Collection<?>) value).size()) {
 257  0
                     ValidationResultInfo valRes = new ValidationResultInfo(xPath, value);
 258  0
                     valRes.setError(MessageUtils.interpolate(getMessage("validation.maxOccurs"), toMap(field)));
 259  0
                     results.add(valRes);
 260  
                 }
 261  0
             } else {
 262  30
                 processConstraint(results, field, objStruct, value, dataProvider, elementStack);
 263  
             }
 264  
 
 265  
         }
 266  33
         return results;
 267  
     }
 268  
 
 269  
     protected Integer tryParse(String s) {
 270  27
         Integer result = null;
 271  27
         if (s != null) {
 272  
             try {
 273  23
                 result = Integer.valueOf(s);
 274  0
             } catch (NumberFormatException e) {
 275  
                 // do nothing
 276  23
             }
 277  
         }
 278  27
         return result;
 279  
     }
 280  
 
 281  
     protected void processNestedObjectStructure(List<ValidationResultInfo> results, Object value, ObjectStructureDefinition nestedObjStruct, FieldDefinition field, Stack<String> elementStack) {
 282  
 
 283  3
         results.addAll(validateObject(value, nestedObjStruct, elementStack, false));
 284  
 
 285  3
     }
 286  
 
 287  
     protected void processConstraint(List<ValidationResultInfo> valResults, FieldDefinition field, ObjectStructureDefinition objStructure, Object value, ConstraintDataProvider dataProvider, Stack<String> elementStack) {
 288  
 
 289  
         // Process Case Constraint
 290  
         // Case Constraint are only evaluated on the field. Nested case constraints are currently ignored
 291  55
         Constraint caseConstraint = processCaseConstraint(valResults, field, objStructure, value, dataProvider, elementStack);
 292  
 
 293  55
         Constraint constraint = (null != caseConstraint) ? caseConstraint : field;
 294  
 
 295  55
         processBaseConstraints(valResults, constraint, field.getDataType(), field.getName(), value, elementStack);
 296  
 
 297  
         // Stop other checks if value is null
 298  55
         if (value == null || "".equals(value.toString().trim())) {
 299  25
             return;
 300  
         }
 301  
 
 302  30
         String elementPath = getElementXpath(elementStack) + "/" + field.getName();
 303  
 
 304  
         // Process Valid Chars
 305  30
         if (null != constraint.getValidChars()) {
 306  15
             ValidationResultInfo val = processValidCharConstraint(elementPath, constraint.getValidChars(), dataProvider, value);
 307  15
             if (null != val) {
 308  3
                 valResults.add(val);
 309  
             }
 310  
         }
 311  
 
 312  
         // Process Require Constraints (only if this field has value)
 313  30
         if (value != null && !"".equals(value.toString().trim())) {
 314  30
             if (null != constraint.getRequireConstraint() && constraint.getRequireConstraint().size() > 0) {
 315  3
                 for (RequiredConstraint rc : constraint.getRequireConstraint()) {
 316  3
                     ValidationResultInfo val = processRequireConstraint(elementPath, rc, field, objStructure, dataProvider);
 317  3
                     if (null != val) {
 318  1
                         valResults.add(val);
 319  
                     }
 320  3
                 }
 321  
             }
 322  
         }
 323  
 
 324  
         // Process Occurs Constraint
 325  30
         if (null != constraint.getOccursConstraint() && constraint.getOccursConstraint().size() > 0) {
 326  0
             for (MustOccurConstraint oc : constraint.getOccursConstraint()) {
 327  0
                 ValidationResultInfo val = processOccursConstraint(elementPath, oc, field, objStructure, dataProvider);
 328  0
                 if (null != val) {
 329  0
                     valResults.add(val);
 330  
                 }
 331  0
             }
 332  
         }
 333  
 
 334  
         // Process lookup Constraint
 335  30
         if (null != constraint.getLookupDefinition()) {
 336  2
             processLookupConstraint(valResults, constraint.getLookupDefinition(), field, elementStack, dataProvider);
 337  
         }
 338  30
     }
 339  
 
 340  
     protected ValidationResultInfo processRequireConstraint(String element, RequiredConstraint constraint, FieldDefinition field, ObjectStructureDefinition objStructure, ConstraintDataProvider dataProvider) {
 341  
 
 342  3
         ValidationResultInfo val = null;
 343  
 
 344  3
         String fieldName = constraint.getFieldPath();// TODO parse fieldname from here
 345  3
         Object fieldValue = dataProvider.getValue(fieldName);
 346  
 
 347  3
         boolean result = true;
 348  
 
 349  3
         if (fieldValue instanceof java.lang.String) {
 350  3
             result = hasText((String) fieldValue);
 351  0
         } else if (fieldValue instanceof Collection) {
 352  0
             result = (((Collection<?>) fieldValue).size() > 0);
 353  
         } else {
 354  0
             result = (null != fieldValue) ? true : false;
 355  
         }
 356  
 
 357  3
         if (!result) {
 358  1
             Map<String, Object> rMap = new HashMap<String, Object>();
 359  1
             rMap.put("field1", field.getName());
 360  1
             rMap.put("field2", fieldName);
 361  1
             val = new ValidationResultInfo(element, fieldValue);
 362  1
             val.setError(MessageUtils.interpolate(getMessage("validation.requiresField"), rMap));
 363  
         }
 364  
 
 365  3
         return val;
 366  
     }
 367  
 
 368  
     /**
 369  
      * Process caseConstraint tag and sets any of the base constraint items if any of the when condition matches
 370  
      *
 371  
      * @param constraint
 372  
      * @param caseConstraint
 373  
      * @param field
 374  
      */
 375  
     protected Constraint processCaseConstraint(List<ValidationResultInfo> valResults, FieldDefinition field, ObjectStructureDefinition objStructure, Object value, ConstraintDataProvider dataProvider, Stack<String> elementStack) {
 376  
 
 377  55
         CaseConstraint constraint = field.getCaseConstraint();
 378  
 
 379  55
         if (null == constraint) {
 380  42
             return null;
 381  
         }
 382  
 
 383  13
         String operator = (hasText(constraint.getOperator())) ? constraint.getOperator() : "EQUALS";
 384  13
         FieldDefinition caseField = (hasText(constraint.getFieldPath())) ? ValidatorUtils.getField(constraint.getFieldPath(), objStructure) : null;
 385  
 
 386  
         // TODO: What happens when the field is not in the dataProvider?
 387  13
         Object fieldValue = (null != caseField) ? dataProvider.getValue(caseField.getName()) : value;
 388  13
         DataType fieldDataType = (null != caseField ? caseField.getDataType():null);
 389  
 
 390  
         // If fieldValue is null then skip Case check
 391  13
         if(null == fieldValue) {
 392  9
             return null;
 393  
         }
 394  
 
 395  
         // Extract value for field Key
 396  4
         for (WhenConstraint wc : constraint.getWhenConstraint()) {
 397  
 
 398  7
             List<Object> whenValueList = wc.getValues();
 399  
 
 400  7
             for (Object whenValue : whenValueList) {
 401  9
                 if (ValidatorUtils.compareValues(fieldValue, whenValue, fieldDataType, operator, constraint.isCaseSensitive(), dateParser) && null != wc.getConstraint()) {
 402  0
                     return wc.getConstraint();
 403  
                 }
 404  
             }
 405  7
         }
 406  
 
 407  4
         return null;
 408  
     }
 409  
 
 410  
     protected ValidationResultInfo processValidCharConstraint(String element, ValidCharsConstraint vcConstraint, ConstraintDataProvider dataProvider, Object value) {
 411  
 
 412  15
         ValidationResultInfo val = null;
 413  
 
 414  15
         StringBuilder fieldValue = new StringBuilder();
 415  15
         String validChars = vcConstraint.getValue();
 416  
 
 417  15
         fieldValue.append(ValidatorUtils.getString(value));
 418  
 
 419  15
         int typIdx = validChars.indexOf(":");
 420  15
         String processorType = "regex";
 421  15
         if (-1 == typIdx) {
 422  0
             validChars = "[" + validChars + "]*";
 423  
         } else {
 424  15
             processorType = validChars.substring(0, typIdx);
 425  15
             validChars = validChars.substring(typIdx + 1);
 426  
         }
 427  
 
 428  15
         if ("regex".equalsIgnoreCase(processorType)) {
 429  15
             if (fieldValue == null || !fieldValue.toString().matches(validChars)) {
 430  3
                     val = new ValidationResultInfo(element, fieldValue);
 431  3
                 if(vcConstraint.getLabelKey()!=null){
 432  0
                         val.setError(getMessage(vcConstraint.getLabelKey()));
 433  
                 }else{
 434  3
                         val.setError(getMessage("validation.validCharsFailed"));
 435  
                 }
 436  
             }
 437  
         }
 438  
 
 439  15
         return val;
 440  
     }
 441  
 
 442  
     /**
 443  
      * Computes if all the filed required in the occurs clause are between the min and max
 444  
      *
 445  
      * @param valResults
 446  
      * @param constraint
 447  
      * @param field
 448  
      * @param type
 449  
      * @param state
 450  
      * @param objStructure
 451  
      * @param dataProvider
 452  
      * @return
 453  
      */
 454  
     protected ValidationResultInfo processOccursConstraint(String element, MustOccurConstraint constraint, FieldDefinition field, ObjectStructureDefinition objStructure, ConstraintDataProvider dataProvider) {
 455  
 
 456  0
         boolean result = false;
 457  0
         int trueCount = 0;
 458  
 
 459  0
         ValidationResultInfo val = null;
 460  
 
 461  0
         for (RequiredConstraint rc : constraint.getRequiredFields()) {
 462  0
             trueCount += (processRequireConstraint("", rc, field, objStructure, dataProvider) != null) ? 1 : 0;
 463  
         }
 464  
 
 465  0
         for (MustOccurConstraint oc : constraint.getOccurs()) {
 466  0
             trueCount += (processOccursConstraint("", oc, field, objStructure, dataProvider) != null) ? 1 : 0;
 467  
         }
 468  
 
 469  0
         result = (trueCount >= constraint.getMin() && trueCount <= constraint.getMax()) ? true : false;
 470  
 
 471  0
         if (!result) {
 472  
          // TODO: figure out what data should go here instead of null
 473  0
             val = new ValidationResultInfo(element, null);
 474  0
             val.setError(getMessage("validation.occurs"));
 475  
         }
 476  
 
 477  0
         return val;
 478  
     }
 479  
 
 480  
     // TODO: Implement lookup constraint
 481  
     protected void processLookupConstraint(List<ValidationResultInfo> valResults, LookupConstraint lookupConstraint, FieldDefinition field, Stack<String> elementStack, ConstraintDataProvider dataProvider) {
 482  2
         if (lookupConstraint == null) {
 483  0
             return;
 484  
         }
 485  
 
 486  
         // Create search params based on the param mapping
 487  2
         List<SearchParam> params = new ArrayList<SearchParam>();
 488  2
         Object fieldValue = null;
 489  2
         for (CommonLookupParam paramMapping : lookupConstraint.getParams()) {
 490  4
             SearchParam param = new SearchParam();
 491  
 
 492  4
             param.setKey(paramMapping.getKey());
 493  
 
 494  
             // If the value of the search param comes form another field then get it
 495  4
             if (paramMapping.getFieldPath() != null && !paramMapping.getFieldPath().isEmpty()) {
 496  2
                 fieldValue = dataProvider.getValue(paramMapping.getFieldPath());
 497  2
                 if (fieldValue instanceof String) {
 498  2
                     param.setValue((String) fieldValue);
 499  0
                 } else if (fieldValue instanceof List<?>) {
 500  0
                     param.setValue((List<String>) fieldValue);
 501  
                 }
 502  2
             } else if (paramMapping.getDefaultValueString() != null) {
 503  2
                 param.setValue(paramMapping.getDefaultValueString());
 504  
             } else {
 505  0
                 param.setValue(paramMapping.getDefaultValueList());
 506  
             }
 507  4
             params.add(param);
 508  4
         }
 509  
 
 510  2
         SearchRequest searchRequest = new SearchRequest();
 511  2
         searchRequest.setMaxResults(1);
 512  2
         searchRequest.setStartAt(0);
 513  2
         searchRequest.setNeededTotalResults(false);
 514  2
         searchRequest.setSearchKey(lookupConstraint.getSearchTypeId());
 515  2
         searchRequest.setParams(params);
 516  
 
 517  2
         SearchResult searchResult = null;
 518  
         try {
 519  2
             searchResult = searchDispatcher.dispatchSearch(searchRequest);
 520  0
         } catch (Exception e) {
 521  0
             LOG.info("Error calling Search", e);
 522  2
         }
 523  2
         if (searchResult == null || searchResult.getRows() == null || searchResult.getRows().isEmpty()) {
 524  2
             ValidationResultInfo val = new ValidationResultInfo(getElementXpath(elementStack) + "/" + field.getName(), fieldValue);
 525  2
             val.setError(getMessage("validation.lookup"));
 526  2
             valResults.add(val);
 527  
         }
 528  2
     }
 529  
 
 530  
     protected void processBaseConstraints(List<ValidationResultInfo> valResults, Constraint constraint, DataType dataType, String name, Object value, Stack<String> elementStack) {
 531  
 
 532  55
         if (value == null || "".equals(value.toString().trim())) {
 533  25
             if (constraint.getMinOccurs() != null && constraint.getMinOccurs() > 0) {
 534  9
                 ValidationResultInfo val = new ValidationResultInfo(getElementXpath(elementStack) + "/" + name, value);
 535  9
                 val.setError(getMessage("validation.required"));
 536  9
                 valResults.add(val);
 537  
             }
 538  25
             return;
 539  
         }
 540  
 
 541  30
         String elementPath = getElementXpath(elementStack) + "/" + name;
 542  
 
 543  30
         if (DataType.STRING.equals(dataType)) {
 544  24
             validateString(value, constraint, elementPath, valResults);
 545  6
         } else if (DataType.INTEGER.equals(dataType)) {
 546  0
             validateInteger(value, constraint, elementPath, valResults);
 547  6
         } else if (DataType.LONG.equals(dataType)) {
 548  0
             validateLong(value, constraint, elementPath, valResults);
 549  6
         } else if (DataType.DOUBLE.equals(dataType)) {
 550  1
             validateDouble(value, constraint, elementPath, valResults);
 551  5
         } else if (DataType.FLOAT.equals(dataType)) {
 552  0
             validateFloat(value, constraint, elementPath, valResults);
 553  5
         } else if (DataType.BOOLEAN.equals(dataType)) {
 554  0
             validateBoolean(value, constraint, elementPath, valResults);
 555  5
         } else if (DataType.DATE.equals(dataType)) {
 556  5
             validateDate(value, constraint, elementPath, valResults, dateParser);
 557  
         }
 558  30
     }
 559  
 
 560  
     protected void validateBoolean(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 561  0
         if (!(value instanceof Boolean)) {
 562  
             try {
 563  0
                 Boolean.valueOf(value.toString());
 564  0
             } catch (Exception e) {
 565  0
                 ValidationResultInfo val = new ValidationResultInfo(element, value);
 566  0
                 val.setError(getMessage("validation.mustBeBoolean"));
 567  0
                 results.add(val);
 568  0
             }
 569  
         }
 570  0
     }
 571  
 
 572  
     protected void validateDouble(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 573  1
         Double v = null;
 574  
 
 575  1
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 576  
 
 577  1
         if (value instanceof Number) {
 578  1
             v = ((Number) value).doubleValue();
 579  
         } else {
 580  
             try {
 581  0
                 v = Double.valueOf(value.toString());
 582  0
             } catch (Exception e) {
 583  0
                 val.setError(getMessage("validation.mustBeDouble"));
 584  0
             }
 585  
         }
 586  
 
 587  1
         if (val.isOk()) {
 588  1
             Double maxValue = ValidatorUtils.getDouble(constraint.getInclusiveMax());
 589  1
             Double minValue = ValidatorUtils.getDouble(constraint.getExclusiveMin());
 590  
 
 591  1
             if (maxValue != null && minValue != null) {
 592  
                 // validate range
 593  1
                 if (v > maxValue || v < minValue) {
 594  1
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 595  
                 }
 596  0
             } else if (maxValue != null) {
 597  0
                 if (v > maxValue) {
 598  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 599  
                 }
 600  0
             } else if (minValue != null) {
 601  0
                 if (v < minValue) {
 602  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 603  
                 }
 604  
             }
 605  
         }
 606  
 
 607  1
         if (!val.isOk()) {
 608  1
             results.add(val);
 609  
         }
 610  1
     }
 611  
 
 612  
     protected void validateFloat(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 613  0
         Float v = null;
 614  
 
 615  0
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 616  0
         if (value instanceof Number) {
 617  0
             v = ((Number) value).floatValue();
 618  
         } else {
 619  
             try {
 620  0
                 v = Float.valueOf(value.toString());
 621  0
             } catch (Exception e) {
 622  0
                 val.setError(getMessage("validation.mustBeFloat"));
 623  0
             }
 624  
         }
 625  
 
 626  0
         if (val.isOk()) {
 627  0
             Float maxValue = ValidatorUtils.getFloat(constraint.getInclusiveMax());
 628  0
             Float minValue = ValidatorUtils.getFloat(constraint.getExclusiveMin());
 629  
 
 630  0
             if (maxValue != null && minValue != null) {
 631  
                 // validate range
 632  0
                 if (v > maxValue || v < minValue) {
 633  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 634  
                 }
 635  0
             } else if (maxValue != null) {
 636  0
                 if (v > maxValue) {
 637  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 638  
                 }
 639  0
             } else if (minValue != null) {
 640  0
                 if (v < minValue) {
 641  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 642  
                 }
 643  
             }
 644  
         }
 645  
 
 646  0
         if (!val.isOk()) {
 647  0
             results.add(val);
 648  
         }
 649  0
     }
 650  
 
 651  
     protected void validateLong(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 652  0
         Long v = null;
 653  
 
 654  0
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 655  0
         if (value instanceof Number) {
 656  0
             v = ((Number) value).longValue();
 657  
         } else {
 658  
             try {
 659  0
                 v = Long.valueOf(value.toString());
 660  0
             } catch (Exception e) {
 661  0
                 val.setError(getMessage("validation.mustBeLong"));
 662  0
             }
 663  
         }
 664  
 
 665  0
         if (val.isOk()) {
 666  0
             Long maxValue = ValidatorUtils.getLong(constraint.getInclusiveMax());
 667  0
             Long minValue = ValidatorUtils.getLong(constraint.getExclusiveMin());
 668  
 
 669  0
             if (maxValue != null && minValue != null) {
 670  
                 // validate range
 671  0
                 if (v > maxValue || v < minValue) {
 672  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 673  
                 }
 674  0
             } else if (maxValue != null) {
 675  0
                 if (v > maxValue) {
 676  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 677  
                 }
 678  0
             } else if (minValue != null) {
 679  0
                 if (v < minValue) {
 680  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 681  
                 }
 682  
             }
 683  
         }
 684  
 
 685  0
         if (!val.isOk()) {
 686  0
             results.add(val);
 687  
         }
 688  
 
 689  0
     }
 690  
 
 691  
     protected void validateInteger(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 692  0
         Integer v = null;
 693  
 
 694  0
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 695  
 
 696  0
         if (value instanceof Number) {
 697  0
             v = ((Number) value).intValue();
 698  
         } else {
 699  
             try {
 700  0
                 v = Integer.valueOf(value.toString());
 701  0
             } catch (Exception e) {
 702  0
                 val.setError(getMessage("validation.mustBeInteger"));
 703  0
             }
 704  
         }
 705  
 
 706  0
         if (val.isOk()) {
 707  0
             Integer maxValue = ValidatorUtils.getInteger(constraint.getInclusiveMax());
 708  0
             Integer minValue = ValidatorUtils.getInteger(constraint.getExclusiveMin());
 709  
 
 710  0
             if (maxValue != null && minValue != null) {
 711  
                 // validate range
 712  0
                 if (v > maxValue || v < minValue) {
 713  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 714  
                 }
 715  0
             } else if (maxValue != null) {
 716  0
                 if (v > maxValue) {
 717  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 718  
                 }
 719  0
             } else if (minValue != null) {
 720  0
                 if (v < minValue) {
 721  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 722  
                 }
 723  
             }
 724  
         }
 725  
 
 726  0
         if (!val.isOk()) {
 727  0
             results.add(val);
 728  
         }
 729  0
     }
 730  
 
 731  
     protected void validateDate(Object value, Constraint constraint, String element, List<ValidationResultInfo> results, DateParser dateParser) {
 732  5
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 733  
 
 734  5
         Date v = null;
 735  
 
 736  5
         if (value instanceof Date) {
 737  5
             v = (Date) value;
 738  
         } else {
 739  
             try {
 740  0
                 v = dateParser.parseDate(value.toString());
 741  0
             } catch (Exception e) {
 742  0
                 val.setError(getMessage("validation.mustBeDate"));
 743  0
             }
 744  
         }
 745  
 
 746  5
         if (val.isOk()) {
 747  5
             Date maxValue = ValidatorUtils.getDate(constraint.getInclusiveMax(), dateParser);
 748  5
             Date minValue = ValidatorUtils.getDate(constraint.getExclusiveMin(), dateParser);
 749  
 
 750  5
             if (maxValue != null && minValue != null) {
 751  
                 // validate range
 752  0
                 if (v.getTime() > maxValue.getTime() || v.getTime() < minValue.getTime()) {
 753  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
 754  
                 }
 755  5
             } else if (maxValue != null) {
 756  0
                 if (v.getTime() > maxValue.getTime()) {
 757  0
                     val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
 758  
                 }
 759  5
             } else if (minValue != null) {
 760  5
                 if (v.getTime() < minValue.getTime()) {
 761  1
                     val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
 762  
                 }
 763  
             }
 764  
         }
 765  
 
 766  5
         if (!val.isOk()) {
 767  1
             results.add(val);
 768  
         }
 769  5
     }
 770  
 
 771  
     protected void validateString(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
 772  
 
 773  24
         if (value == null) {
 774  0
             value = "";
 775  
         }
 776  24
         String s = value.toString().trim();
 777  
 
 778  24
         ValidationResultInfo val = new ValidationResultInfo(element, value);
 779  
 
 780  24
         Integer maxLength = tryParse(constraint.getMaxLength());
 781  24
         if (maxLength != null && constraint.getMinLength() != null && constraint.getMinLength() > 0) {
 782  22
             if (s.length() > maxLength || s.length() < constraint.getMinLength()) {
 783  10
                 val.setError(MessageUtils.interpolate(getMessage("validation.lengthOutOfRange"), toMap(constraint)));
 784  
             }
 785  2
         } else if (maxLength != null) {
 786  1
             if (s.length() > Integer.parseInt(constraint.getMaxLength())) {
 787  1
                 val.setError(MessageUtils.interpolate(getMessage("validation.maxLengthFailed"), toMap(constraint)));
 788  
             }
 789  1
         } else if (constraint.getMinLength() != null && constraint.getMinLength() > 0) {
 790  1
             if (s.length() < constraint.getMinLength()) {
 791  1
                 val.setError(MessageUtils.interpolate(getMessage("validation.minLengthFailed"), toMap(constraint)));
 792  
             }
 793  
         }
 794  
 
 795  24
         if (!val.isOk()) {
 796  12
             results.add(val);
 797  
         }
 798  24
     }
 799  
 
 800  
     protected String getMessage(String messageId) {
 801  29
         if (null == messageService) {
 802  29
             return messageId;
 803  
         }
 804  
 
 805  0
         Message msg = messageService.getMessage(messageLocaleKey, messageGroupKey, messageId);
 806  
 
 807  0
         return msg.getValue();
 808  
     }
 809  
 
 810  
     protected String getElementXpath(Stack<String> elementStack) {
 811  74
         StringBuilder xPath = new StringBuilder();
 812  74
         Iterator<String> itr = elementStack.iterator();
 813  145
         while (itr.hasNext()) {
 814  71
             xPath.append(itr.next());
 815  71
             if(itr.hasNext()){
 816  34
                     xPath.append("/");
 817  
             }
 818  
         }
 819  
 
 820  74
         return xPath.toString();
 821  
     }
 822  
 
 823  
     /*
 824  
      * Homemade has text so we dont need outside libs.
 825  
      */
 826  
     protected boolean hasText(String string) {
 827  
 
 828  29
         if (string == null || string.length() < 1) {
 829  1
             return false;
 830  
         }
 831  28
         int stringLength = string.length();
 832  
 
 833  28
         for (int i = 0; i < stringLength; i++) {
 834  28
             char currentChar = string.charAt(i);
 835  28
             if (' ' != currentChar || '\t' != currentChar || '\n' != currentChar) {
 836  28
                 return true;
 837  
             }
 838  
         }
 839  
 
 840  0
         return false;
 841  
     }
 842  
 
 843  
     protected Map<String, Object> toMap(Constraint c) {
 844  14
         Map<String, Object> result = new HashMap<String, Object>();
 845  14
         result.put("minOccurs", c.getMinOccurs());
 846  14
         result.put("maxOccurs", c.getMaxOccurs());
 847  14
         result.put("minLength", c.getMinLength());
 848  14
         result.put("maxLength", c.getMaxLength());
 849  14
         result.put("minValue", c.getExclusiveMin());
 850  14
         result.put("maxValue", c.getInclusiveMax());
 851  
         // result.put("dataType", c.getDataType());
 852  
 
 853  14
         return result;
 854  
     }
 855  
 
 856  
     public SearchDispatcher getSearchDispatcher() {
 857  0
         return searchDispatcher;
 858  
     }
 859  
 
 860  
     public void setSearchDispatcher(SearchDispatcher searchDispatcher) {
 861  1
         this.searchDispatcher = searchDispatcher;
 862  1
     }
 863  
 
 864  
         @Override
 865  
         public List<ValidationResultInfo> validateObject(FieldDefinition field,
 866  
                         Object o, ObjectStructureDefinition objStructure,Stack<String> elementStack) {
 867  0
                 return null;
 868  
         }
 869  
 }