Package org.apache.myfaces.commons.validator

Source Code of org.apache.myfaces.commons.validator.AbstractCompareToValidator

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.commons.validator;

import java.util.Comparator;

import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.FacesMessage;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.faces.render.Renderer;
import javax.faces.validator.ValidatorException;

import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFValidator;
import org.apache.myfaces.commons.util.MessageUtils;

/**
*
* Validates this component against another component.
* <p>
* Specify the foreign component with the for={foreign-component-id} attribute.
* </p>
* <p>
* Valid operator attribute values:
* </p>
* <ul>
*   <li>equals:                  eq, ==, =,</li>
*      <li>not equals:              ne, !=,</li>
*   <li>greater than:            gt, &gt;,</li>
*   <li>less than:               lt, &lt;,</li>
*   <li>greater than or equals:  ge, &gt;=,</li>
*   <li>less than or equals:     le, &lt;=</li>
* </ul>
* <p>
* If the comparator attribute is specified, the component values are compared
* using the specified java.util.Comparator object.
* If no comparator is specified, the component values must implement Comparable
* and are compared using compareTo().
* If either value or foreign value does not implement Comparable and no Comparator
* is specified, validation always succeeds.
* </p>
* <p>
* Put this validator on the bottom-most component to insure that
* the foreign component's value has been converted and validated first.
* </p>
* <p>
* However, this validator will attempt to convert and validate the foreign
* component's value if this has not already occurred.  This process may not
* be identical to the standard JSF conversion and validation process.
* </p><p>
* The validation error message key is currently hardcoded as
* </p>
* <p>
*     "{0} value &lt;{1}&gt; must be {2} {3} value &lt;{4}&gt;"
* </p>
* where
* <ul>
*       <li>{0} is the parent component id,</li>
*       <li>{1} is the parent component value,</li>
*       <li>{2} is the operator name,</li>
*       <li>{3} is the foreign component id, and</li>
*       <li>{4} is the foreign component value.</li>
* </ul>
* <p>
* The alternateOperatorName attribute can specify a custom operator name.
* For example, use "after" instead of "greater than" when comparing dates.
*
* The message attribute can specify an alternate validation error message key.
* For example, use "{0} must be {2} {3}" to remove values from the message.
* </p>
* <p>
* Known issues:
* </p>
* <ul>
*   <li> Operator names should be localized.</li>
*   <li> The default message key should be localized.</li>
*   <li> Perhaps an exception should be thrown if the two values are not Comparable and no Comparator is specified.</li>
* </ul>
*  
*  
* @author Mike Kienenberger (latest modification by $Author: lu4242 $)
* @version $Revision: 1099842 $ $Date: 2011-05-05 10:28:24 -0500 (Thu, 05 May 2011) $
*/
@JSFValidator(
   name = "mcv:validateCompareTo",
   clazz = "org.apache.myfaces.commons.validator.CompareToValidator",
   tagClass = "org.apache.myfaces.commons.validator.ValidateCompareToTag",
   serialuidtag = "-8879289182242196266L")
public abstract class AbstractCompareToValidator extends ValidatorBase {
    /**
     * <p>The standard converter id for this converter.</p>
     */
    public static final String     VALIDATOR_ID        = "org.apache.myfaces.commons.validator.CompareTo";

    /**
     * <p>The message identifier of the {@link FacesMessage} to be created if
     * the comparison check fails.</p>
     */
    public static final String COMPARE_TO_MESSAGE_ID = "org.apache.myfaces.commons.validator.CompareTo.INVALID";
   
    public AbstractCompareToValidator(){
        super();
    }

    public static final String OPERATOR_EQUALS = "eq";
    public static final String OPERATOR_NOT_EQUALS = "ne";
    public static final String OPERATOR_GREATER_THAN = "gt";
    public static final String OPERATOR_LESS_THAN = "lt";
    public static final String OPERATOR_GREATER_THAN_OR_EQUALS = "ge";
    public static final String OPERATOR_LESS_THAN_OR_EQUALS = "le";

