Package org.apache.beehive.netui.pageflow

Source Code of org.apache.beehive.netui.pageflow.ProcessPopulate$ExpressionUpdateNode

/*
* Copyright 2004 The Apache Software Foundation.
*
* 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.
*
* $Header:$
*/
package org.apache.beehive.netui.pageflow;

import org.apache.beehive.netui.util.internal.InternalStringBuilder;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.jsp.el.VariableResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.beehive.netui.pageflow.internal.InternalUtils;
import org.apache.beehive.netui.script.Expression;
import org.apache.beehive.netui.script.ExpressionEvaluator;
import org.apache.beehive.netui.script.ExpressionEvaluatorFactory;
import org.apache.beehive.netui.script.ExpressionUpdateException;
import org.apache.beehive.netui.script.common.ImplicitObjectUtil;
import org.apache.beehive.netui.util.Bundle;
import org.apache.beehive.netui.util.logging.Logger;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.struts.action.ActionForm;

/**
* Implement the processPopulate stage of the Struts / PageFlow request
* processing lifecycle.  The {@link #populate(HttpServletRequest, HttpServletResponse, ActionForm, boolean)} method is
* invoked in order to take request parameters from the {@link HttpServletRequest}
* use the key / value pairs from the request to perform an update to the underlying
* JavaBean objects.
* <br/>
* <br/>
* Updates are performed on a key / value pair if the key is an expression; otherwise,
* the updates are delegated to the Struts processPopulate infrastructure.
*
*/
public class ProcessPopulate
{
    /**
     * This defines the name of the parameter that will contain the NetUI ID map..
     */
    public static final String IDMAP_PARAMETER_NAME = "netuiIdMap";

    private static final Logger _logger = Logger.getInstance(ProcessPopulate.class);

    // these must be kept in sync with the context names specified in the scripting languages
    private static final String PAGE_FLOW_CONTEXT = "pageFlow";
    private static final String GLOBAL_APP_CONTEXT = "globalApp";

    private static final String WLW_TAG_HANDLER_PREFIX = "wlw-";
    private static final String WLW_TAG_HANDLER_SUFFIX = ":";

    private static final Map handlerMap = new HashMap();

    /**
     * An inner class that represnts the data that will be used to
     * perform an update.  If a key has a prefix handler, this
     * node is constructed and passed to the prefix handler
     * so that the prefix handler can change the expression or
     * values that will be used to execute the expression update.
     */
    public final static class ExpressionUpdateNode
    {
        public String expression = null;
        public String[] values = null;             

        // can't be constructed outside of this class
        private ExpressionUpdateNode() {}

        public String toString()
        {
            InternalStringBuilder buf = new InternalStringBuilder();
            buf.append("expression: " + expression + "\n");
            if(values != null)
                for(int i = 0; i < values.length; i++)
                    buf.append("value[" + i + "]: " + values[i]);
            else buf.append("values are null");

            return buf.toString();
        }
    }

    /**
     * Register a {@link org.apache.beehive.netui.pageflow.RequestParameterHandler} that is added to handle a
     * particular prefix which be present as a prefix to a request parameter
     * key.  For keys that match the prefix, the key / value from the request
     * are put in an {@link ExpressionUpdateNode} struct and handed to the
     * {@link org.apache.beehive.netui.pageflow.RequestParameterHandler} for processing.  The returned {@link ExpressionUpdateNode}
     * is used to perform an expression update.
     *
     * @param prefix the String prefix that will be appended to request paramters that
     * should pass through the {@link RequestParameterHandler} before being updated.
     * @param handler the handler that should handle all request paramters with
     * the given <code>prefix</code>
     */
    public static void registerPrefixHandler(String prefix, RequestParameterHandler handler)
    {
        // should happen very infrequently
        synchronized(handlerMap)
        {
            String msg = "Register RequestParameterHandler with\n\tprefix: " + prefix + "\n\thandler: " + (handler != null ? handler.getClass().getName(): null);

            if(_logger.isInfoEnabled()) _logger.info(msg);

            if (handlerMap.get(prefix) == null)
                handlerMap.put(prefix, handler);
        }
    }

