Package com.sun.faces.facelets.tag.jsf

Source Code of com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* 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 com.sun.faces.facelets.tag.jsf;

import com.sun.faces.facelets.Facelet;
import com.sun.faces.facelets.FaceletFactory;
import com.sun.faces.facelets.util.ReflectionUtil;
import com.sun.faces.facelets.el.VariableMapperWrapper;
import com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.CreateComponentDelegate;
import com.sun.faces.facelets.tag.MetaRulesetImpl;
import com.sun.faces.facelets.tag.MetadataTargetImpl;
import com.sun.faces.util.RequestStateManager;
import com.sun.faces.util.Util;

import javax.el.ELException;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import javax.el.ELContext;
import javax.faces.FacesException;
import javax.faces.application.Resource;
import javax.faces.application.ProjectStage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIPanel;
import javax.faces.component.ActionSource;
import javax.faces.component.ValueHolder;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UISelectOne;
import javax.faces.component.UISelectMany;
import javax.faces.context.FacesContext;
import javax.faces.view.AttachedObjectHandler;
import javax.faces.view.facelets.ComponentConfig;
import javax.faces.view.facelets.ComponentHandler;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.MetaRuleset;
import javax.faces.view.facelets.Metadata;
import javax.faces.view.facelets.MetadataTarget;
import javax.faces.view.facelets.Tag;
import javax.faces.view.facelets.TagAttribute;
import javax.faces.view.facelets.MetaRule;
import java.beans.PropertyDescriptor;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import javax.faces.FactoryFinder;
import javax.faces.view.ViewDeclarationLanguage;
import javax.faces.view.ViewDeclarationLanguageFactory;

/**
* <p>
* Facelet handler responsible for, building the component tree representation
* of a composite component based on the metadata contained in the composite
* interface and implementation sections of the composite component template.
* </p>
*/
public class CompositeComponentTagHandler extends ComponentHandler implements CreateComponentDelegate {

   
    CompositeComponentTagHandler(Resource ccResource, ComponentConfig config) {
        super(config);
        this.ccResource = ccResource;
        ((ComponentTagHandlerDelegateImpl)this.getTagHandlerDelegate()).setCreateCompositeComponentDelegate(this);
    }


    private Resource ccResource;
    private UIComponent cc;
   


    public UIComponent createComponent(FaceletContext ctx) {
        FacesContext context = ctx.getFacesContext();
        UIComponent result = context.getApplication().createComponent(context, ccResource);
        this.cc = result;
        return result;
    }
   
    @Override
    public void applyNextHandler(FaceletContext ctx, UIComponent c) throws IOException, FacesException, ELException {
        // Allow any nested elements that reside inside the markup element
        // for this tag to get applied
        super.applyNextHandler(ctx, c);

        // Apply the facelet for this composite component
        applyCompositeComponent(ctx, c);

        // Allow any PDL declared attached objects to be retargeted
        if (ComponentHandler.isNew(c)) {
            FacesContext context = ctx.getFacesContext();
            String viewId = context.getViewRoot().getViewId();
            // PENDING(rlubke): performance
            ViewDeclarationLanguageFactory factory = (ViewDeclarationLanguageFactory)
                    FactoryFinder.getFactory(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);

            ViewDeclarationLanguage vdl = factory.getViewDeclarationLanguage(viewId);
            vdl.retargetAttachedObjects(context, c,
                    getAttachedObjectHandlers(c, false));
            vdl.retargetMethodExpressions(context, c);

            // RELEASE_PENDING This is *ugly*.  See my comments in
            // ComponentTagHandlerDelegateImpl at the end of the apply()
            // method
            if (Boolean.TRUE.equals(ctx.getFacesContext().getAttributes().get("partialStateSaving"))) {
                markInitialState(c);
            }


        }

    }

   
    private void applyCompositeComponent(FaceletContext ctx, UIComponent c)
    throws IOException {

        FacesContext facesContext = ctx.getFacesContext();
        FaceletFactory factory = (FaceletFactory)
              RequestStateManager.get(facesContext, RequestStateManager.FACELET_FACTORY);
        VariableMapper orig = ctx.getVariableMapper();
       
        UIPanel facetComponent;
        if (ComponentHandler.isNew(c)) {
            facetComponent = (UIPanel)
            facesContext.getApplication().createComponent("javax.faces.Panel");
            facetComponent.setRendererType("javax.faces.Group");
            c.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, facetComponent);
        }                                                                                
        else {
            facetComponent = (UIPanel)
                    c.getFacets().get(UIComponent.COMPOSITE_FACET_NAME);
        }
        assert(null != facetComponent);
       
