Package org.apache.myfaces.orchestra.urlParamNav

Source Code of org.apache.myfaces.orchestra.urlParamNav.UrlParameterViewHandler

/*
* 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.orchestra.urlParamNav;

import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;

import org.apache.myfaces.orchestra.lib.OrchestraException;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Locale;

/**
* Allow the to-view-id URL in a faces-config navigation case to include
* query parameters and EL expressions.
* <p>
* This class plays a few tricks to hide from the real NavigationHandler
* and ViewHandler classes the fact that a URL contains non-standard data.
* <p>
* This class also plays a few reflection-based tricks so that the code can
* be compiled against JSF1.1, and work with both JSF1.1 and JSF1.2. The
* code is a little fragile and will probably need to be updated to work
* correctly with JSF2.0, but that is the fault of the JSF spec.
*/
public class UrlParameterViewHandler extends ViewHandler
{
    private static final Method CALC_CHAR_ENC_METHOD;
    private static final Method INIT_VIEW_METHOD;

    private final ViewHandler original;

    /**
     * Static initialization block.
     */
    static
    {
        CALC_CHAR_ENC_METHOD = getMethodOpt(ViewHandler.class,
                "calculateCharacterEncoding",
                new Class[] {FacesContext.class});

        INIT_VIEW_METHOD = getMethodOpt(ViewHandler.class,
                "initView",
                new Class[] {FacesContext.class});
    }

    /**
     * If the specified class has a method with the specified name and params, return
     * it else return null.
     */
    private static Method getMethodOpt(Class clazz, String methodName, Class[] args)
    {
        try
        {
            return clazz.getMethod(methodName, args);
        }
        catch(NoSuchMethodException e)
        {
            return null;
        }
    }

    /**
     * Constructor.
     */
    public UrlParameterViewHandler(final ViewHandler original)
    {
        this.original = original;
    }

    /**
     * Delegate to wrapped instance.
     * <p>
     * This method was added in JSF1.2. We must therefore use reflection
     * to invoke the method on the wrapped instance. Note that this method
     * is never invoked unless this is a JSF1.2 environment.
     *
     * @since 1.3
     */
    public java.lang.String calculateCharacterEncoding(FacesContext context)
    {
        try
        {
            Object ret = CALC_CHAR_ENC_METHOD.invoke(original, new Object[] {context});
            return (String) ret;
        }
        catch(Exception e)
        {
            throw new OrchestraException("Unable to invoke calculateCharacterEncoding on wrapped ViewHandler");
        }
    }

    /**
     * Delegate to wrapped instance.
     * <p>
     * This method was added in JSF1.2. We must therefore use reflection
     * to invoke the method on the wrapped instance. Note that this method
     * is never invoked unless this is a JSF1.2 environment.
     *
     * @since 1.3
     */
    public void initView(FacesContext context)
    throws FacesException
    {
        try
        {
            INIT_VIEW_METHOD.invoke(original, new Object[] {context});
        }
        catch(Exception e)
        {
            throw new OrchestraException("Unable to invoke initView on wrapped ViewHandler");
        }
    }

    public Locale calculateLocale(FacesContext context)
    {
        return original.calculateLocale(context);
    }

    public String calculateRenderKitId(FacesContext context)
    {
        return original.calculateRenderKitId(context);
    }

    public UIViewRoot createView(FacesContext context, String viewId)
    {
        return original.createView(context, viewId);
    }

    public String getActionURL(FacesContext context, String viewId)
    {
        if (viewId != null)
        {
            // Expand any EL expression in the URL.
            //
            // This handles a call from a NavigationHandler which is processing a redirect
            // navigation case. A NavigationHandler must call the following in order:
            //  * ViewHandler.getActionURL,
            //  * ExternalContext.encodeActionURL
            //  * ExternalContext.redirect
            //
            // Orchestra hooks into ExternalContext.encodeActionURL to trigger the
            // RequestParameterProviderManager which then inserts various query params
            // into the URL.
            //
            // So here, ensure that any EL expressions are expanded before the
            // RequestParameterProviderManager is invoked. An alternative would be for
            // the RequestParameterProviderManager to do the encoding, but at the current
            // time that class is not JSF-dependent in any way, so calling JSF expression
            // expansion from there is not possible.
            //
            // Note that this method is also called from a Form component when rendering
            // its 'action' attribute. This code therefore has the side-effect of
            // permitting EL expressions in a form's action. This is not particularly
            // useful, however, as they are expected to have been expanded before this
            // method is invoked..
            viewId = expandExpressions(context, viewId);

            // Hide query parameters from the standard ViewHandlerImpl. The standard
            // implementation of ViewHandlerImpl.getActionUrl method does not handle
            // query params well. So strip them off, invoke the processing, then reattach
            // them afterwards.
            int pos = viewId.indexOf('?');
            if (pos > -1)
            {
                String realViewId = viewId.substring(0, pos);
                String params = viewId.substring(pos);

                return original.getActionURL(context, realViewId) + params;
            }
        }
        return original.getActionURL(context, viewId);
    }

    public String getResourceURL(FacesContext context, String path)
    {
        return original.getResourceURL(context, path);
    }

    public void renderView(FacesContext context, UIViewRoot viewToRender)
        throws IOException, FacesException
    {
        original.renderView(context, viewToRender);
    }

    public UIViewRoot restoreView(FacesContext context, String viewId)
    {
        return original.restoreView(context, viewId);
    }

    public void writeState(FacesContext context)
        throws IOException
    {
        original.writeState(context);
    }

    private static String expandExpressions(FacesContext context, String url)
    {
        int pos = url.indexOf("#{");
        if (pos > -1 && url.indexOf("}", pos) > -1)
        {
            // There is at least one EL expression, so evaluate the whole url string.
            // Note that something like "aaa#{foo}bbb#{bar}ccc" is fine; both the
            // el expressions will get replaced.
            ValueBinding vb = context.getApplication().createValueBinding(url);
            return (String) vb.getValue(context);
        }

        return url;
    }
}
TOP

Related Classes of org.apache.myfaces.orchestra.urlParamNav.UrlParameterViewHandler

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.