    /**
     * Write the handler name specified onto the given expression.
     */
    public static String writeHandlerName(String handler, String expression)
    {
        if(!ExpressionEvaluatorFactory.getInstance().isExpression(expression))
            throw new IllegalArgumentException(Bundle.getErrorString("ProcessPopulate_handler_nonAtomicExpression", new Object[] {expression}));

        if(!handlerMap.containsKey(handler))
            throw new IllegalStateException(Bundle.getErrorString("ProcessPopulate_handler_notRegistered", new Object[] {handler}));

        InternalStringBuilder buf = new InternalStringBuilder();
        buf.append(WLW_TAG_HANDLER_PREFIX);
        buf.append(handler);
        buf.append(WLW_TAG_HANDLER_SUFFIX);
        buf.append(expression);

        return buf.toString();
    }

    /**
     * Use the request parameters to populate all properties that have expression keys into
     * the underlying JavaBeans.
     * Creates a <code>java.util.Map</code> of objects that will be consumed by
     *         Struts processPopulate.  This includes all request attributes that
     *         were not expressions
     *
     * @param request the current <code>HttpServletRequest</code>
     * @param form if this request references an action and it has an <code>ActionForm</code>
     *             associated with it, then the <code>form</code> parameter is non-null.
     * @throws ServletException when an error occurs in populating data after
     *         the request; failure here can be caused by failures in creating
     *         or executing update expressions.
     */
    public static void populate(HttpServletRequest request, HttpServletResponse response, ActionForm form, boolean requestHasPopulated)
        throws ServletException
    {
        String key = null;
        Map strutsProperties = null;
        ExpressionEvaluator ee = ExpressionEvaluatorFactory.getInstance();

        // a boolean so that we can avoid an instanceof below...
        boolean isMultipart = false;

        // if this returns null, it's not a mulitpart request
        Map params = MultipartRequestUtils.handleMultipartRequest(request, form);

        // make adjustments
        if(params != null)
            isMultipart = true;
        else params = request.getParameterMap();

        if(params == null)
        {
            if(_logger.isWarnEnabled()) _logger.warn("An error occurred checking a request for multipart status.  No model values were updated.");
            return;
        }

        /* explicitly build a variable resolver that is used to provide objects that may be updated to the expression engine */
        VariableResolver variableResolver = ImplicitObjectUtil.getUpdateVariableResolver(form, request, response, true);

        /* todo: are there any ordering issues with using an Iterator vs. an Enumeration here? */
        Iterator iterator = params.keySet().iterator();
        while (iterator.hasNext())
        {
            key = (String) iterator.next();
            String expr = null;

            // if there is an expression map, lookup the real expression from the name
            expr = key;
            if (_logger.isDebugEnabled())
                _logger.debug("key: " + key + " value type: " + params.get(key).getClass().getName() + " value: " + params.get(key));

            try
            {
                Object paramsValue = params.get(key);
                if (ee.containsExpression(expr))
                {
                    Object updateValue = null;
                    if (!isMultipart || paramsValue instanceof String[])
                    {
                        String[] values = (String[]) paramsValue;

                        // the only "contains" case that is accepted
                        if (expr.startsWith(WLW_TAG_HANDLER_PREFIX))
                        {
                            if (_logger.isDebugEnabled()) _logger.debug("Found an expression requiring a TAG HANDLER");

                            ExpressionUpdateNode node = doTagHandler(key, expr, values, request);

                            expr = node.expression;
                            values = node.values;
                        }

                        if (values != null && values.length == 1)
                            updateValue = values[0];
                        else
                            updateValue = values;
                    }
                    // handle funky types that Struts returns for a file upload request handler
                    else
                    {
                        updateValue = params.get(key);
                    }

                    try
                    {
                        // trap any bad expressions here
                        if (ee.isExpression(expr))
                        {
                            // common case, make this fast
                            if (!requestHasPopulated)
                                ee.update(expr, updateValue, variableResolver, true);
                            // must check the expression to make sure pageFlow. and globalApp. don't get executed more than once
                            else
                            {
                                Expression pe = ee.parseExpression(expr);
                                String contextName = pe.getContext();
                                if (!contextName.equals(PAGE_FLOW_CONTEXT) && !contextName.equals(GLOBAL_APP_CONTEXT))
                                    ee.update(expr, updateValue, variableResolver, true);
                            }
                        }
                    }
                            // catch any errors, particularly expression parse failures
                    catch (ExpressionUpdateException e)
                    {
                        String s = Bundle.getString("ExprUpdateError", new Object[]{expr, e});

                        // this is the hairy NetUI Warning that gets printed to the console
                        System.err.println(s);
                        if (_logger.isErrorEnabled()) _logger.error(s);

                        // add binding errors via PageFlowUtils
                        InternalUtils.addBindingUpdateError(request, expr, s, e);
                    }
                }
                else
                {
                    if (_logger.isDebugEnabled()) _logger.debug("HTTP request parameter key \"" + key + "\" is not an expression, handle with Struts");

                    if (strutsProperties == null)
                        strutsProperties = new HashMap();

                    strutsProperties.put(key, paramsValue);
                }
            }
                    // catch any unexpected exception
            catch (Exception e)
            {
                String s = Bundle.getString("ProcessPopulate_exprUpdateError", new Object[]{expr, e});
                //e.printStackTrace();

                System.err.println(s);

                if (_logger.isWarnEnabled()) _logger.warn(s, e);

                // add binding errors via PageFlowUtils
                InternalUtils.addBindingUpdateError(request, expr, s, e);
            }
        }

        handleStrutsProperties(strutsProperties, form);
    }

