001/**
002 * Copyright 2005-2014 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.service;
017
018import java.beans.PropertyDescriptor;
019
020import org.kuali.rice.krad.datadictionary.DataDictionaryEntry;
021import org.kuali.rice.krad.datadictionary.ReferenceDefinition;
022import org.kuali.rice.krad.datadictionary.state.StateMapping;
023import org.kuali.rice.krad.datadictionary.validation.AttributeValueReader;
024import org.kuali.rice.krad.datadictionary.validation.result.DictionaryValidationResult;
025import org.kuali.rice.krad.document.Document;
026import org.kuali.rice.krad.document.TransactionalDocument;
027
028/**
029 * Defines the API for the validating against the data dictionary.
030 *
031 * @author Kuali Rice Team (rice.collab@kuali.org)
032 */
033public interface DictionaryValidationService {
034
035    /**
036     * Validates the contents of a document (i.e. attributes within a document) against the data dictionary.
037     *
038     * @param document - document to validate
039     */
040    public void validateDocument(Document document);
041
042    /**
043     * Validates the contents of a document and recursively validates any of its updatable references
044     *
045     * @param document the document
046     * @param maxDepth the maximum numbers of levels to recurse
047     * @param validateRequired whether to validate whether a field is required and is currently blank
048     */
049    public void validateDocumentAndUpdatableReferencesRecursively(Document document, int maxDepth,
050            boolean validateRequired);
051
052    /**
053     * Validates the contents of a document and recursively validates any of its updatable references
054     *
055     * @param document the document
056     * @param maxDepth the maximum numbers of levels to recurse
057     * @param validateRequired whether to validate whether a field is required and is currently blank
058     * @param chompLastLetterSFromCollectionName if true, the error path for any collections encountered will have the
059     * last "s" removed from the collection name if it ends
060     * with the letter "s".  If false, this method acts like {@link #validateDocumentAndUpdatableReferencesRecursively(Document,
061     * int, boolean)}
062     */
063    public void validateDocumentAndUpdatableReferencesRecursively(Document document, int maxDepth,
064            boolean validateRequired, boolean chompLastLetterSFromCollectionName);
065
066    /**
067     * Validates the specified attribute of the given document against the data dictionary.
068     *
069     * @param document
070     * @param attributeName
071     * @param errorPrefix
072     */
073    public void validateDocumentAttribute(Document document, String attributeName, String errorPrefix);
074
075    /**
076     * Validates an object using its class name as the entry name to look up its metadata in the dictionary.
077     *
078     * @param object - an object to validate
079     * @return the dictionary validation result object associated with this validation
080     */
081    public DictionaryValidationResult validate(Object object);
082
083    /**
084     * Validate an object with the passed in dictionary entryName and the specific attribute to be evaluated
085     *
086     * @param object - an object to validate
087     * @param entryName - the dictionary entry name to look up the metadata associated with this object
088     * @param attributeName - the name of the attribute (field) on the object that should be validated
089     * @param doOptionalProcessing true if the validation should do optional validation (e.g. to check if empty values
090     * are required or not), false otherwise
091     * @return the dictionary validation result object associated with this validation
092     * @since 1.1
093     */
094    public DictionaryValidationResult validate(Object object, String entryName, String attributeName,
095            boolean doOptionalProcessing);
096
097    /**
098     * Same as {@link DictionaryValidationService#validate(Object, String, String, boolean)} except
099     * that it provides an explicit data dictionary entry to use for the purpose of validation.
100     * 
101     * @param object - an object to validate
102     * @param entryName - the dictionary entry name to use in association with error look ups
103     * @param entry - the dictionary entry to use for validation
104     * @param doOptionalProcessing true if the validation should do optional validation (e.g. to
105     *        check if empty values are required or not), false otherwise
106     * @return the dictionary validation result object associated with this validation
107     * @since 1.1
108     */
109    public DictionaryValidationResult validate(Object object, String entryName, DataDictionaryEntry entry,
110            boolean doOptionalProcessing);
111
112    /**
113     * Validates the object agains the next state (or current state if there is no next state).
114     *
115     * <p>When no stateMapping exists on the DataDictionaryEntry that applies for this object, validation is considered
116     * stateless and all constraints are processed regardless of their states attribute.</p>
117     *
118     * @param object
119     * @return the dictionary validation result object associated with this validation
120     * @since 2.2
121     */
122    public DictionaryValidationResult validateAgainstNextState(Object object);
123
124    /**
125     * Validates the object against the state specified.
126     *
127     * <p>Important note: Alternatively the state can be changed on the
128     * object itself and another validation method can be used instead of this one (in practice, you'd revert the
129     * state on the object if validation returns errors).</p>
130     *
131     * @param object
132     * @param validationState
133     * @return the dictionary validation result object associated with this validation
134     * @since 2.2
135     */
136    public DictionaryValidationResult validateAgainstState(Object object, String validationState);
137
138    /**
139     * Same as other validate methods, except allows you to provide the attributeValueReader directly for evaluation
140     *
141     * @param valueReader - an object to validate
142     * @param doOptionalProcessing true if the validation should do optional validation (e.g. to check if empty values
143     * are required or not), false otherwise
144     * @return the dictionary validation result object associated with this validation
145     * @since 1.1
146     */
147    public DictionaryValidationResult validate(AttributeValueReader valueReader, boolean doOptionalProcessing,
148            String validationState, StateMapping stateMapping);
149
150    /**
151     * Encapsulates {@link #validateBusinessObject(BusinessObject)} and returns boolean so one
152     * doesn't need to check the ErrorMap.Validates the business object primitive attributes against
153     * the data dictionary. Adds errors to the map as they are encountered.<br/>
154     * <br/>
155     * Makes no error path adjustments
156     * 
157     * @param businessObject - business object to validate
158     * @return boolean validOrNot
159     */
160    public boolean isBusinessObjectValid(Object businessObject);
161
162    /**
163     * Encapsulates {@link #validateBusinessObject(BusinessObject)} and returns boolean so one
164     * doesn't need to check the ErrorMap.Validates the business object primitive attributes against
165     * the data dictionary. Adds errors to the map as they are encountered.<br/>
166     * <br/>
167     * Makes no error path adjustments
168     * 
169     * @param businessObject - business object to validate
170     * @param prefix - error prefix
171     * @return boolean valid or not
172     */
173    public boolean isBusinessObjectValid(Object businessObject, String prefix);
174
175    /**
176     * Validates the business object primitive attributes against the data dictionary. Adds errors to the map as they
177     * are
178     * encountered.
179     *
180     * @param businessObject - business object to validate
181     * @deprecated since 1.1 - use validate(Object.class) instead
182     */
183    @Deprecated
184    public void validateBusinessObject(Object businessObject);
185
186    /**
187     * Validates the business object primitive attributes against the data dictionary. Adds errors to the map as they
188     * are
189     * encountered.
190     *
191     * @param businessObject - business object to validate
192     * @param validateRequired - whether to execute required field checks
193     * @deprecated since 1.1 - use validate(Object.class) instead
194     */
195    @Deprecated
196    public void validateBusinessObject(Object businessObject, boolean validateRequired);
197
198    /**
199     * This method examines the populated BusinessObject bo instance passed in for a member named by the referenceName.
200     * If this
201     * member exists, and if this member is a descendent of BusinessObject, then an existence check proceeds.
202     *
203     * First the foreign keys for this reference are gathered, and then examined to see if they have values. If they do
204     * not have
205     * values, the method ends with a true return value. If they all have values, then an object with those primary
206     * keys
207     * is retrieve
208     * from the database. If one is retrieve, then the reference exists, and True is returned. Otherwise, false is
209     * returned.
210     *
211     * This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
212     * errorMap with no
213     * prefix, other than what has already been pushed onto the errorMap.
214     *
215     * @param dataObject - the data object whose reference is being tested.
216     * @param reference - The ReferenceDefinition to be existence tested.
217     * @return True if no exceptions occur and the object exists in the db, false otherwise.
218     */
219    public boolean validateReferenceExists(Object dataObject, ReferenceDefinition reference);
220
221    /**
222     * This method examines the populated BusinessObject bo instance passed in for a member named by the referenceName.
223     * If this
224     * member exists, and if this member is a descendent of BusinessObject, then an existence check proceeds.
225     *
226     * First the foreign keys for this reference are gathered, and then examined to see if they have values. If they do
227     * not have
228     * values, the method ends with a true return value. If they all have values, then an object with those primary
229     * keys
230     * is retrieve
231     * from the database. If one is retrieve, then the reference exists, and True is returned. Otherwise, false is
232     * returned.
233     *
234     * This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
235     * errorMap with no
236     * prefix, other than what has already been pushed onto the errorMap.
237     *
238     * @param dataObject - the data object whose reference is being tested.
239     * @param referenceName - The name of the member to be existence tested.
240     * @return True if no exceptions occur and the object exists in the db, false otherwise.
241     */
242    public boolean validateReferenceExists(Object dataObject, String referenceName);
243
244    /**
245     * This method retrieves the reference from the DB, and then tests whether the object is active.
246     *
247     * It will return false if there is no activeIndicator field on this object, if the object doesnt exist in the DB,
248     * if the field
249     * doesnt exist or cannot be cast as a boolean, if the field value is null, or if the field value is false.
250     *
251     * It will only return true if the reference bo is present, the field is present, it is a boolean and non-null, and
252     * the value is
253     * true.
254     *
255     * This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
256     * errorMap with no
257     * prefix, other than what has already been pushed onto the errorMap.
258     *
259     * @param dataObject
260     * @param reference
261     * @return true if the reference is active
262     */
263    public boolean validateReferenceIsActive(Object dataObject, ReferenceDefinition reference);
264
265    /**
266     * This method retrieves the reference from the DB, and then tests whether the object is active.
267     *
268     * It will return false if there is no activeIndicator field on this object, if the object doesnt exist in the DB,
269     * if the field
270     * doesnt exist or cannot be cast as a boolean, if the field value is null, or if the field value is false.
271     *
272     * It will only return true if the reference bo is present, the field is present, it is a boolean and non-null, and
273     * the value is
274     * true.
275     *
276     * This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
277     * errorMap with no
278     * prefix, other than what has already been pushed onto the errorMap.
279     *
280     * @param dataObject
281     * @param referenceName
282     * @return true if the reference is active
283     */
284    public boolean validateReferenceIsActive(Object dataObject, String referenceName);
285
286    /**
287     * validateReferenceExistsAndIsActive intelligently tests the designated reference on the data object for both existence and
288     * active status, where
289     * appropriate
290     *
291     * <p>It will not test anything if the foreign-key fields for the given reference aren't filled out with values,
292     * and
293     * it
294     * will not test active status if the reference doesn't exist.</p>
295     *
296     * <p>Further, it will only test active status where the correct flag is set.</p>
297     *
298     * <p>On failures of either sort, it will put the relevant errors into the GlobalVariables errorMap, and return a
299     * false. If there
300     * are no failures, or nothing can be tested because the foreign-key fields arent fully filled out, it will return
301     * true and add
302     * no errors.</p>
303     *
304     * <p>This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
305     * errorMap with no
306     * prefix, other than what has already been pushed onto the errorMap.</p>
307     *
308     * @param dataObject - the data object instance to be tested.
309     * @param reference - the ReferenceDefinition to control the nature of the testing.
310     * @return true or false as per the criteria above
311     */
312    public boolean validateReferenceExistsAndIsActive(Object dataObject, ReferenceDefinition reference);
313
314    /**
315     * This method intelligently tests the designated reference on the data object for both existence and active status, where
316     * appropriate.
317     *
318     * It will not test anything if the foreign-key fields for the given reference arent filled out with values, and it
319     * will not
320     * test active status if the reference doesnt exist.
321     *
322     * Note that it will not fail or raise any error if all of the foreign-keys are filled with a value. If this needs
323     * to be tested
324     * (ie, the 'if any field is filled, then all must be filled' rule), you'll have to do that separately.
325     *
326     * Further, it will only test active status where the correct flag is set.
327     *
328     * On failures of either sort, it will put the relevant errors into the GlobalVariables errorMap, and return a
329     * false. If there
330     * are no failures, or nothing can be tested because the foreign-key fields arent fully filled out, it will return
331     * true and add
332     * no errors.
333     *
334     * This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
335     * errorMap with no
336     * prefix, other than what has already been pushed onto the errorMap.
337     *
338     * @param dataObject - the BusinessObject instance to be tested.
339     * @param referenceName - the member name on the data object to be tested for existence and active-state
340     * @param attributeToHighlightOnFail - the fieldName to highlight with the error message on a failure
341     * @param displayFieldName - the human-readable display name of the failed field, to go in the error message
342     * @return true or false as per the criteria above
343     */
344    public boolean validateReferenceExistsAndIsActive(Object dataObject, String referenceName,
345            String attributeToHighlightOnFail, String displayFieldName);
346
347    /**
348     * This method does an existence check against all references of a BusinessObject as defined in the
349     * MaintenanceDocument.xml file
350     * for that business object.
351     *
352     * Appropriate errors will also be placed in the GlobalVariables.ErrorMap.
353     *
354     * This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
355     * errorMap with no
356     * prefix, other than what has already been pushed onto the errorMap.
357     *
358     * @param dataObject - BusinessObject instance that should be tested
359     * @return true if all passed existence tests, false if any failed
360     */
361    public boolean validateDefaultExistenceChecks(Object dataObject);
362
363    /**
364     * Does an existence check against all references configured as a default existence check in the maintenance
365     * document data dictionary file for the given business object
366     *
367     * Appropriate errors will also be placed in the GlobalVariables.ErrorMap.
368     *
369     * This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
370     * errorMap
371     * with no
372     * prefix, other than what has already been pushed onto the errorMap.
373     *
374     * @param dataObject parent business object instance to retrieve default checks for
375     * @param newCollectionItem new collection line to validate
376     * @param collectionName name of the collection in the parent
377     * @return true if all passed existence tests, false if any failed
378     */
379    public boolean validateDefaultExistenceChecksForNewCollectionItem(Object dataObject, Object newCollectionItem,
380            String collectionName);
381
382    /**
383     * This method does an existence check against all references of a transactionalDocument
384     *
385     * Appropriate errors will also be placed in the GlobalVariables.ErrorMap.
386     *
387     * This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
388     * errorMap
389     * with no
390     * prefix, other than what has already been pushed onto the errorMap.
391     *
392     * @param document document instance that should be tested
393     * @return true if all passed existence tests, false if any failed
394     */
395    public boolean validateDefaultExistenceChecksForTransDoc(TransactionalDocument document);
396
397    /**
398     * This method does an existence check against all references of a transactionalDocument
399     *
400     * Appropriate errors will also be placed in the GlobalVariables.ErrorMap.
401     *
402     * This method assumes that you already have the errorPath set exactly as desired, and adds new errors to the
403     * errorMap
404     * with no
405     * prefix, other than what has already been pushed onto the errorMap.
406     *
407     * @param document document instance that should be tested
408     * @param accountingLine that should be tested
409     * @param collectionName that should be tested
410     * @return true if all passed existence tests, false if any failed
411     */
412    public boolean validateDefaultExistenceChecksForNewCollectionItem(TransactionalDocument document,
413            Object newCollectionItem, String collectionName);
414
415    /**
416     * @deprecated since 1.1
417     */
418    @Deprecated
419    public void validatePrimitiveFromDescriptor(String entryName, Object object, PropertyDescriptor propertyDescriptor,
420            String errorPrefix, boolean validateRequired);
421}