Package net.sourceforge.stripes.validation.expression

Source Code of net.sourceforge.stripes.validation.expression.ExpressionExecutorSupport$BeanVariableResolver

/* Copyright 2008 Tim Fennell
*
* Licensed 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 net.sourceforge.stripes.validation.expression;

import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.util.bean.BeanUtil;
import net.sourceforge.stripes.util.Log;
import net.sourceforge.stripes.controller.ParameterName;
import net.sourceforge.stripes.controller.StripesConstants;
import net.sourceforge.stripes.validation.ValidationMetadata;
import net.sourceforge.stripes.validation.ValidationErrors;
import net.sourceforge.stripes.validation.ValidationError;
import net.sourceforge.stripes.validation.ScopedLocalizableError;
import net.sourceforge.stripes.exception.StripesRuntimeException;

import javax.servlet.jsp.el.VariableResolver;
import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.Expression;
import javax.servlet.jsp.el.ExpressionEvaluator;
import java.util.List;

/**
* A base class that provides the general plumbing for running expression validation
* using the old JSP 2.0 style ExpressionEvaluator. Uses a custom VariableResolver
* to make fields of the ActionBean available in the expression.
*
* @author Tim Fennell
* @since Stripes 1.5
*/
@SuppressWarnings("deprecation")
public abstract class ExpressionExecutorSupport implements ExpressionExecutor {

    private static final Log log = Log.getInstance(ExpressionExecutorSupport.class);

    /**
     * A JSP EL VariableResolver that first attempts to look up the value of the variable as a first
     * level property on the ActionBean, and if does not exist then delegates to the built in resolver.
     *
     * @author Tim Fennell
     * @since Stripes 1.3
     */
    protected static class BeanVariableResolver implements VariableResolver {
        private ActionBean bean;
        private Object currentValue;

        /** Constructs a resolver based on the action bean . */
        BeanVariableResolver(ActionBean bean) {
            this.bean = bean;
        }

        /** Sets the value that the 'this' variable will point at. */
        void setCurrentValue(Object value) {
            this.currentValue = value;
        }

        /**
         * Recognizes a couple of special variables, and if the property requested
         * isn't one of them, just looks up a property on the action bean.
         *
         * @param property the name of the variable/property being looked for
         * @return the property value or null
         * @throws javax.servlet.jsp.el.ELException
         */
        public Object resolveVariable(String property) throws ELException {
            if (isSelfKeyword(bean, property)) {
                return this.currentValue;
            }
            else if (StripesConstants.REQ_ATTR_ACTION_BEAN.equals(property)) {
                return this.bean;
            }
            else {
                try { return BeanUtil.getPropertyValue(property, bean); }
                catch (Exception e) { return null; }
            }
        }
    }

    // See interface for javadoc
    public void evaluate(final ActionBean bean, final ParameterName name, final List<Object> values,
                         final ValidationMetadata validationInfo, final ValidationErrors errors) {
        Expression expr = null;
        BeanVariableResolver resolver = null;

        if (validationInfo.expression() != null) {
            try {
                // Make sure we can get an evaluator
                ExpressionEvaluator evaluator = getEvaluator();
                if (evaluator == null) return;

                // If this turns out to be slow we could probably cache the parsed expression
                String expression = validationInfo.expression();
                expr = evaluator.parseExpression(expression, Boolean.class, null);
                resolver = new BeanVariableResolver(bean);
            }
            catch (ELException ele) {
                throw new StripesRuntimeException(
                        "Could not parse the EL expression being used to validate field " +
                        name.getName() + ". This is not a transient error. Please double " +
                        "check the following expression for errors: " +
                        validationInfo.expression(), ele);
            }
        }

        // Then validate each value we have and add error messages
        for (Object value : values) {
            // And then if we have an expression to use
            if (expr != null) {
                try {
                    resolver.setCurrentValue(value);
                    Boolean result = (Boolean) expr.evaluate(resolver);
                    if (!Boolean.TRUE.equals(result)) {
                        ValidationError error = new ScopedLocalizableError(ERROR_DEFAULT_SCOPE,
                                                                           ERROR_KEY);
                        error.setFieldValue(String.valueOf(value));
                        errors.add(name.getName(), error);
                    }
                }
                catch (ELException ele) {
                    log.error("Error evaluating expression for property ", name.getName(),
                              " of class ", bean.getClass().getSimpleName(), ". Expression: ",
                              validationInfo.expression());
                }
            }
        }
    }

    /**
     * Must be implemented by subclasses to return an instance of ExpressionEvaluator
     * that can be used to execute expressions.
     *
     * @return a working ExpressionEvaluator implementation.
     */
    protected abstract ExpressionEvaluator getEvaluator() ;

    /**
     * Utility method for checking deprecated use of 'this' in expressions. Checks if
     * <code>prop</code> == 'this' and logs a Warning message inviting the user to
     * update to the new keyword.
     */
    static boolean isSelfKeyword(ActionBean bean, Object prop) {
        boolean isDeprecatedThis = THIS.equals(prop);
        if (isDeprecatedThis) {
            // log a message if using the deprecated 'this' keyword. This can happen
            // if the appserver (e.g. tomcat 7) is configured to skip identifier
            // check.
            // this message encourages the user to update EL validation
            // expressions using the new keyword
            log.warn("You are using the 'this' keyword in ActionBean class '" + bean.getClass().getName() +
                    "'. It is a reserved keyword. Your application server doesn't seem to complain, but " +
                    "the application could malfunction on other servers. " +
                    "Please use the keyword '" + SELF + "' in replacement of 'this' in your EL expressions.");
        }
        return isDeprecatedThis || SELF.equals(prop);
    }

}
TOP

Related Classes of net.sourceforge.stripes.validation.expression.ExpressionExecutorSupport$BeanVariableResolver

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.