    /**
     * Process a single key.
     *
     * @param key the request key that is being processed
     * @param request the ServletRequest object representing this request
     */
    static final ExpressionUpdateNode doTagHandler(String key, String expression, String[] values, HttpServletRequest request)
    {
        // not sure if this array will be mutable.  don't want to find out at this point.
        String[] _values = values;

        // key might be mangled here; make a copy
        String expr = expression;

        if(_logger.isDebugEnabled()) _logger.debug("Found prefixed tag; handlerName: " + key.substring(WLW_TAG_HANDLER_PREFIX.length(), key.indexOf(WLW_TAG_HANDLER_SUFFIX)));
           
        String handlerName = expression.substring(WLW_TAG_HANDLER_PREFIX.length(), expression.indexOf(WLW_TAG_HANDLER_SUFFIX));
       
        // execute callback to parameter handler.  Generally, these are tags.
        RequestParameterHandler handler = (RequestParameterHandler)handlerMap.get(handlerName);
       
        if(handler != null)
        {
            expr = expression.substring(expression.indexOf(WLW_TAG_HANDLER_SUFFIX)+1);
           
            if(_logger.isDebugEnabled()) _logger.debug("found handler for prefix \"" + handlerName + "\" type: " +
                                   (handler != null ? handler.getClass().getName() : null) + "\n\t" +
                                   "key: \"" + key + "\" expr: \"" + expr + "\"");
           
            ExpressionUpdateNode node = new ExpressionUpdateNode();
            node.expression = expr;
            node.values = _values;
           
            // request, request key, the standalone expression (may have other stuff bracketing the expression
            handler.process(request, key, expression, node);
           
            return node;
        }
        else throw new IllegalStateException("Request parameter references a tag handler prefix \"" +
                                             handlerName + "\" that is not registered for expression \"" + key + "\"");
    }

    // @struts: org.apache.struts.util.RequestUtils.populate
    private static final void handleStrutsProperties(Map strutsProperties, ActionForm form)
    {
        if(strutsProperties != null)
        {
            if(_logger.isDebugEnabled()) _logger.debug("Handle Struts request parameters.");

            // default to Struts for non-expression keys
            try
            {
                BeanUtils.populate(form, strutsProperties);
            }
            catch(Exception e)
            {
                throw new RuntimeException("Exception processing bean and request parameters: ", e);
            }
        }
    }
}
TOP

Related Classes of org.apache.beehive.netui.pageflow.ProcessPopulate$ExpressionUpdateNode

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.