Package com.sun.faces.application

Source Code of com.sun.faces.application.ValidateComponentNesting

package com.sun.faces.application;

import java.util.EnumSet;

import javax.faces.application.FacesMessage;
import javax.faces.application.ProjectStage;
import javax.faces.component.ActionSource;
import javax.faces.component.ActionSource2;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.component.UIViewAction;
import javax.faces.component.UIViewParameter;
import javax.faces.component.UIViewRoot;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitHint;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;


import com.sun.faces.util.MessageUtils;

/**
* <p>ValidateFormComponentNesting performs component tree validation to assure {@link ActionSource}
* , {@link ActionSource2} and {@link EditableValueHolder} components are placed inside a form.
* ValidateFormComponentNesting is installed automatically if {@link ProjectStage#Development} is
* active. </p>
*
* @author dueni
*
*/
public class ValidateComponentNesting implements SystemEventListener {

    @Override
    public boolean isListenerForSource(Object source) {
        return (source instanceof UIViewRoot);
    }

    /**
     * Process PostAddToViewEvent on UIViewRoot to validate form - action/input nesting.
     */
    @Override
    public void processEvent(SystemEvent event) throws AbortProcessingException {
        UIComponent root = (UIComponent) event.getSource();
        FacesContext jsf = FacesContext.getCurrentInstance();
        EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_ITERATION);
        VisitContext visitContext = VisitContext.createVisitContext(jsf, null, hints);

        root.visitTree(visitContext, new ValidateFormNestingCallback());
    }

    static class ValidateFormNestingCallback implements VisitCallback {

        // report missing form problem only once
        boolean reportedOmittedFormOnce = false;

        // report missing metadata problem only once
        boolean reportedOmittedMetadataOnce = false;

        @Override
        public VisitResult visit(VisitContext context, UIComponent target) {
            // default result: continue tree walk
            VisitResult result = VisitResult.ACCEPT;

            if (target instanceof UIForm || target.getFamily().endsWith("Form")
                            || UIViewRoot.METADATA_FACET_NAME.equals(target.getId())) {
                // stop tree walk if component is of type UIForm or component family ends on "Form"
                // or if the component is the UIPanel with id METADATA_FACET_NAME
                result = VisitResult.REJECT;
            } else if (target instanceof UIViewParameter || target instanceof UIViewAction) {
                if (reportedOmittedMetadataOnce) {
                    // report first detected problem only, then stop tree walk
                    result = VisitResult.COMPLETE;
                }
                addOmittedMessage(context.getFacesContext(), target.getClientId(context
                                .getFacesContext()), MessageUtils.MISSING_METADATA_ERROR);
                reportedOmittedMetadataOnce = true;

            } else if (target instanceof EditableValueHolder || target instanceof ActionSource
                            || target instanceof ActionSource2) {
                if (reportedOmittedFormOnce) {
                    // report first detected problem only, then stop tree walk
                    result = VisitResult.COMPLETE;
                }
                // if we find ActionSource, ActionSource2 or EditableValueHolder, that component
                // must be outside of a form add warning message
                addOmittedMessage(context.getFacesContext(), target.getClientId(context
                                .getFacesContext()), MessageUtils.MISSING_FORM_ERROR);
                reportedOmittedFormOnce = true;

            }
            return result;
        }
    }

    /**
     * method for adding a message regarding missing ancestor to context
     *
     * @param ctx
     * @param clientId
     */
    private static void addOmittedMessage(FacesContext jsf, String clientId, String key) {
        Object[] params = new Object[] {};

        FacesMessage m = MessageUtils.getExceptionMessage(key, params);
        m.setSeverity(FacesMessage.SEVERITY_WARN);
        jsf.addMessage(clientId, m);
    }

}
TOP

Related Classes of com.sun.faces.application.ValidateComponentNesting

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.