    public static final String OPERATOR_EQUALS_ALT = "==";
    public static final String OPERATOR_NOT_EQUALS_ALT = "!=";
    public static final String OPERATOR_GREATER_THAN_ALT = ">";
    public static final String OPERATOR_LESS_THAN_ALT = "<";
    public static final String OPERATOR_GREATER_THAN_OR_EQUALS_ALT = ">=";
    public static final String OPERATOR_LESS_THAN_OR_EQUALS_ALT = "<=";

    public static final String OPERATOR_EQUALS_ALT2 = "=";

    protected String getOperatorForString(String operatorSpecified)
    {
        if (OPERATOR_EQUALS.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_EQUALS;
        else if (OPERATOR_NOT_EQUALS.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_NOT_EQUALS;
        else if (OPERATOR_GREATER_THAN.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_GREATER_THAN;
        else if (OPERATOR_LESS_THAN.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_LESS_THAN;
        else if (OPERATOR_GREATER_THAN_OR_EQUALS.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_GREATER_THAN_OR_EQUALS;
        else if (OPERATOR_LESS_THAN_OR_EQUALS.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_LESS_THAN_OR_EQUALS;

        else if (OPERATOR_EQUALS_ALT.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_EQUALS;
        else if (OPERATOR_NOT_EQUALS_ALT.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_NOT_EQUALS;
        else if (OPERATOR_GREATER_THAN_ALT.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_GREATER_THAN;
        else if (OPERATOR_LESS_THAN_ALT.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_LESS_THAN;
        else if (OPERATOR_GREATER_THAN_OR_EQUALS_ALT.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_GREATER_THAN_OR_EQUALS;
        else if (OPERATOR_LESS_THAN_OR_EQUALS_ALT.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_LESS_THAN_OR_EQUALS;

        else if (OPERATOR_EQUALS_ALT2.equalsIgnoreCase(operatorSpecified))
            return OPERATOR_EQUALS;

        throw new IllegalStateException("Operator has unknown value of '" + operatorSpecified + "'");
    }

    protected String nameForOperator(String operator)
    {
        if (OPERATOR_EQUALS.equals(operator))
            return "equal to";
        else if (OPERATOR_NOT_EQUALS.equals(operator))
            return "inequal to";
        else if (OPERATOR_GREATER_THAN.equals(operator))
            return "greater than";
        else if (OPERATOR_LESS_THAN.equals(operator))
            return "less than";
        else if (OPERATOR_GREATER_THAN_OR_EQUALS.equals(operator))
            return "greater than or equal to";
        else if (OPERATOR_LESS_THAN_OR_EQUALS.equals(operator))
            return "less than or equal to";

        throw new IllegalStateException("Operator has unknown value of '" + operator + "'");
    }

    protected boolean validateOperatorOnComparisonResult(String operator, int result)
    {
        if (OPERATOR_EQUALS.equals(operator))
            return result == 0;
        else if (OPERATOR_NOT_EQUALS.equals(operator))
            return result != 0;
        else if (OPERATOR_GREATER_THAN.equals(operator))
            return result > 0;
        else if (OPERATOR_LESS_THAN.equals(operator))
            return result < 0;
        else if (OPERATOR_GREATER_THAN_OR_EQUALS.equals(operator))
            return result >= 0;
        else if (OPERATOR_LESS_THAN_OR_EQUALS.equals(operator))
            return result <= 0;

        throw new IllegalStateException("Operator has unknown value of '" + operator + "'");
    }

    public void validate(
        FacesContext facesContext,
        UIComponent uiComponent,
        Object value)
        throws ValidatorException {

        if (facesContext == null) throw new NullPointerException("facesContext");
        if (uiComponent == null) throw new NullPointerException("uiComponent");

        // Don't perform validation if the value is null
        if (value == null)
        {
            return;
        }

        String foreignComponentName = getFor();
        foreignComponentName = (foreignComponentName != null && foreignComponentName.length() > 0) ? foreignComponentName : getForId();
        if (foreignComponentName == null) {
            throw new FacesException("No id set to compare. Use 'for' in jsp mode and 'forId' in facelets mode");
        }

        UIComponent foreignComponent = (UIComponent) uiComponent.getParent().findComponent(foreignComponentName);
        if(foreignComponent == null)
            throw new FacesException("Unable to find component '" + foreignComponentName + "' (calling findComponent on component '" + uiComponent.getId() + "')");

        if(false == foreignComponent instanceof EditableValueHolder)
            throw new FacesException("Component '" + foreignComponent.getId() + "' does not implement EditableValueHolder");
        EditableValueHolder foreignEditableValueHolder = (EditableValueHolder)foreignComponent;

        if (foreignEditableValueHolder.isRequired() && foreignEditableValueHolder.getValue()== null ) {
            return;
        }

        Object foreignValue;
        if (foreignEditableValueHolder.isValid())
        {
            foreignValue = foreignEditableValueHolder.getValue();
        }
        else
        {
            try
            {
                foreignValue = getConvertedValueNonValid(facesContext, foreignComponent);
            }
            catch(ConverterException e)
            {
                /*
                 * If the value cannot be converted this should return,
                 * because does not have sense compare one
                 * foreign invalid value with other value.
                 * this force end the validation but do not continue
                 * with the next phases, because the converter
                 * of the foreign component fails and show a validation error.
                 */
                return;
            }
        }

        // Don't perform validation if the foreign value is null
        if (null == foreignValue)
        {
            return;
        }

        String operator = getOperatorForString(getOperator());

        String alternateOperatorName = getAlternateOperatorName();
        Object[] args = {
                uiComponent.getId(),
                value.toString(),
                (alternateOperatorName == null) ? nameForOperator(operator) : alternateOperatorName,
                foreignComponent.getId(),
                foreignValue.toString()
        };

        String message = getMessage();
        if (null == messagemessage = COMPARE_TO_MESSAGE_ID;

        Comparator comparator = createComparator();

        if (null != comparator)
        {
            if (false == validateOperatorOnComparisonResult(operator, comparator.compare(value, foreignValue)))
            {
                throw new ValidatorException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR, message, args));
            }
        }
        else if ( (value instanceof Comparable) && (foreignValue instanceof Comparable) )
        {
            try
            {
                if (false == validateOperatorOnComparisonResult(operator, ((Comparable)value).compareTo(foreignValue)))
                {
                    throw new ValidatorException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR, message, args));
                }
            }
            catch (RuntimeException exception)
            {
                if (exception instanceof ValidatorException)
                {
                    throw exception;
                }
                else
                {
                    throw new ValidatorException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR, message + ": " + exception.getLocalizedMessage(), args));
                }
            }
        }
        else if (value instanceof Comparable)
        {
            throw new ClassCastException(getClassCastExceptionMessage(foreignComponent.getId(), Comparable.class, foreignValue));
        }
        else if (foreignValue instanceof Comparable)
        {
            throw new ClassCastException(getClassCastExceptionMessage(uiComponent.getId(), Comparable.class, value));
        }
    }

    protected String getClassCastExceptionMessage(String name, Class clazz, Object object)
    {
        if (null == object)
            return name + " must be type " + clazz + " but is null";
        else return name + " must be type " + clazz + " but is type " + object.getClass();
    }

    protected Comparator createComparator()
    {
        Object comparator = getComparator();

        if (null == comparatorreturn null;

        if (false == comparator instanceof Comparator)
        {
            throw new ClassCastException(getClassCastExceptionMessage("comparator", Comparator.class, comparator));
        }

        return (Comparator)comparator;
    }

    // -------------------------------------------------------- GETTER & SETTER

    /**
     * The JSF id of the component with which to compare values.
     *
     * In JSF 2.0 facelets mode is used to identify the components this
     * validator should be applied to when using composite components.
     * Please use forId in that case instead.
     *
     * @return the foreign component_id, on which a value should be validated
     */
    @JSFProperty
    public abstract String getFor();

    /**
     * @param string the foreign component_id, on which a value should be validated
     */
    public abstract void setFor(String string);
   
    /**
     * The JSF id of the component with which to compare values.
     *
     * @return
     */
    @JSFProperty(faceletsOnly=true)
    public abstract String getForId();
   
    /**
     *
     * @param string the foreign component_id, on which a value should be validated
     */
    public abstract void setForId(String string);

    /**
     * Operator for comparison: equals: eq, ==, =, not equals: ne, !=, greater than: gt, &gt;, less than: lt, &lt;, greater than or equals: ge, &gt;=, less than or equals: le, &lt;=
     *
     * @return
     */
    @JSFProperty
    public abstract String getOperator();

    public abstract void setOperator(String operator);

    /**
     * Value binding for an alternate java.util.Comparator object if component
     * values don't implement Comparable
     *
     * @return
     */
    @JSFProperty
    public abstract Object getComparator();

    public abstract void setComparator(Object comparator);

    /**
     * custom operator name in error message (ie "after" instead of "greater than" for dates)
     *
     * @return
     */
    @JSFProperty
    public abstract String getAlternateOperatorName();

    public abstract void setAlternateOperatorName(String alternateOperatorName);

    // ---------------- Borrowed to convert foreign submitted values

    private Renderer getRenderer(FacesContext context, UIComponent foreignComponent)
    {
        if (context == null) throw new NullPointerException("context");
        String rendererType = foreignComponent.getRendererType();
        if (rendererType == null) return null;
        String renderKitId = context.getViewRoot().getRenderKitId();
        RenderKitFactory rkf = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
        RenderKit renderKit = rkf.getRenderKit(context, renderKitId);
        Renderer renderer = renderKit.getRenderer(foreignComponent.getFamily(), rendererType);
        if (renderer == null)
        {
            getFacesContext().getExternalContext().log("No Renderer found for component " + foreignComponent + " (component-family=" + foreignComponent.getFamily() + ", renderer-type=" + rendererType + ")");
        }
        return renderer;
    }

    private Converter findUIOutputConverter(FacesContext facesContext, UIComponent component)
    {
        Converter converter = null;
        if (component instanceof ValueHolder)
        {
            converter = ((ValueHolder)component).getConverter();
        }
        if (converter != null) return converter;

        //Try to find out by value binding
        ValueExpression vb = component.getValueExpression("value");
        if (vb == null) return null;

        Class valueType = vb.getType(facesContext.getELContext());
        if (valueType == null) return null;

        if (String.class.equals(valueType)) return null;    //No converter needed for String type
        if (Object.class.equals(valueType)) return null;    //There is no converter for Object class

        try
        {
            return facesContext.getApplication().createConverter(valueType);
        }
        catch (FacesException e)
        {
            getFacesContext().getExternalContext().log("No Converter for type " + valueType.getName() + " found", e);
            return null;
        }
    }


    // --------------------- borrowed and modified from UIInput ------------

    private Object getConvertedValueNonValid(FacesContext facesContext, UIComponent component)
        throws ConverterException
    {
        Object componentValueObject;
        //If the component does not implements EditableValueHolder
        //we don't have any way to get the submitted value, so
        //just return null.
        if (!(component instanceof EditableValueHolder))
        {
            return null;
        }
        Object submittedValue = ((EditableValueHolder) component).getSubmittedValue();
        if (submittedValue == null)
        {
            componentValueObject = null;
        }
        else
        {
            Renderer renderer = getRenderer(facesContext, component);
            if (renderer != null)
            {
                componentValueObject = renderer.getConvertedValue(facesContext, component, submittedValue);
            }
            else if (submittedValue instanceof String)
            {
                Converter converter = findUIOutputConverter(facesContext, component);
                if (converter != null)
                {
                    componentValueObject = converter.getAsObject(facesContext, component, (String)submittedValue);
                }
                else
                {
                    componentValueObject = submittedValue;
                }
            }else{
                componentValueObject = submittedValue;
            }
        }
        return componentValueObject;
    }
}
TOP

Related Classes of org.apache.myfaces.commons.validator.AbstractCompareToValidator

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.