com.icesoft.faces.webapp.parser.ImplementationUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.icesoft.faces.webapp.parser.ImplementationUtil.java

Source

/*
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * "The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * The Original Code is ICEfaces 1.5 open source software code, released
 * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
 * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
 * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
 *
 * Contributor(s): _____________________.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
 * License), in which case the provisions of the LGPL License are
 * applicable instead of those above. If you wish to allow use of your
 * version of this file only under the terms of the LGPL License and not to
 * allow others to use your version of this file under the MPL, indicate
 * your decision by deleting the provisions above and replace them with
 * the notice and other provisions required by the LGPL License. If you do
 * not delete the provisions above, a recipient may use your version of
 * this file under either the MPL or the LGPL License."
 *
 */

package com.icesoft.faces.webapp.parser;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.faces.FacesException;
import javax.faces.context.FacesContext;
import javax.servlet.jsp.PageContext;
import java.util.List;

/**
 * For ICEfaces to support JSF-RI, MyFaces, or any other future JSF
 * implementations, it may require some logic specific to the implementation.
 * Obviously this is not a good thing but it may be unavoidable if we need to
 * access something under the hood that isn't available through public API
 * calls.  This class is available to encapsulate implementation specific
 * anomalies.
 */
public class ImplementationUtil {

    /**
     * Logging instance for this class.
     */
    protected static Log log = LogFactory.getLog(ImplementationUtil.class);

    /**
     * Boolean values to track which implementation we are running under.
     */
    private static boolean isRI = false;
    private static boolean isMyFaces = false;
    private static boolean isJSF12 = false;
    private static boolean isJSF2 = false;
    private static boolean jsfStateSaving;

    /**
     * Whether stock JSF components' set attributes are tracked.
     * @see #isAttributeTracking
     */
    private static boolean isStockAttributeTracking = false;
    /**
     * Whether 3rd party components' set attributes are tracked.
     * @see #isAttributeTracking
     */
    private static boolean isAnyAttributeTracking = false;

    /**
     * Marker classes whose presence we used to detect which implementation we
     * are running under.
     */
    private static String RI_MARKER = "com.sun.faces.application.ApplicationImpl";
    private static String MYFACES_MARKER = "org.apache.myfaces.application.ApplicationImpl";
    private static String JSF12_MARKER = "javax.faces.webapp.UIComponentELTag";
    private static String JSF2_MARKER = "javax.faces.context.PartialViewContext";

    /**
     * In a couple of places, we need to access the component stack from the
     * PageContext and the key used to do this is implemenation dependent.  So
     * here is where we track the keys and provide appropriate value depending
     * on the implementation we are running under.
     */
    private static String RI_COMPONENT_STACK_KEY = "javax.faces.webapp.COMPONENT_TAG_STACK";

    private static String MYFACES_COMPONENT_STACK_KEY = "javax.faces.webapp.UIComponentTag.COMPONENT_STACK";

    static {
        try {
            Class.forName(RI_MARKER);
            isRI = true;
        } catch (ClassNotFoundException e) {
        }

        //Test for JSF 1.2
        try {
            Class.forName(JSF12_MARKER);
            isJSF12 = true;
        } catch (Throwable t) {
        }

        if (log.isTraceEnabled()) {
            log.trace("JSF-12: " + isJSF12);
        }

        //Test for JSF 2
        try {
            Class.forName(JSF2_MARKER);
            isJSF2 = true;
        } catch (Throwable t) {
        }

        if (log.isTraceEnabled()) {
            log.trace("JSF-2: " + isJSF2);
        }

        try {
            Class.forName(MYFACES_MARKER);
            isMyFaces = true;
            //Disable JSF12 detection in MyFaces environment
            isJSF12 = false;
        } catch (ClassNotFoundException e) {
        }

        if (log.isTraceEnabled()) {
            log.trace("JSF-RI: " + isRI + "  MyFaces: " + isMyFaces);
        }

        try {
            javax.faces.component.html.HtmlOutputText comp = new javax.faces.component.html.HtmlOutputText();
            isStockAttributeTracking = isAttributeTracking(comp);

            comp = (javax.faces.component.html.HtmlOutputText) Class
                    .forName("com.icesoft.faces.component.ext.HtmlOutputText").newInstance();
            //TODO List seting will happen in our component constructors, not in this test
            //comp.getAttributes().put(
            //    "javax.faces.component.UIComponentBase.attributesThatAreSet",
            //    new java.util.ArrayList(6));
            isAnyAttributeTracking = isAttributeTracking(comp);
        } catch (Throwable t) {
        }
    }

