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