Package er.directtoweb.delegates

Source Code of er.directtoweb.delegates.ERDQueryValidationDelegate$ErrorKeys

package er.directtoweb.delegates;

import java.math.BigDecimal;
import java.util.Enumeration;

import com.webobjects.appserver.WODisplayGroup;
import com.webobjects.directtoweb.D2WContext;
import com.webobjects.eoaccess.EOAttribute;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EORelationship;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSValidation;

import er.directtoweb.pages.ERD2WQueryPage;
import er.extensions.foundation.ERXStringUtilities;
import er.extensions.foundation.ERXValueUtilities;
import er.extensions.validation.ERXValidationFactory;

/**
* <p>A delegate class for validating user inputs before a query is executed.  Validation rules are derived from the D2W
* context.</p>
*
* <p>To disallow a query with no user inputs, create a rule like:</p>
*
* <p><code>entity.name = 'Foo' => allowsEmptyQueryValue = "false" (BooleanAssignment)</code></p>
*
* <p>To define a validation for a propertyKey, create a rule like:</p>
*
* <p><code>entity.name = 'Foo' and propertyKey = 'bar' => allowsEmptyQueryValue = "false" (BooleanAssignment)</code></p>
*
* <p>To define a minimum length validation for a (String) propertyKey, create a rule like:</p>
*
* <p><code>entity.name = 'Foo' and propertyKey = 'bar' => minimumInputLength = "3" (Assignment)</code></p>
*
* <p>Subclasses wishing to implement custom validation logic should implement the {@link #validateQueryValues} method.
* The implementation should catch validation exceptions and invoke
* {@link er.directtoweb.pages.ERD2WPage#validationFailedWithException(Throwable, Object, String)} with any caught exceptions.  To customize
* behavior, while retaining the default checks, extend {@link ERDQueryValidationDelegate.DefaultQueryValidationDelegate}
* to perform custom validations and then call {@link #validateQueryValues} on the superclass.</p>
*
* @author Travis Cripps
* @d2wKey displayPropertyKeys
* @d2wKey maximumInputLength
* @d2wKey minimumInputLength
* @d2wKey maximumInputValue
* @d2wKey minimumInputValue
*/
public abstract class ERDQueryValidationDelegate {

    // The validation keys correspond to rule names for validation definitions in the D2W model.
    public static interface ValidationKeys {
        public static final String AllowsEmptyQuery = "allowsEmptyQuery"; // Does the page allow a query with no query values?
        public static final String AllowsEmptyQueryValue = "allowsEmptyQueryValue"; // Does the corresponding property key allow an empty query value?

        public static final String MaximumInputLength = "maximumInputLength"; // A minimum input length for String attributes.
        public static final String MinimumInputLength = "minimumInputLength"; // A maximum input length for String attributes.

        public static final String MaximumInputValue = "maximumInputValue"; // A minimum input value for numeric attributes.
        public static final String MinimumInputValue = "minimumInputValue"; // A maximum input value for numeric attributes.
    }

    // The error keys should correspond to entries in the ValidationTemplate.strings file.
    public static interface ErrorKeys {
        public static final String QueryEmpty = "QueryEmpty";
        public static final String QueryValueRequired = "QueryValueRequired";

        public static final String QueryValueTooShort = "QueryValueTooShort";
        public static final String QueryValueTooLong = "QueryValueTooLong";

        public static final String QueryValueTooSmall = "QueryValueTooSmall";
        public static final String QueryValueTooLarge = "QueryValueTooLarge";
    }

    protected D2WContext d2wContext;

    /**
     * Validates the query inputs before executing the query.
     * @param sender query page whose inputs to validate
     */
    public void validateQuery(ERD2WQueryPage sender) {
        d2wContext = sender.d2wContext();

        // First check to see if there are any query values.
        WODisplayGroup displayGroup = sender.displayGroup();
        if (displayGroup.queryMatch().allKeys().count() == 0 && displayGroup.queryMin().allKeys().count() == 0 &&
            displayGroup.queryMax().allKeys().count() == 0 && displayGroup.queryBindings().allKeys().count() == 0 &&
            !ERXValueUtilities.booleanValueWithDefault(d2wContext.valueForKey(ValidationKeys.AllowsEmptyQuery), true)) {
            throw ERXValidationFactory.defaultFactory().createCustomException(null, ErrorKeys.QueryEmpty);
        }

        // Check the query values.
        String cachedPropertyKey = d2wContext.propertyKey();
        validateQueryValues(sender);
        d2wContext.setPropertyKey(cachedPropertyKey);
    }

