001/**
002 * Copyright 2005-2015 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.datadictionary.validation;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
020import org.kuali.rice.krad.datadictionary.validation.capability.CaseConstrainable;
021import org.kuali.rice.krad.datadictionary.validation.capability.Constrainable;
022import org.kuali.rice.krad.datadictionary.validation.capability.MustOccurConstrainable;
023import org.kuali.rice.krad.datadictionary.validation.capability.PrerequisiteConstrainable;
024import org.kuali.rice.krad.datadictionary.validation.capability.SimpleConstrainable;
025import org.kuali.rice.krad.datadictionary.validation.capability.ValidCharactersConstrainable;
026import org.kuali.rice.krad.datadictionary.validation.constraint.CaseConstraint;
027import org.kuali.rice.krad.datadictionary.validation.constraint.MustOccurConstraint;
028import org.kuali.rice.krad.datadictionary.validation.constraint.PrerequisiteConstraint;
029import org.kuali.rice.krad.datadictionary.validation.constraint.SimpleConstraint;
030import org.kuali.rice.krad.datadictionary.validation.constraint.ValidCharactersConstraint;
031import org.kuali.rice.krad.uif.UifConstants;
032import org.kuali.rice.krad.uif.UifPropertyPaths;
033import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata;
034import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
035import org.kuali.rice.krad.uif.view.ViewModel;
036
037import java.util.ArrayList;
038import java.util.HashMap;
039import java.util.List;
040import java.util.Map;
041
042/**
043 * AttributeValueReader which can read the correct values from all InputFields which exist on the View
044 *
045 * @author Kuali Rice Team (rice.collab@kuali.org)
046 */
047public class ViewAttributeValueReader extends BaseAttributeValueReader {
048    private ViewModel form;
049
050    private List<Constrainable> inputFields = new ArrayList<Constrainable>();
051    private Map<String, InputFieldConstrainableInfo> inputFieldMap = new HashMap<String, InputFieldConstrainableInfo>();
052
053    /**
054     * Constructor for ViewAttributeValueReader, the View must already be indexed and
055     * the InputFields must have already be initialized for this reader to work properly
056     *
057     * @param form model object representing the View's form data
058     */
059    public ViewAttributeValueReader(ViewModel form) {
060        this.form = form;
061
062        ViewPostMetadata viewPostMetadata = form.getViewPostMetadata();
063
064        // Copying information stored about InputField in the post metadata to info objects for use by this reader
065        for (String id : viewPostMetadata.getInputFieldIds()) {
066            InputFieldConstrainableInfo info = new InputFieldConstrainableInfo();
067
068            Object label = viewPostMetadata.getComponentPostData(id, UifConstants.PostMetadata.LABEL);
069            if (label != null) {
070                info.setLabel((String) label);
071            }
072
073            Object name = viewPostMetadata.getComponentPostData(id, UifConstants.PostMetadata.PATH);
074            if (name != null) {
075                info.setName((String) name);
076            }
077
078            Object validCharactersConstraint = viewPostMetadata.getComponentPostData(id,
079                    UifConstants.PostMetadata.VALID_CHARACTER_CONSTRAINT);
080            if (validCharactersConstraint != null) {
081                info.setValidCharactersConstraint((ValidCharactersConstraint) validCharactersConstraint);
082            }
083
084            Object caseConstraint = viewPostMetadata.getComponentPostData(id,
085                    UifConstants.PostMetadata.CASE_CONSTRAINT);
086            if (caseConstraint != null) {
087                info.setCaseConstraint((CaseConstraint) caseConstraint);
088            }
089
090            Object prerequisiteConstraints = viewPostMetadata.getComponentPostData(id,
091                    UifConstants.PostMetadata.PREREQ_CONSTSTRAINTS);
092            if (prerequisiteConstraints != null) {
093                info.setPrerequisiteConstraints((List<PrerequisiteConstraint>) prerequisiteConstraints);
094            }
095
096            Object mustOccurConstraints = viewPostMetadata.getComponentPostData(id,
097                    UifConstants.PostMetadata.MUST_OCCUR_CONSTRAINTS);
098            if (mustOccurConstraints != null) {
099                info.setMustOccurConstraints((List<MustOccurConstraint>) mustOccurConstraints);
100            }
101
102            Object simpleConstraint = viewPostMetadata.getComponentPostData(id,
103                    UifConstants.PostMetadata.SIMPLE_CONSTRAINT);
104            if (simpleConstraint != null) {
105                info.setSimpleConstraint((SimpleConstraint) simpleConstraint);
106            }
107
108            inputFields.add(info);
109            inputFieldMap.put(info.getName(), info);
110        }
111    }
112
113    /**
114     * Gets the definition which is an InputField on the View/Page
115     */
116    @Override
117    public Constrainable getDefinition(String attributeName) {
118        InputFieldConstrainableInfo field = inputFieldMap.get(attributeName);
119        if (field != null) {
120            return field;
121        } else {
122            return null;
123        }
124    }
125
126    /**
127     * Gets all InputFields (which extend Constrainable)
128     *
129     * @return constrainable input fields
130     */
131    @Override
132    public List<Constrainable> getDefinitions() {
133        return inputFields;
134    }
135
136    /**
137     * Returns the label associated with the InputField which has that AttributeName
138     *
139     * @param attributeName attribute name
140     * @return label associated with the named attribute
141     */
142    @Override
143    public String getLabel(String attributeName) {
144        InputFieldConstrainableInfo field = inputFieldMap.get(attributeName);
145        if (field != null) {
146            return field.getLabel();
147        } else {
148            return "";
149        }
150    }
151
152    /**
153     * Returns the Form object
154     *
155     * @return form set in the constructor
156     */
157    @Override
158    public Object getObject() {
159        return form;
160    }
161
162    /**
163     * Not used for this reader, returns null
164     *
165     * @return null
166     */
167    @Override
168    public Constrainable getEntry() {
169        return null;
170    }
171
172    /**
173     * Returns current attributeName which represents the path
174     *
175     * @return attributeName set on this reader
176     */
177    @Override
178    public String getPath() {
179        return this.attributeName;
180    }
181
182    /**
183     * Gets the type of value for this AttributeName as represented on the Form
184     *
185     * @param attributeName
186     * @return attribute type
187     */
188    @Override
189    public Class<?> getType(String attributeName) {
190        Object fieldValue = ObjectPropertyUtils.getPropertyValue(form, attributeName);
191        return fieldValue.getClass();
192    }
193
194    /**
195     * If the current attribute being evaluated is a field of an addLine return false because it should not
196     * be evaluated during Validation.
197     *
198     * @return false if InputField is part of an addLine for a collection, true otherwise
199     */
200    @Override
201    public boolean isReadable() {
202        if (attributeName != null && attributeName.contains(UifPropertyPaths.NEW_COLLECTION_LINES)) {
203            return false;
204        }
205        return true;
206    }
207
208    /**
209     * Return value of the field for the attributeName currently set on this reader
210     *
211     * @param <X> return type
212     * @return value of the field for the attributeName currently set on this reader
213     * @throws AttributeValidationException
214     */
215    @Override
216    public <X> X getValue() throws AttributeValidationException {
217        X fieldValue = null;
218        if (StringUtils.isNotBlank(this.attributeName)) {
219            fieldValue = ObjectPropertyUtils.<X>getPropertyValue(form, this.attributeName);
220        }
221        return fieldValue;
222    }
223
224    /**
225     * Return value of the field for the attributeName passed in
226     *
227     * @param attributeName name (which represents a path) of the value to be retrieved on the Form
228     * @param <X> return type
229     * @return value of that attributeName represents on the form
230     * @throws AttributeValidationException
231     */
232    @Override
233    public <X> X getValue(String attributeName) throws AttributeValidationException {
234        X fieldValue = null;
235        if (StringUtils.isNotBlank(attributeName)) {
236            fieldValue = ObjectPropertyUtils.<X>getPropertyValue(form, this.attributeName);
237        }
238        return fieldValue;
239    }
240
241    /**
242     * Cones this AttributeValueReader
243     *
244     * @return AttributeValueReader
245     */
246    @Override
247    public AttributeValueReader clone() {
248        ViewAttributeValueReader clone = new ViewAttributeValueReader(form);
249        clone.setAttributeName(this.attributeName);
250        return clone;
251    }
252
253    /**
254     * This is a simple object used to contain information about InputFields that are being evaluated and used by
255     * this ViewAttributeValueReader.
256     *
257     * <p>For full documentation refer to the {@link org.kuali.rice.krad.uif.field.InputField} class.</p>
258     */
259    public class InputFieldConstrainableInfo implements SimpleConstrainable, CaseConstrainable, PrerequisiteConstrainable, MustOccurConstrainable, ValidCharactersConstrainable {
260
261        private String label;
262        private String name;
263        private ValidCharactersConstraint validCharactersConstraint;
264        private CaseConstraint caseConstraint;
265        private List<PrerequisiteConstraint> prerequisiteConstraints;
266        private List<MustOccurConstraint> mustOccurConstraints;
267        private SimpleConstraint simpleConstraint;
268
269        /**
270         * Get the field's label
271         *
272         * @return the label
273         */
274        public String getLabel() {
275            return label;
276        }
277
278        /**
279         * @see org.kuali.rice.krad.datadictionary.validation.ViewAttributeValueReader.InputFieldConstrainableInfo#getLabel()
280         */
281        public void setLabel(String label) {
282            this.label = label;
283        }
284
285        /**
286         * {@inheritDoc}
287         */
288        @Override
289        public String getName() {
290            return name;
291        }
292
293        /**
294         * @see org.kuali.rice.krad.datadictionary.validation.ViewAttributeValueReader.InputFieldConstrainableInfo#getName()
295         */
296        public void setName(String name) {
297            this.name = name;
298        }
299
300        /**
301         * {@inheritDoc}
302         */
303        @Override
304        public ValidCharactersConstraint getValidCharactersConstraint() {
305            return validCharactersConstraint;
306        }
307
308        /**
309         * @see org.kuali.rice.krad.datadictionary.validation.ViewAttributeValueReader.InputFieldConstrainableInfo#getValidCharactersConstraint()
310         */
311        public void setValidCharactersConstraint(ValidCharactersConstraint validCharactersConstraint) {
312            this.validCharactersConstraint = validCharactersConstraint;
313        }
314
315        /**
316         * {@inheritDoc}
317         */
318        @Override
319        public CaseConstraint getCaseConstraint() {
320            return caseConstraint;
321        }
322
323        /**
324         * @see org.kuali.rice.krad.datadictionary.validation.ViewAttributeValueReader.InputFieldConstrainableInfo#getCaseConstraint()
325         */
326        public void setCaseConstraint(CaseConstraint caseConstraint) {
327            this.caseConstraint = caseConstraint;
328        }
329
330        /**
331         * {@inheritDoc}
332         */
333        @Override
334        public List<PrerequisiteConstraint> getPrerequisiteConstraints() {
335            return prerequisiteConstraints;
336        }
337
338        /**
339         * @see org.kuali.rice.krad.datadictionary.validation.ViewAttributeValueReader.InputFieldConstrainableInfo#getPrerequisiteConstraints()
340         */
341        public void setPrerequisiteConstraints(List<PrerequisiteConstraint> prerequisiteConstraints) {
342            this.prerequisiteConstraints = prerequisiteConstraints;
343        }
344
345        /**
346         * {@inheritDoc}
347         */
348        @Override
349        public List<MustOccurConstraint> getMustOccurConstraints() {
350            return mustOccurConstraints;
351        }
352
353        /**
354         * @see org.kuali.rice.krad.datadictionary.validation.ViewAttributeValueReader.InputFieldConstrainableInfo#getMustOccurConstraints()
355         */
356        public void setMustOccurConstraints(List<MustOccurConstraint> mustOccurConstraints) {
357            this.mustOccurConstraints = mustOccurConstraints;
358        }
359
360        /**
361         * {@inheritDoc}
362         */
363        @Override
364        public SimpleConstraint getSimpleConstraint() {
365            return simpleConstraint;
366        }
367
368        /**
369         * @see org.kuali.rice.krad.datadictionary.validation.ViewAttributeValueReader.InputFieldConstrainableInfo#getSimpleConstraint()
370         */
371        public void setSimpleConstraint(SimpleConstraint simpleConstraint) {
372            this.simpleConstraint = simpleConstraint;
373        }
374    }
375
376}