    /**
     * For stock JSF components, all setting of attributes, whether by setter 
     * methods, or by puts on the the attribute map (which can delegate to 
     * setter methods), result in List UIComponent.attributesThatAreSet, aka 
     * UIComponentBase.getAttributes().get(
     *     "javax.faces.component.UIComponentBase.attributesThatAreSet")
     * containing that attribute name, as of JSF RI 1.2_05. This optimisation 
     * is disabled for components not in javax.faces.component.* packages, 
     * even if the component extend the stock ones. Meaning that the stock 
     * attributes become decellerated in third party components. It's possible 
     * to create the attributesThatAreSet List for 3rd party components, and 
     * have it track attribute maps puts for attributes that do not have 
     * setter methods. But setter method tracking is only enabled as of 
     * //TODO// JSF RI 1.2_xx, so we need to ascertain that separately, for ICEfaces 
     * extended and custom component rendering.
     * 
     * @param comp An arbitrary component whose attributes are known 
     * @return If the JSF implementation tracks this component's set attributes
     */
    private static boolean isAttributeTracking(javax.faces.component.html.HtmlOutputText comp) {
        boolean tracked = false;
        comp.setTitle("value");
        comp.getAttributes().put("lang", "value");
        comp.getAttributes().put("no_method", "value");
        List attributesThatAreSet = (List) comp.getAttributes()
                .get("javax.faces.component.UIComponentBase.attributesThatAreSet");
        //System.out.println(comp.getClass().getName() + " :: attributesThatAreSet: " + attributesThatAreSet);
        if (attributesThatAreSet != null && attributesThatAreSet.contains("title")
                && attributesThatAreSet.contains("lang") && attributesThatAreSet.contains("no_method")) {
            //System.out.println(comp.getClass().getName() + " :: attributesThatAreSet ENABLED");
            tracked = true;
        }
        return tracked;
    }

    /**
     * Identifies if the JSF implementation we are running in is Sun's JSF
     * reference implemenation (RI).
     *
     * @return true if the JSF implementation is Sun's JSF reference
     *         implemenation
     */
    public static boolean isRI() {
        return isRI;
    }

    /**
     * Identifies if the JSF implementation we are running in is Apache's
     * MyFaces implementation.
     *
     * @return true if the JSF implementation is Apache MyFaces.
     */
    public static boolean isMyFaces() {
        return isMyFaces;
    }

    /**
     * Identifies if the JSF implementation we are running in is JSF 1.2
     *
     * @return true if the JSF implementation is JSF 1.2
     */
    public static boolean isJSF12() {
        return isJSF12;
    }

    /**
     * Identifies if the JSF implementation we are running in is JSF 2.x
     *
     * @return true if the JSF implementation is JSF 2.x
     */
    public static boolean isJSF2() {
        return isJSF2;
    }

    /**
     * @return Whether stock JSF components' set attributes are tracked.
     * @see #isAttributeTracking
     */
    public static boolean isStockAttributeTracking() {
        return isStockAttributeTracking;
    }

    /**
     * @return Whether 3rd party components' set attributes are tracked.
     * @see #isAttributeTracking
     */
    public static boolean isAnyAttributeTracking() {
        return isAnyAttributeTracking;
    }

    /**
     * Returns the key used to get the component stack from the PageContext. The
     * key is a private member of UIComponentTag class but differs between the
     * known JSF implementations.  We detect the correct implementation in this
     * class and provide the proper key.
     *
     * @return String
     */
    public static String getComponentStackKey() {
        String key = null;
        if (isRI) {
            key = RI_COMPONENT_STACK_KEY;
        } else if (isMyFaces) {
            key = MYFACES_COMPONENT_STACK_KEY;
        }

        if (key != null) {
            return key;
        }

        if (log.isFatalEnabled()) {
            log.fatal("cannot detect JSF implementation so cannot determine component stack key");
        }

        throw new UnknownJSFImplementationException("cannot determine component stack key");
    }

    /**
     * Returns the component tag stack, including checking in the current
     * request as is the strategy of JSF 1.1_02
     * @param pageContext
     * @return list being the component tag stack
     */
    public static List getComponentStack(PageContext pageContext) {
        List list = (List) pageContext.getAttribute(getComponentStackKey(), PageContext.REQUEST_SCOPE);
        if (null == list) {
            list = (List) FacesContext.getCurrentInstance().getExternalContext().getRequestMap()
                    .get(getComponentStackKey());
        }
        return list;

    }

    public static void setJSFStateSaving(boolean isJSFStateSaved) {
        jsfStateSaving = isJSFStateSaved;
    }

    public static boolean isJSFStateSaving() {
        return jsfStateSaving;
    }
}

class UnknownJSFImplementationException extends FacesException {

    public UnknownJSFImplementationException() {
    }

    public UnknownJSFImplementationException(Throwable cause) {
        super(cause);
    }

    public UnknownJSFImplementationException(String message) {
        super(message);
    }

    public UnknownJSFImplementationException(String message, Throwable cause) {
        super(message, cause);
    }

}