    /**
     * Validates the query input values from the query page's display group.
     * @param sender query page whose inputs to validate
     */
    public abstract void validateQueryValues(ERD2WQueryPage sender);

    /**
     * Gets the D2WContext against which the validation definitions will be evaluated.
     * from
     * @return the D2WContext
     */
    public D2WContext d2wContext() {
        return d2wContext;
    }

    /**
     * Gets the D2W property key corresponding to the display group key by matching the key with one in the D2W
     * context's <code>displayPropertyKeys</code>.
     * @param key from the display group
     * @return the corresponding D2W key, or the original key if not found
     */
    protected String propertyKeyFromDisplayGroupKey(String key) {
        String result = key;
        if (result.indexOf(".") > 0) {
            NSArray propertyKeys = ERXValueUtilities.arrayValueWithDefault(d2wContext().valueForKey("displayPropertyKeys"), NSArray.EmptyArray);
            boolean found;
            do {
                found = propertyKeys.indexOfObject(result) > 0;
                if (!found) {
                    if (result.indexOf(".") > 0) {
                        result = ERXStringUtilities.keyPathWithoutLastProperty(result);
                    } else {
                        break;
                    }
                }
            } while (!found);
            if (!found) { // Give up.
                result = key;
            }
        }
        return result;
    }

    /**
     * Determines if the D2W context contains a validation definition for the provided validation key}.
     * @param key to check
     * @return true if a validation definition for the given key exists
     */
    public boolean hasValidationDefinitionForKey(String key) {
        return d2wContext != null && d2wContext.valueForKey(key) != null;
    }

