View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.datadictionary.validation.processor;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.kuali.rice.core.api.uif.DataType;
22  import org.kuali.rice.krad.datadictionary.DataDictionaryEntry;
23  import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
24  import org.kuali.rice.krad.datadictionary.validation.AttributeValueReader;
25  import org.kuali.rice.krad.datadictionary.validation.DictionaryObjectAttributeValueReader;
26  import org.kuali.rice.krad.datadictionary.validation.ValidationUtils;
27  import org.kuali.rice.krad.datadictionary.validation.capability.Constrainable;
28  import org.kuali.rice.krad.datadictionary.validation.capability.HierarchicallyConstrainable;
29  import org.kuali.rice.krad.datadictionary.validation.constraint.CaseConstraint;
30  import org.kuali.rice.krad.datadictionary.validation.constraint.Constraint;
31  import org.kuali.rice.krad.datadictionary.validation.constraint.DataTypeConstraint;
32  import org.kuali.rice.krad.datadictionary.validation.constraint.WhenConstraint;
33  import org.kuali.rice.krad.datadictionary.validation.result.DictionaryValidationResult;
34  import org.kuali.rice.krad.datadictionary.validation.result.ProcessorResult;
35  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
36  
37  /**
38   * This object processes 'case constraints', which are constraints that are imposed only in specific cases, for
39   * example,
40   * when a value is
41   * equal to some constant, or greater than some limit.
42   *
43   * @author Kuali Rice Team (rice.collab@kuali.org)
44   */
45  public class CaseConstraintProcessor extends MandatoryElementConstraintProcessor<CaseConstraint> {
46  
47      private static final String CONSTRAINT_NAME = "case constraint";
48  
49      /**
50       * @see org.kuali.rice.krad.datadictionary.validation.processor.ConstraintProcessor#process(DictionaryValidationResult,
51       *      Object, org.kuali.rice.krad.datadictionary.validation.capability.Constrainable,
52       *      org.kuali.rice.krad.datadictionary.validation.AttributeValueReader)
53       */
54      @Override
55      public ProcessorResult process(DictionaryValidationResult result, Object value, CaseConstraint caseConstraint,
56              AttributeValueReader attributeValueReader) throws AttributeValidationException {
57  
58          // Don't process this constraint if it's null
59          if (null == caseConstraint) {
60              return new ProcessorResult(result.addNoConstraint(attributeValueReader, CONSTRAINT_NAME));
61          }
62          AttributeValueReader constraintAttributeReader = attributeValueReader.clone();
63  
64          String operator = (ValidationUtils.hasText(caseConstraint.getOperator())) ? caseConstraint.getOperator() :
65                  "EQUALS";
66          AttributeValueReader fieldPathReader = (ValidationUtils.hasText(caseConstraint.getPropertyName())) ?
67                  getChildAttributeValueReader(caseConstraint.getPropertyName(), attributeValueReader) :
68                  attributeValueReader;
69  
70          Constrainable caseField = (null != fieldPathReader) ? fieldPathReader.getDefinition(
71                  fieldPathReader.getAttributeName()) : null;
72          Object fieldValue = (null != fieldPathReader) ? fieldPathReader.getValue(fieldPathReader.getAttributeName()) :
73                  value;
74          DataType fieldDataType = (null != caseField && caseField instanceof DataTypeConstraint) ?
75                  ((DataTypeConstraint) caseField).getDataType() : null;
76  
77          // Default to a string comparison
78          if (fieldDataType == null) {
79              fieldDataType = DataType.STRING;
80          }
81  
82          // If fieldValue is null then skip Case check
83          if (null == fieldValue) {
84              // FIXME: not sure if the definition and attribute value reader should change under this case
85              return new ProcessorResult(result.addSkipped(attributeValueReader, CONSTRAINT_NAME), caseField,
86                      fieldPathReader);
87          }
88  
89          List<Constraint> constraints = new ArrayList<Constraint>();
90          // Extract value for field Key
91          for (WhenConstraint wc : caseConstraint.getWhenConstraint()) {
92              evaluateWhenConstraint(fieldValue, fieldDataType, operator, caseConstraint, wc, attributeValueReader,
93                      constraints);
94          }
95          if (!constraints.isEmpty()) {
96              return new ProcessorResult(result.addSuccess(attributeValueReader, CONSTRAINT_NAME), null,
97                      constraintAttributeReader, constraints);
98          }
99  
100         // Assuming that not finding any case constraints is equivalent to 'skipping' the constraint
101         return new ProcessorResult(result.addSkipped(attributeValueReader, CONSTRAINT_NAME));
102     }
103 
104     private void evaluateWhenConstraint(Object fieldValue, DataType fieldDataType, String operator,
105             CaseConstraint caseConstraint, WhenConstraint wc, AttributeValueReader attributeValueReader,
106             List<Constraint> constraints) {
107         if (ValidationUtils.hasText(wc.getValuePath())) {
108             Object whenValue = null;
109 
110             AttributeValueReader whenValueReader = getChildAttributeValueReader(wc.getValuePath(),
111                     attributeValueReader);
112             whenValue = whenValueReader.getValue(whenValueReader.getAttributeName());
113 
114             if (ValidationUtils.compareValues(fieldValue, whenValue, fieldDataType, operator,
115                     caseConstraint.isCaseSensitive(), dateTimeService) && null != wc.getConstraint()) {
116                 constraints.add(wc.getConstraint());
117             }
118         } else {
119             List<Object> whenValueList = wc.getValues();
120 
121             for (Object whenValue : whenValueList) {
122                 if (ValidationUtils.compareValues(fieldValue, whenValue, fieldDataType, operator,
123                         caseConstraint.isCaseSensitive(), dateTimeService) && null != wc.getConstraint()) {
124                     constraints.add(wc.getConstraint());
125                     break;
126                 }
127             }
128         }
129     }
130 
131     @Override
132     public String getName() {
133         return CONSTRAINT_NAME;
134     }
135 
136     /**
137      * @see org.kuali.rice.krad.datadictionary.validation.processor.ConstraintProcessor#getConstraintType()
138      */
139     @Override
140     public Class<? extends Constraint> getConstraintType() {
141         return CaseConstraint.class;
142     }
143 
144     private AttributeValueReader getChildAttributeValueReader(String key,
145             AttributeValueReader attributeValueReader) throws AttributeValidationException {
146         String[] lookupPathTokens = ValidationUtils.getPathTokens(key);
147 
148         AttributeValueReader localAttributeValueReader = attributeValueReader;
149         for (int i = 0; i < lookupPathTokens.length; i++) {
150             for (Constrainable definition : localAttributeValueReader.getDefinitions()) {
151                 String attributeName = definition.getName();
152                 if (attributeName.equals(lookupPathTokens[i])) {
153                     if (i == lookupPathTokens.length - 1) {
154                         localAttributeValueReader.setAttributeName(attributeName);
155                         return localAttributeValueReader;
156                     }
157                     if (definition instanceof HierarchicallyConstrainable) {
158                         String childEntryName = ((HierarchicallyConstrainable) definition).getChildEntryName();
159                         DataDictionaryEntry entry = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary()
160                                 .getDictionaryObjectEntry(childEntryName);
161                         Object value = attributeValueReader.getValue(attributeName);
162                         attributeValueReader.setAttributeName(attributeName);
163                         String attributePath = attributeValueReader.getPath();
164                         localAttributeValueReader = new DictionaryObjectAttributeValueReader(value, childEntryName,
165                                 entry, attributePath);
166                     }
167                     break;
168                 }
169             }
170         }
171         return null;
172     }
173 
174 }