        try {
            Facelet f = factory.getFacelet(ccResource.getURL());
            setAttributes(ctx, c);
            VariableMapper wrapper = new VariableMapperWrapper(orig) {

                @Override
                public ValueExpression resolveVariable(String variable) {
                    return super.resolveVariable(variable);
                }
               
            };
            ctx.setVariableMapper(wrapper);
            f.apply(facesContext, facetComponent);
        } finally {
            ctx.setVariableMapper(orig);
        }

    }


    /**
     * Specialized implementation to prevent caching of the MetaRuleset when
     * ProjectStage is Development.
     */
    @Override
    public void setAttributes(FaceletContext ctx, Object instance) {

        if (instance != null) {
            if (ctx.getFacesContext().isProjectStage(ProjectStage.Development)) {
                Metadata meta = createMetaRuleset(instance.getClass()).finish();
                meta.applyMetadata(ctx, instance);
            } else {
                super.setAttributes(ctx, instance);
            }
        }

    }


    /**
     * This is basically a copy of what's define in ComponentTagHandlerDelegateImpl
     * except for the MetaRuleset implementation that's being used.
     *
     * This also allows us to treat composite component's backed by custom component
     * implementation classes based on their type.
     *
     * @param type the <code>Class</code> for which the
     * <code>MetaRuleset</code> must be created.
     *
     */
    @Override
    protected MetaRuleset createMetaRuleset(Class type) {

        Util.notNull("type", type);
        MetaRuleset m = new CompositeComponentMetaRuleset(getTag(), type, (BeanInfo) cc.getAttributes().get(UIComponent.BEANINFO_KEY));

        // ignore standard component attributes
        m.ignore("binding").ignore("id");

        m.addRule(CompositeComponentRule.Instance);

        // if it's an ActionSource
        if (ActionSource.class.isAssignableFrom(type)) {
            m.addRule(ActionSourceRule.Instance);
        }

        // if it's a ValueHolder
        if (ValueHolder.class.isAssignableFrom(type)) {
            m.addRule(ValueHolderRule.Instance);

            // if it's an EditableValueHolder
            if (EditableValueHolder.class.isAssignableFrom(type)) {
                m.ignore("submittedValue");
                m.ignore("valid");
                m.addRule(EditableValueHolderRule.Instance);
            }
        }

        // if it's a selectone or selectmany
        if (UISelectOne.class.isAssignableFrom(type) || UISelectMany.class.isAssignableFrom(type)) {
            m.addRule(RenderPropertyRule.Instance);
        }

        return m;

    }

    public static List<AttachedObjectHandler> getAttachedObjectHandlers(UIComponent component) {
        return getAttachedObjectHandlers(component, true);
    }
   
    @SuppressWarnings({"unchecked"})
    public static List<AttachedObjectHandler> getAttachedObjectHandlers(UIComponent component,
            boolean create) {
        Map<String, Object> attrs = component.getAttributes();
        List<AttachedObjectHandler> result = (List<AttachedObjectHandler>)
                attrs.get("javax.faces.RetargetableHandlers");
       
        if (null == result) {
            if (create) {
                result = new ArrayList<AttachedObjectHandler>();
                attrs.put("javax.faces.RetargetableHandlers", result);
            }
            else {
                result = Collections.EMPTY_LIST;
            }
        }
        return result;
    }



    private void markInitialState(UIComponent c) {
        c.markInitialState();
        for (Iterator<UIComponent> i = c.getFacetsAndChildren(); i.hasNext(); ) {
            markInitialState(i.next());
        }
    }


    // ---------------------------------------------------------- Nested Classes


    /**
     * Specialized MetaRulesetImpl to return CompositeMetadataTarget for component
     * attribute handling.
     */
    private static final class CompositeComponentMetaRuleset extends MetaRulesetImpl {

        private BeanInfo compBeanInfo;
        private Class<?> type;

        public CompositeComponentMetaRuleset(Tag tag,
                                             Class<?> type,
                                             BeanInfo compBeanInfo) {

            super(tag, type);
            this.compBeanInfo = compBeanInfo;
            this.type = type;

        }

        @Override
        protected MetadataTarget getMetadataTarget() {
            try {
                return new CompositeMetadataTarget(type, compBeanInfo);
            } catch (IntrospectionException ie) {
                throw new FacesException(ie);
            }
        }


        // ------------------------------------------------------ Nested Classes


        /**
         * This class is responsible for creating ValueExpression instances with
         * the expected type based off the following:
         *
         *  - if the composite:attribute metadata is present, then use the type
         *    if specified by the author, or default to Object.class
         *  - if no composite:attribute is specified, then attempt to return the
         *    type based off the bean info for this component
         */
        private static final class CompositeMetadataTarget extends MetadataTargetImpl {

            private BeanInfo compBeanInfo;


            // ---------------------------------------------------- Construcrors


            public CompositeMetadataTarget(Class<?> type, BeanInfo compBeanInfo)
            throws IntrospectionException {

                super(type);
                this.compBeanInfo = compBeanInfo;

            }


            // --------------------------------- Methods from MetadataTargetImpl


            @Override
            public Class getPropertyType(String name) {
                PropertyDescriptor compDescriptor = findDescriptor(name);
                if (compDescriptor != null) {
                    // composite:attribute declaration...
                    ValueExpression typeVE = (ValueExpression) compDescriptor.getValue("type");
                    if (typeVE == null) {
                        return Object.class;
                    } else {
                        String className = (String) typeVE.getValue(FacesContext.getCurrentInstance().getELContext());
                        if (className != null) {
                            className = prefix(className);
                            try {
                                return ReflectionUtil.forName(className);
                            } catch (ClassNotFoundException cnfe) {
                                throw new FacesException(cnfe);
                            }
                        } else {
                            return Object.class;
                        }
                    }
                } else {
                    // defer to the default processing which will inspect the
                    // PropertyDescriptor of the UIComponent type
                    return super.getPropertyType(name);
                }
            }


            // ------------------------------------------------- Private Methods


            private PropertyDescriptor findDescriptor(String name) {

                for (PropertyDescriptor pd : compBeanInfo.getPropertyDescriptors()) {

                    if (pd.getName().equals(name)) {
                        return pd;
                    }

                }
                return null;

            }


            private String prefix(String className) {

                if (className.indexOf('.') == -1
                    && Character.isUpperCase(className.charAt(0))) {
                    return ("java.lang." + className);
                } else {
                    return className;
                }

            }
        }

    } // END CompositeComponentMetaRuleset


    /**
     * <code>MetaRule</code> for populating the ValueExpression map of a
     * composite component.
     */
    private static class CompositeComponentRule extends MetaRule {

        private static final CompositeComponentRule Instance = new CompositeComponentRule();


        // ------------------------------------------ Methods from ComponentRule


        public Metadata applyRule(String name, TagAttribute attribute, MetadataTarget meta) {

            if (meta.isTargetInstanceOf(UIComponent.class)) {
                Class type = meta.getPropertyType(name);
                if (type == null) {
                    type = Object.class;
                }

                if (!attribute.isLiteral()) {
                    return new CompositeExpressionMetadata(name, type, attribute);
                } else {
                    return new LiteralAttributeMetadata(name, type, attribute);
                }
            }
            return null;

        }


        // ------------------------------------------------------ Nested Classes


        /**
         * For literal expressions, coerce the literal value to the type
         * as provided to the constructor prior to setting the value into
         * the component's attribute map.
         */
        private static final class LiteralAttributeMetadata extends Metadata {

            private String name;
            private Class<?> type;
            private TagAttribute attribute;


            // ---------------------------------------------------- Constructors


            public LiteralAttributeMetadata(String name,
                                            Class<?> type,
                                            TagAttribute attribute) {

                this.name = name;
                this.type = type;
                this.attribute = attribute;
               
            }


            // ------------------------------------------- Methods from Metadata


            public void applyMetadata(FaceletContext ctx, Object instance) {

                UIComponent c = (UIComponent) instance;
                c.getAttributes().put(name, attribute.getObject(ctx, type));

            }

        } // END LiteralAttributeMetadata


        /**
         * CompositeExpressionMetadata sets up specialized wrapper ValueExpression
         * instances around the source ValueExpression that, when evaluated,
         * will cause the parent composite component of the currently available
         * composite component to be pushed onto a stack that the
         * ImplicitObjectELResolver will check for.
         */
        private static final class CompositeExpressionMetadata extends Metadata {

            private String name;
            private Class<?> type;
            private TagAttribute attr;


            // ---------------------------------------------------- Constructors


            public CompositeExpressionMetadata(String name,
                                               Class<?> type,
                                               TagAttribute attr) {
                this.name = name;
                this.type = type;
                this.attr = attr;


            }

            // ------------------------------------------- Methods from Metadata


            public void applyMetadata(FaceletContext ctx, Object instance) {

                ValueExpression ve = attr.getValueExpression(ctx, type);
                UIComponent cc = (UIComponent) instance;
                assert (UIComponent.isCompositeComponent(cc));
                cc.setValueExpression(name, new ContextualCompositeExpression(ve));

            }


        } // END CompositeExpressionMetadata


        private static final class ContextualCompositeExpression extends ValueExpression {

            private ValueExpression originalVE;
      

            // ---------------------------------------------------- Constructors


            /* For serialization purposes */
            public ContextualCompositeExpression() { }


            public ContextualCompositeExpression(ValueExpression originalVE) {

                this.originalVE = originalVE;

            }


            // ------------------------------------ Methods from ValueExpression


            public Object getValue(ELContext elContext) {

                FacesContext ctx = (FacesContext) elContext.getContext(FacesContext.class);
                boolean pushed = pushCompositeComponent(ctx);
                try {
                    return originalVE.getValue(elContext);
                } finally {
                    if (pushed) {
                        popCompositeComponent(ctx);
                    }
                }

            }

            public void setValue(ELContext elContext, Object o) {

                FacesContext ctx = (FacesContext) elContext.getContext(FacesContext.class);
                 boolean pushed = pushCompositeComponent(ctx);
                try {
                    originalVE.setValue(elContext, o);
                } finally {
                    if (pushed) {
                        popCompositeComponent(ctx);
                    }
                }

            }

            public boolean isReadOnly(ELContext elContext) {

                FacesContext ctx = (FacesContext) elContext.getContext(FacesContext.class);
                boolean pushed = pushCompositeComponent(ctx);
                try {
                    return originalVE.isReadOnly(elContext);
                } finally {
                    if (pushed) {
                        popCompositeComponent(ctx);
                    }
                }

            }

            public Class<?> getType(ELContext elContext) {

                FacesContext ctx = (FacesContext) elContext.getContext(FacesContext.class);
                boolean pushed = pushCompositeComponent(ctx);
                try {
                    return originalVE.getType(elContext);
                } finally {
                    if (pushed) {
                        popCompositeComponent(ctx);
                    }
                }

            }

            public Class<?> getExpectedType() {
               
                FacesContext ctx = FacesContext.getCurrentInstance();
                boolean pushed = pushCompositeComponent(ctx);
                try {
                    return originalVE.getExpectedType();
                } finally {
                    if (pushed) {
                        popCompositeComponent(ctx);
                    }
                }

            }


            // ----------------------------------------- Methods from Expression


            public String getExpressionString() {
                return originalVE.getExpressionString();
            }

            @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"})
            public boolean equals(Object o) {
                return originalVE.equals(o);
            }

            public int hashCode() {
                return originalVE.hashCode();
            }

            public boolean isLiteralText() {
                return originalVE.isLiteralText();
            }


            // ------------------------------------------------- Private Methods


            private boolean pushCompositeComponent(FacesContext ctx) {

                Stack<UIComponent> tstack = getTreeCreationStack(ctx);
                Stack<UIComponent> stack = getStack(ctx, false);
                UIComponent ccp = null;
                if (tstack != null) {
                    // We have access to the stack of composite components
                    // the tree creation process has made available.
                    // Since we can' reliably access the parent composite component
                    // of the current composite component, use the index of the
                    // current composite component within the stack to locate the
                    // parent.
                    UIComponent currentComp;
                    if (stack == null || stack.isEmpty()) {
                        currentComp = UIComponent.getCurrentComponent(ctx);
                    } else {
                        currentComp = stack.peek();

                    }
                    if (currentComp != null) {
                        int idx = tstack.indexOf(currentComp);
                        if (idx > 0) {
                            ccp = tstack.get(idx - 1);
                        }
                    }
                } else {
                    // no tree creation stack available, so use the runtime stack.
                    // If the current stack isn't empty, then use the component
                    // on the stack as the current composite component.
                    stack = getStack(ctx, false);
                    if (stack != null && !stack.isEmpty()) {
                        ccp = UIComponent.getCompositeComponentParent(stack.peek());
                    } else {
                        ccp = UIComponent.getCompositeComponentParent(UIComponent.getCurrentCompositeComponent(ctx));
                    }
                }

                if (ccp != null) {
                    if (stack == null) {
                        stack = getStack(ctx, true);
                    }
                    stack.push(ccp);
                    return true;
                }
                return false;

            }


            private void popCompositeComponent(FacesContext ctx) {

                Stack<UIComponent> stack = getStack(ctx, false);
                if (stack == null) {
                    return;
                }
                if (!stack.isEmpty()) {
                    stack.pop();
                }

            }


            @SuppressWarnings({"unchecked"})
            private Stack<UIComponent> getStack(FacesContext ctx, boolean create) {

                Stack<UIComponent> stack = (Stack<UIComponent>)
                      RequestStateManager.get(ctx, RequestStateManager.COMPCOMP_STACK);
                if (stack == null && create) {
                    stack = new Stack<UIComponent>();
                    RequestStateManager.set(ctx, RequestStateManager.COMPCOMP_STACK, stack);
                }
                return stack;

            }


            @SuppressWarnings({"unchecked"})
            private Stack<UIComponent> getTreeCreationStack(FacesContext ctx) {

                return (Stack<UIComponent>)
                      RequestStateManager.get(ctx, RequestStateManager.COMPCOMP_STACK_TREE_CREATION);

            }


        } // END ContextualCompositeExpression

    } // END CompositeComponentRule
   
   
}
TOP

Related Classes of com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler

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.