    /**
     * Validates a string value, checking minimumInputLength and maximumInputLength.
     * @param value to validate
     * @param key of the property to validate
     * @throws NSValidation.ValidationException when the validation fails
     */
    public void validateStringValueForKey(String value, String key) throws NSValidation.ValidationException {
        int minimumLength = ERXValueUtilities.intValueWithDefault(d2wContext().valueForKey(ValidationKeys.MinimumInputLength), 0);
        if (null == value) {
            if (minimumLength > 0) {
                throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, ErrorKeys.QueryValueRequired);
            }
        } else {
            int maximumLength = ERXValueUtilities.intValueWithDefault(d2wContext().valueForKey(ValidationKeys.MaximumInputLength), -1);

            if (minimumLength > 0 && value.length() < minimumLength) {
                throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, ErrorKeys.QueryValueTooShort);
            }
            if (maximumLength > 0 && value.length() > maximumLength) {
                throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, ErrorKeys.QueryValueTooLong);
            }
        }
    }

    /**
     * Validates a string value, checking minimumInputValue and maximumInputValue.
     * @param value to validate
     * @param key of the property to validate
     * @throws NSValidation.ValidationException when the validation fails
     */
    public void validateNumericValueForKey(Number value, String key) throws NSValidation.ValidationException {
        if (null == value) {
            if (d2wContext.valueForKey(ValidationKeys.MinimumInputValue) != null) {
                throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, "QueryValueRequired");
            }
        } else {
            EOAttribute attribute = d2wContext.attribute();
            String valueType = attribute.valueType();

            if ("s".equals(valueType) || "i".equals(valueType) || "l".equals(valueType)) { // Short or Integer or Long
                long longValue = value.longValue();
                if (hasValidationDefinitionForKey(ValidationKeys.MinimumInputValue)) {
                    Long minimumValue = ERXValueUtilities.longValue(d2wContext().valueForKey(ValidationKeys.MinimumInputValue));
                    if (minimumValue.compareTo(longValue) > 0) {
                        throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, ErrorKeys.QueryValueTooSmall);
                    }
                }
                if (hasValidationDefinitionForKey(ValidationKeys.MaximumInputValue)) {
                    Long maximumValue = ERXValueUtilities.longValue(d2wContext().valueForKey(ValidationKeys.MaximumInputValue));
                    if (maximumValue.compareTo(longValue) < 0) {
                        throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, "QueryValueTooLarge");
                    }
                }
            } else if ("f".equals(valueType) || "d".equals(valueType)) { // Float or Double
                double doubleValue = value.doubleValue();
                if (hasValidationDefinitionForKey(ValidationKeys.MinimumInputValue)) {
                    Double minimumValue = ERXValueUtilities.doubleValue(d2wContext().valueForKey(ValidationKeys.MinimumInputValue));
                    if (minimumValue.compareTo(doubleValue) > 0) {
                        throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, "QueryValueTooSmall");
                    }
                }
                if (hasValidationDefinitionForKey(ValidationKeys.MaximumInputValue)) {
                    Double maximumValue = ERXValueUtilities.doubleValue(d2wContext().valueForKey(ValidationKeys.MaximumInputValue));
                    if (maximumValue.compareTo(doubleValue) < 0) {
                        throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, "QueryValueTooLarge");
                    }
                }
            } else if ("B".equals(valueType)) { // BigDecimal
                BigDecimal bdValue = (value instanceof BigDecimal) ? (BigDecimal)value : new BigDecimal(value.doubleValue());
                if (hasValidationDefinitionForKey(ValidationKeys.MinimumInputValue)) {
                    BigDecimal minimumValue = ERXValueUtilities.bigDecimalValue(d2wContext().valueForKey(ValidationKeys.MinimumInputValue));
                    if (minimumValue.compareTo(bdValue) > 0) {
                        throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, "QueryValueTooSmall");
                    }
                }
                if (hasValidationDefinitionForKey(ValidationKeys.MaximumInputValue)) {
                    BigDecimal maximumValue = ERXValueUtilities.bigDecimalValue(d2wContext().valueForKey(ValidationKeys.MaximumInputValue));
                    if (maximumValue.compareTo(bdValue) < 0) {
                        throw ERXValidationFactory.defaultFactory().createCustomException(null, key, value, "QueryValueTooLarge");
                    }
                }
            }
        }
    }


    /**
     * A "default" implementation of a query validation delegate, which simply validates each key in the query page's
     * display group against validation definitions from the D2W rules.
     */
    public static class DefaultQueryValidationDelegate extends ERDQueryValidationDelegate {

        private ERD2WQueryPage queryPage;

        /**
         * @inheritDoc
         */
        @Override
        public void validateQueryValues(ERD2WQueryPage sender) {
            queryPage = sender;
           
            WODisplayGroup displayGroup = queryPage.displayGroup();
            _validateQueryValues(displayGroup.queryMatch());
            _validateQueryValues(displayGroup.queryMin());
            _validateQueryValues(displayGroup.queryMax());
            _validateQueryValues(displayGroup.queryBindings());
        }

        /**
         * Validates the values in the query dictionary.
         * @param queryDict to validate.
         */
        private void _validateQueryValues(NSDictionary queryDict) {
            for (Enumeration keysEnum = queryDict.keyEnumerator(); keysEnum.hasMoreElements();) {
                String key = (String)keysEnum.nextElement();
                Object value = queryDict.objectForKey(key);
                try {
                    validateValueForQueryKey(value, key);
                } catch (NSValidation.ValidationException ve) {
                    queryPage.validationFailedWithException(ve, null, ve.key());
                }
            }
        }

        /**
         * Validates the value of a particular key in the query dictionary.
         * @param value to validate
         * @param key of the property to validate
         * @throws NSValidation.ValidationException when the validation fails
         */
        public void validateValueForQueryKey(Object value, String key) throws NSValidation.ValidationException {
            if( value instanceof NSKeyValueCoding.Null) { value = null; }

            D2WContext d2wContext = d2wContext();
            String propertyKey = propertyKeyFromDisplayGroupKey(key);
            d2wContext().setPropertyKey(propertyKey);

            if (null == value && !ERXValueUtilities.booleanValueWithDefault(d2wContext.valueForKey(ValidationKeys.AllowsEmptyQueryValue), true)) {
                throw ERXValidationFactory.defaultFactory().createCustomException(null, propertyKey, value, "QueryValueRequired");
            }

            EOAttribute attribute = null;
            if (ERXValueUtilities.booleanValue(d2wContext.valueForKey("isAttribute"))) {
                attribute = d2wContext.attribute();
            } else {
                EORelationship relationship = d2wContext.relationship();
                if (relationship != null && !(value instanceof EOEnterpriseObject)) {
                    String keyWhenRelationship = (String)d2wContext.valueForKey("keyWhenRelationship");
                    if (keyWhenRelationship != null) {
                        EOEntity destinationEntity = relationship.destinationEntity();
                        attribute = destinationEntity.attributeNamed(keyWhenRelationship);
                    }
                }
            }

            if (attribute != null) {
                String valueClassName = attribute.className();
                if (String.class.getName().equals(valueClassName) && value instanceof String) {
                    validateStringValueForKey((String)value, propertyKey);
                } else if (Number.class.getName().equals(valueClassName) || BigDecimal.class.getName().equals(valueClassName)) {
                    validateNumericValueForKey((Number)value, propertyKey);
                }
            }
        }

    }

}
TOP

Related Classes of er.directtoweb.delegates.ERDQueryValidationDelegate$ErrorKeys

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.