Package com.sun.faces.config.processor

Source Code of com.sun.faces.config.processor.FacesFlowDefinitionConfigProcessor$FlowDefinitionDocument

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. 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_1_1.html
* or packager/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 packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [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.

*/
package com.sun.faces.config.processor;

import com.sun.faces.RIConstants;
import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.config.DocumentInfo;
import com.sun.faces.config.WebConfiguration;
import com.sun.faces.facelets.util.ReflectionUtil;
import com.sun.faces.flow.FlowImpl;
import com.sun.faces.flow.ParameterImpl;
import com.sun.faces.flow.builder.FlowBuilderImpl;
import com.sun.faces.util.FacesLogger;
import com.sun.faces.util.Util;
import java.net.MalformedURLException;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.PostConstructApplicationEvent;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;
import javax.faces.flow.FlowHandler;
import javax.faces.flow.FlowHandlerFactory;
import javax.faces.flow.FlowNode;
import javax.faces.flow.Parameter;
import javax.faces.flow.builder.FlowBuilder;
import javax.faces.flow.builder.FlowCallBuilder;
import javax.faces.flow.builder.MethodCallBuilder;
import javax.faces.flow.builder.NavigationCaseBuilder;
import javax.faces.flow.builder.SwitchBuilder;
import javax.servlet.ServletContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
* <p>
*  This <code>ConfigProcessor</code> handles all elements defined under
<code>/faces-config/flow-definition</code>.
* </p>
*/
public class FacesFlowDefinitionConfigProcessor extends AbstractConfigProcessor {

    private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();
       
    /**
     * <code>/faces-config/flow-definition</code>
     */
    private static final String FACES_FLOW_DEFINITION = "flow-definition";
   
    public FacesFlowDefinitionConfigProcessor() {
    }
   
    public static boolean uriIsFlowDefinition(URI uri) {
        boolean result = false;
        String path = uri.getPath();
        String [] segments = path.split("/");
        if (1 < segments.length) {
            String flowName = segments[segments.length-2];
            String definingName = segments[segments.length-1];
            result = definingName.equals(flowName + "-flow.xml");
        }
       
        return result;
    }
   
    /*
     * Implement the requirements of 11.4.3.3
     *
     * @param uri
     * @param toPopulate
     * @return
     */
    public static Document synthesizeEmptyFlowDefinition(URI uri) throws ParserConfigurationException {
        Document newDoc = null;

        String path = uri.getPath();
        String [] segments = path.split("/");
        if (segments.length < 2) {
            return newDoc;
        }
        String flowName = segments[segments.length-2];
       
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder builder = dbf.newDocumentBuilder();
        DOMImplementation domImpl = builder.getDOMImplementation();
        newDoc = domImpl.createDocument(RIConstants.JAVAEE_XMLNS, "faces-config", null);
        Node documentElement = newDoc.getDocumentElement();
        Attr versionAttribute = newDoc.createAttribute("version");
        versionAttribute.setValue("2.2");
        documentElement.getAttributes().setNamedItem(versionAttribute);
       
        Node facesConfig = newDoc.getFirstChild();
       
        Element flowDefinition = newDoc.createElementNS(RIConstants.JAVAEE_XMLNS, "flow-definition");
        flowDefinition.setAttribute("id", flowName);
        facesConfig.appendChild(flowDefinition);
        final String flowReturnStr = flowName + "-return";
       
        Element flowReturn = newDoc.createElementNS(RIConstants.JAVAEE_XMLNS, "flow-return");
        flowReturn.setAttribute("id", flowReturnStr);
        flowDefinition.appendChild(flowReturn);
       
        Element fromOutcome = newDoc.createElementNS(RIConstants.JAVAEE_XMLNS, "from-outcome");
        flowReturn.appendChild(fromOutcome);
        fromOutcome.setTextContent("/" + flowReturnStr);
       
        return newDoc;
    }
   

    @Override
    public void process(ServletContext sc, DocumentInfo[] documentInfos)
    throws Exception {

        WebConfiguration config = WebConfiguration.getInstance(sc);
        FacesContext context = FacesContext.getCurrentInstance();
       
        for (int i = 0; i < documentInfos.length; i++) {
            URI definingDocumentURI = documentInfos[i].getSourceURI();
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE,
                           MessageFormat.format(
                                "Processing factory elements for document: ''{0}''",
                                definingDocumentURI));
            }
            Document document = documentInfos[i].getDocument();
            String namespace = document.getDocumentElement()
                 .getNamespaceURI();
            NodeList flowDefinitions = document.getDocumentElement()
                 .getElementsByTagNameNS(namespace, FACES_FLOW_DEFINITION);
            if (flowDefinitions != null && flowDefinitions.getLength() > 0) {
                config.setHasFlows(true);
               
                saveFlowDefinition(context, definingDocumentURI, document);
            }
        }
       
        if (config.isHasFlows()) {
            String optionValue = config.getOptionValue(WebConfiguration.WebContextInitParameter.ClientWindowMode);
            boolean clientWindowNeedsEnabling = false;
            if ("none".equals(optionValue)) {
                clientWindowNeedsEnabling = true;
                String featureName =
                        WebConfiguration.WebContextInitParameter.ClientWindowMode.getQualifiedName();
                LOGGER.log(Level.WARNING,
                        "{0} was set to none, but Faces Flows requires {0} is enabled.  Setting to ''url''.", new Object[]{featureName});
            } else if (null == optionValue) {
                clientWindowNeedsEnabling = true;
            }
            if (clientWindowNeedsEnabling) {
                config.setOptionValue(WebConfiguration.WebContextInitParameter.ClientWindowMode, "url");
            }
           
            context.getApplication().subscribeToEvent(PostConstructApplicationEvent.class,
                    Application.class, new PerformDeferredFlowProcessing());
        }
       
        invokeNext(sc, documentInfos);
    }
   
    // <editor-fold defaultstate="collapsed" desc="Enable deferred processing of flow definitions">
   
    private static final String flowDefinitionListKey = RIConstants.FACES_PREFIX + "FacesFlowDefinitions";
   
    private void saveFlowDefinition(FacesContext context,
            URI definingDocumentURI,
            Document flowDefinitions) {
        Map<String, Object> appMap = context.getExternalContext().getApplicationMap();
        List<FlowDefinitionDocument> def = (List<FlowDefinitionDocument>) appMap.get(flowDefinitionListKey);
        if (null == def) {
            def = new ArrayList<FlowDefinitionDocument>();
            appMap.put(flowDefinitionListKey, def);
        }
        def.add(new FlowDefinitionDocument(definingDocumentURI, flowDefinitions));
    }
   
    private List<FlowDefinitionDocument> getSavedFlowDefinitions(FacesContext context) {
        Map<String, Object> appMap = context.getExternalContext().getApplicationMap();
        List<FlowDefinitionDocument> def = (List<FlowDefinitionDocument>) appMap.get(flowDefinitionListKey);
        return (null != def) ? def : Collections.EMPTY_LIST;
    }
   
    private void clearSavedFlowDefinitions(FacesContext context) {
        Map<String, Object> appMap = context.getExternalContext().getApplicationMap();
        List<FlowDefinitionDocument> def = (List<FlowDefinitionDocument>) appMap.get(flowDefinitionListKey);
        if (null != def) {
            for (FlowDefinitionDocument cur : def) {
                cur.clear();
            }
            def.clear();
            appMap.remove(flowDefinitionListKey);
        }
    }
   
    private static class FlowDefinitionDocument {
        URI definingDocumentURI;
        Document flowDefinitions;

        public FlowDefinitionDocument(URI definingDocumentURI,
                Document flowDefinitions) {
            this.definingDocumentURI = definingDocumentURI;
            this.flowDefinitions = flowDefinitions;
        }
       
        public void clear() {
            this.definingDocumentURI = null;
            this.flowDefinitions = null;
        }
       
    }
   
    private class PerformDeferredFlowProcessing implements SystemEventListener {

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

        @Override
        public void processEvent(SystemEvent event) throws AbortProcessingException {
            FacesContext context = FacesContext.getCurrentInstance();
            List<FlowDefinitionDocument> flowDefinitions =
                    FacesFlowDefinitionConfigProcessor.this.getSavedFlowDefinitions(context);
            for (FlowDefinitionDocument cur: flowDefinitions) {
                try {
                    FacesFlowDefinitionConfigProcessor.this.
                            processFacesFlowDefinitions(cur.definingDocumentURI, cur.flowDefinitions);
                } catch (XPathExpressionException ex) {
                    throw new FacesException(ex);
                }
            }
            FacesFlowDefinitionConfigProcessor.this.clearSavedFlowDefinitions(context);
        }
    }
   
    // </editor-fold>
   
    private void processFacesFlowDefinitions(URI definingDocumentURI,
            Document document) throws XPathExpressionException {
        String namespace = document.getDocumentElement()
                .getNamespaceURI();
        NodeList flowDefinitions = document.getDocumentElement()
                .getElementsByTagNameNS(namespace, FACES_FLOW_DEFINITION);
       
        if (0 == flowDefinitions.getLength()) {
            return;
        }
        FacesContext context = FacesContext.getCurrentInstance();
        Application app = context.getApplication();
        FlowHandler flowHandler = app.getFlowHandler();
        if (null == flowHandler) {
            FlowHandlerFactory flowHandlerFactory = (FlowHandlerFactory) FactoryFinder.getFactory(FactoryFinder.FLOW_HANDLER_FACTORY);
            app.setFlowHandler(flowHandler =
                    flowHandlerFactory.createFlowHandler(context));
        }
       
        XPath xpath = XPathFactory.newInstance().newXPath();
        xpath.setNamespaceContext(new FacesConfigNamespaceContext());
       
        String nameStr = "";
        NodeList nameList = (NodeList) xpath.evaluate("./ns1:name/text()",
                document.getDocumentElement(), XPathConstants.NODESET);
        if (null != nameList && 1 < nameList.getLength()) {
            throw new XPathExpressionException("<faces-config> must have at most one <name> element.");
        }
        if (null != nameList && 1 == nameList.getLength()) {
            nameStr = nameList.item(0).getNodeValue().trim();
            if (0 < nameStr.length()) {
                ApplicationAssociate associate = ApplicationAssociate.getInstance(context.getExternalContext());
                try {
                    associate.relateUrlToDefiningDocumentInJar(definingDocumentURI.toURL(), nameStr);
                } catch (MalformedURLException ex) {
                    throw new XPathExpressionException(ex);
                }
            }
        }
       
        for (int c = 0, size = flowDefinitions.getLength(); c < size; c++) {
            Node flowDefinition = flowDefinitions.item(c);
            String flowId = getIdAttribute(flowDefinition);
           
            String uriStr = definingDocumentURI.toASCIIString();
            if (uriStr.endsWith(RIConstants.FLOW_DEFINITION_ID_SUFFIX)) {
                nameStr = "";
            }
           
            FlowBuilderImpl flowBuilder = new FlowBuilderImpl(context);
            flowBuilder.id(nameStr, flowId);
           
            processViews(xpath, flowDefinition, flowBuilder);
            processNavigationRules(xpath, flowDefinition, flowBuilder);
            processReturns(xpath, flowDefinition, flowBuilder);
            processInboundParameters(xpath, flowDefinition, flowBuilder);
            processFlowCalls(xpath, flowDefinition, flowBuilder);
            processSwitches(xpath, flowDefinition, flowBuilder);
            processMethodCalls(context, xpath, flowDefinition, flowBuilder);
            processInitializerFinalizer(xpath, flowDefinition, flowBuilder);
           
            String startNodeId = processStartNode(xpath, flowDefinition, flowBuilder);
           
            if (null != startNodeId) {
                FlowImpl toAdd = flowBuilder._getFlow();
                FlowNode startNode = toAdd.getNode(startNodeId);
                if (null == startNode) {
                    throw new XPathExpressionException("Unable to find flow node with id " + startNodeId + " to mark as start node");
                } else {
                    toAdd.setStartNodeId(startNodeId);
                }
            } else {
                flowBuilder.viewNode(flowId, "/" + flowId + "/" + flowId + ".xhtml").markAsStartNode();
            }
            flowHandler.addFlow(context, flowBuilder.getFlow());
           
        }
       
    }

    private void processNavigationRules(XPath xpath, Node flowDefinition, FlowBuilder flowBuilder) throws XPathExpressionException{
        // <editor-fold defaultstate="collapsed">
        NodeList navRules = (NodeList) xpath.evaluate(".//ns1:navigation-rule",
                flowDefinition, XPathConstants.NODESET);
        for (int i_navRule = 0; i_navRule < navRules.getLength(); i_navRule++) {
            Node navRule = navRules.item(i_navRule);
            NodeList fromViewIdList = (NodeList)
                    xpath.evaluate(".//ns1:from-view-id/text()", navRule, XPathConstants.NODESET);
            if (1 != fromViewIdList.getLength()) {
                throw new XPathExpressionException("Within <navigation-rule> must have exactly one <from-view-id>");
            }
            String fromViewId = fromViewIdList.item(0).getNodeValue().trim();
           
            NodeList navCases = (NodeList)
                    xpath.evaluate(".//ns1:navigation-case", navRule, XPathConstants.NODESET);
            for (int i_navCase = 0; i_navCase < navCases.getLength(); i_navCase++) {
                Node navCase = navCases.item(i_navCase);
                NodeList toViewIdList = (NodeList)
                        xpath.evaluate(".//ns1:to-view-id/text()", navCase, XPathConstants.NODESET);
                if (1 != toViewIdList.getLength()) {
                    throw new XPathExpressionException("Within <navigation-case>, must have exactly one <to-view-id>");
                }
                String toViewId = toViewIdList.item(0).getNodeValue().trim();
               
                NavigationCaseBuilder ncb = flowBuilder.navigationCase();
                ncb.fromViewId(fromViewId).toViewId(toViewId);
               
                {
                    NodeList fromOutcomeList = (NodeList)
                            xpath.evaluate(".//ns1:from-outcome/text()", navCase, XPathConstants.NODESET);
                    if (null != fromOutcomeList && 1 < fromOutcomeList.getLength()) {
                        throw new XPathExpressionException("Within <navigation-case>, must have at most one <from-outcome>");
                    }
                    if (null != fromOutcomeList && 1 == fromOutcomeList.getLength()) {
                        String fromOutcome = fromOutcomeList.item(0).getNodeValue().trim();
                        ncb.fromOutcome(fromOutcome);
                    }
                }
                
                {
                    NodeList fromActionList = (NodeList)
                            xpath.evaluate(".//ns1:from-action/text()", navCase, XPathConstants.NODESET);
                    if (null != fromActionList && 1 < fromActionList.getLength()) {
                        throw new XPathExpressionException("Within <navigation-case>, must have at most one <from-action>");
                    }
                    if (null != fromActionList && 1 == fromActionList.getLength()) {
                        String fromAction = fromActionList.item(0).getNodeValue().trim();
                        ncb.fromAction(fromAction);
                    }
                }

                {
                    NodeList ifList = (NodeList)
                            xpath.evaluate(".//ns1:if/text()", navCase, XPathConstants.NODESET);
                    if (null != ifList && 1 < ifList.getLength()) {
                        throw new XPathExpressionException("Within <navigation-case>, must have zero or one <if>");
                    }
                    if (null != ifList && 1 == ifList.getLength()) {
                        String ifStr = ifList.item(0).getNodeValue().trim();
                        ncb.condition(ifStr);
                    }

                }
               
                {
                    NodeList redirectList = (NodeList)
                            xpath.evaluate(".//ns1:redirect", navCase, XPathConstants.NODESET);
                    if (null != redirectList && 1 < redirectList.getLength()) {
                        throw new XPathExpressionException("Within <navigation-case>, must have zero or one <redirect>");
                    }
                    if (null != redirectList && 1 == redirectList.getLength()) {
                        NavigationCaseBuilder.RedirectBuilder redirector = ncb.redirect();
                        Node redirectNode = redirectList.item(0);
                        String includeViewParams = getAttribute(redirectNode, "include-view-params");
                        if (null != includeViewParams && "true".equalsIgnoreCase(includeViewParams)) {
                            redirector.includeViewParams();
                        }
                        NodeList viewParamList = (NodeList)
                                xpath.evaluate(".//ns1:redirect-param", redirectNode, XPathConstants.NODESET);
                        if (null != viewParamList) {
                            for (int i_viewParam = 0; i_viewParam < viewParamList.getLength(); i_viewParam++) {
                                Node viewParam = viewParamList.item(i_viewParam);
                                NodeList nameList = (NodeList)
                                        xpath.evaluate(".//ns1:name/text()", viewParam, XPathConstants.NODESET);
                                if (null == nameList || 1 != nameList.getLength()) {
                                    throw new XPathExpressionException("Within <redirect-param> must have <name>.");
                                }
                                String nameStr = nameList.item(0).getNodeValue().trim();
                               
                                NodeList valueList = (NodeList)
                                        xpath.evaluate(".//ns1:value/text()", viewParam, XPathConstants.NODESET);
                                if (null == valueList || 1 != valueList.getLength()) {
                                    throw new XPathExpressionException("Within <redirect-param> must have <value>.");
                                }
                                String valueStr = valueList.item(0).getNodeValue().trim();
                                redirector.parameter(nameStr, valueStr);
                            }
                        }
                    }
                }
               
               
            }
        }
        // </editor-fold>
    }
   
    private void processViews(XPath xpath, Node flowDefinition, FlowBuilder flowBuilder) throws XPathExpressionException{
        // <editor-fold defaultstate="collapsed">
        NodeList views = (NodeList) xpath.evaluate(".//ns1:view",
                flowDefinition, XPathConstants.NODESET);
        for (int i_view = 0; i_view < views.getLength(); i_view++) {
            Node viewNode = views.item(i_view);
            String viewNodeId = getIdAttribute(viewNode);
            NodeList vdlDocumentList = (NodeList)
                    xpath.evaluate(".//ns1:vdl-document/text()", viewNode, XPathConstants.NODESET);
            if (1 != vdlDocumentList.getLength()) {
                throw new XPathExpressionException("Within <view> exactly one child is allowed, and it must be a <vdl-document>");
            }
            String vdlDocumentStr = vdlDocumentList.item(0).getNodeValue().trim();
            flowBuilder.viewNode(viewNodeId, vdlDocumentStr);
        }       
        // </editor-fold>
    }

    private void processReturns(XPath xpath, Node flowDefinition, FlowBuilder flowBuilder) throws XPathExpressionException{
        // <editor-fold defaultstate="collapsed">

        NodeList returns = (NodeList) xpath.evaluate(".//ns1:flow-return",
                flowDefinition, XPathConstants.NODESET);
        for (int i_return = 0; i_return < returns.getLength(); i_return++) {
            Node returnNode = returns.item(i_return);
            NodeList fromOutcomeList = (NodeList)
                    xpath.evaluate(".//ns1:from-outcome/text()", returnNode, XPathConstants.NODESET);
            String id = getIdAttribute(returnNode);
            if (null != fromOutcomeList && 1 < fromOutcomeList.getLength()) {
                throw new XPathExpressionException("Within <flow-return id=\"" + id + "\"> only one child is allowed, and it must be a <from-outcome>");
            }
            if (null != fromOutcomeList && 1 == fromOutcomeList.getLength()) {
                String fromOutcomeStr = fromOutcomeList.item(0).getNodeValue().trim();
                flowBuilder.returnNode(id).fromOutcome(fromOutcomeStr);
            }
           
        }
        // </editor-fold>
    }
   
    private void processInboundParameters(XPath xpath, Node flowDefinition, FlowBuilder flowBuilder) throws XPathExpressionException {
        // <editor-fold defaultstate="collapsed">
        NodeList inboundParameters = (NodeList) xpath.evaluate(".//ns1:inbound-parameter",
                flowDefinition, XPathConstants.NODESET);
        for (int i_inbound = 0; i_inbound < inboundParameters.getLength(); i_inbound++) {
            Node inboundParamNode = inboundParameters.item(i_inbound);
            NodeList nameList = (NodeList)
                    xpath.evaluate(".//ns1:name/text()", inboundParamNode, XPathConstants.NODESET);
            if (1 < nameList.getLength()) {
                throw new XPathExpressionException("Within <inbound-parameter> only one <name> child is allowed");
            }
            String nameStr = nameList.item(0).getNodeValue().trim();
           
            NodeList valueList = (NodeList)
                    xpath.evaluate(".//ns1:value/text()", inboundParamNode, XPathConstants.NODESET);
            if (1 < valueList.getLength()) {
                throw new XPathExpressionException("Within <inbound-parameter> only one <value> child is allowed");
            }
            String valueStr = valueList.item(0).getNodeValue().trim();
            flowBuilder.inboundParameter(nameStr, valueStr);
        }
        // </editor-fold>
    }
   
    private void processFlowCalls(XPath xpath, Node flowDefinition, FlowBuilder flowBuilder) throws XPathExpressionException {
        // <editor-fold defaultstate="collapsed">
        NodeList flowCalls = (NodeList) xpath.evaluate(".//ns1:flow-call",
                flowDefinition, XPathConstants.NODESET);
        for (int i_flowCall = 0; i_flowCall < flowCalls.getLength(); i_flowCall++) {
            Node flowCallNode = flowCalls.item(i_flowCall);
            String flowCallId = getIdAttribute(flowCallNode);
            NodeList facesFlowRefList = (NodeList)
                    xpath.evaluate(".//ns1:flow-reference",
                    flowCallNode, XPathConstants.NODESET);
            if (null == facesFlowRefList || 1 != facesFlowRefList.getLength()) {
                throw new XPathExpressionException("Within <flow-call> must have exactly one <flow-reference>");
            }
            Node facesFlowRefNode = facesFlowRefList.item(0);

            NodeList facesFlowIdList = (NodeList)
                    xpath.evaluate(".//ns1:flow-id/text()",
                    facesFlowRefNode, XPathConstants.NODESET);
            if (null == facesFlowIdList || 1 != facesFlowIdList.getLength()) {
                throw new XPathExpressionException("Within <flow-reference> must have exactly one <flow-id>");
            }
           
            String destinationId = facesFlowIdList.item(0).getNodeValue().trim();
           
            NodeList definingDocumentIdList = (NodeList)
                    xpath.evaluate(".//ns1:flow-document-id/text()",
                    facesFlowRefNode, XPathConstants.NODESET);
            if (null == definingDocumentIdList && 1 != definingDocumentIdList.getLength()) {
                throw new XPathExpressionException("Within <flow-reference> must have at most one <flow-document-id>");
            }
            String definingDocumentId = "";
            if (null != definingDocumentIdList && 1 == definingDocumentIdList.getLength()) {
                definingDocumentId = definingDocumentIdList.item(0).getNodeValue().trim();
            }
           
            FlowCallBuilder flowCallBuilder = flowBuilder.flowCallNode(flowCallId);
                   
            flowCallBuilder.flowReference(definingDocumentId, destinationId);
           
            NodeList outboundParameters = (NodeList) xpath.evaluate(".//ns1:outbound-parameter",
                    flowDefinition, XPathConstants.NODESET);
            if (null != outboundParameters) {
                for (int i_outbound = 0; i_outbound < outboundParameters.getLength(); i_outbound++) {
                    Node outboundParamNode = outboundParameters.item(i_outbound);
                    NodeList nameList = (NodeList)
                            xpath.evaluate(".//ns1:name/text()", outboundParamNode, XPathConstants.NODESET);
                    if (1 < nameList.getLength()) {
                        throw new XPathExpressionException("Within <outbound-parameter> only one <name> child is allowed");
                    }
                    String nameStr = nameList.item(0).getNodeValue().trim();
                   
                    NodeList valueList = (NodeList)
                            xpath.evaluate(".//ns1:value/text()", outboundParamNode, XPathConstants.NODESET);
                    if (1 < valueList.getLength()) {
                        throw new XPathExpressionException("Within <inbound-parameter> only one <value> child is allowed");
                    }
                    String valueStr = valueList.item(0).getNodeValue().trim();
                    flowCallBuilder.outboundParameter(nameStr, valueStr);
                }
            }
           
        }
        // </editor-fold>
    }
   
    private void processSwitches(XPath xpath, Node flowDefinition, FlowBuilder flowBuilder) throws XPathExpressionException {
        // <editor-fold defaultstate="collapsed">
        NodeList switches = (NodeList) xpath.evaluate(".//ns1:switch",
                flowDefinition, XPathConstants.NODESET);
        if (null == switches) {
            return;
        }
        for (int i_switch = 0; i_switch < switches.getLength(); i_switch++) {
            Node switchNode = switches.item(i_switch);
            String switchId = getIdAttribute(switchNode);
            SwitchBuilder switchBuilder = flowBuilder.switchNode(switchId);
            NodeList cases = (NodeList) xpath.evaluate(".//ns1:case",
                    switchNode, XPathConstants.NODESET);
            if (null != cases) {
                for (int i_case = 0; i_case < cases.getLength(); i_case++) {
                    Node caseNode = cases.item(i_case);
                    NodeList ifList = (NodeList)
                            xpath.evaluate(".//ns1:if/text()", caseNode, XPathConstants.NODESET);
                    if (1 < ifList.getLength()) {
                        throw new XPathExpressionException("Within <case> only one <if> child is allowed");
                    }
                    String ifStr = ifList.item(0).getNodeValue().trim();

                    NodeList fromOutcomeList = (NodeList)
                            xpath.evaluate(".//ns1:from-outcome/text()", caseNode, XPathConstants.NODESET);
                    if (1 < fromOutcomeList.getLength()) {
                        throw new XPathExpressionException("Within <case> only one <from-outcome> child is allowed");
                    }
                    String fromOutcomeStr = fromOutcomeList.item(0).getNodeValue().trim();
                   
                    switchBuilder.switchCase().condition(ifStr).fromOutcome(fromOutcomeStr);
                }
            }
           
            NodeList defaultOutcomeList = (NodeList)
                    xpath.evaluate(".//ns1:default-outcome/text()", switchNode, XPathConstants.NODESET);
            if (null != defaultOutcomeList && 1 < defaultOutcomeList.getLength()) {
                throw new XPathExpressionException("Within <switch> only one <default-outcome> child is allowed");
            }
            if (null != defaultOutcomeList) {
                String defaultOutcomeStr = defaultOutcomeList.item(0).getNodeValue().trim();
                switchBuilder.defaultOutcome(defaultOutcomeStr);
            }
        }
       
       
        // </editor-fold>
    }
   
    private void processMethodCalls(FacesContext context, XPath xpath, Node flowDefinition, FlowBuilder flowBuilder) throws XPathExpressionException {
        // <editor-fold defaultstate="collapsed">
        NodeList methodCalls = (NodeList) xpath.evaluate(".//ns1:method-call",
                flowDefinition, XPathConstants.NODESET);
        if (null == methodCalls) {
            return;
        }
        for (int i_methodCall = 0; i_methodCall < methodCalls.getLength(); i_methodCall++) {
            Node methodCallNode = methodCalls.item(i_methodCall);
            String methodCallId = getIdAttribute(methodCallNode);
            MethodCallBuilder methodCallBuilder = flowBuilder.methodCallNode(methodCallId);
            NodeList methodList = (NodeList)
                    xpath.evaluate(".//ns1:method/text()", methodCallNode, XPathConstants.NODESET);
            if (1 != methodList.getLength()) {
                throw new XPathExpressionException("Within <method-call> exactly one <method> child is allowed");
            }
            String methodStr = methodList.item(0).getNodeValue().trim();
           
            NodeList params = (NodeList) xpath.evaluate(".//ns1:parameter",
                    methodCallNode, XPathConstants.NODESET);
            if (null != params) {
                List<Class> paramTypes = Collections.emptyList();
                if (0 < params.getLength()) {
                    paramTypes = new ArrayList<Class>();
                    List<Parameter> paramList = new ArrayList<Parameter>();
                    Parameter toAdd = null;
                    ExpressionFactory ef = context.getApplication().getExpressionFactory();
                    ELContext elContext = context.getELContext();
                    ValueExpression ve = null;
                   
                    for (int i_param = 0; i_param < params.getLength(); i_param++) {
                        Node param = params.item(i_param);
                        NodeList valueList = (NodeList)
                                xpath.evaluate(".//ns1:value/text()", param, XPathConstants.NODESET);
                        if (null == valueList || 1 != valueList.getLength()) {
                            throw new XPathExpressionException("Within <parameter> exactly one <value> child is allowed");
                        }
                        String valueStr = valueList.item(0).getNodeValue().trim();
                        String classStr = null;
                       
                        NodeList classList = (NodeList)
                                xpath.evaluate(".//ns1:class/text()", param, XPathConstants.NODESET);
                        if (null != classList && 1 < classList.getLength()) {
                            throw new XPathExpressionException("Within <parameter> at most one <class> child is allowed");
                        }
                        if (null != classList && 1 == classList.getLength()) {
                            classStr = classList.item(0).getNodeValue().trim();
                        }
                        Class clazz = String.class;
                        if (null != classStr) {
                            try {
                                clazz = ReflectionUtil.forName(classStr);
                            } catch (ClassNotFoundException e) {
                                clazz = Object.class;
                            }
                        }
                       
                        ve = ef.createValueExpression(elContext, valueStr, clazz);
                        toAdd = new ParameterImpl(classStr, ve);
                        paramList.add(toAdd);
                        paramTypes.add(clazz);
                    }
                    methodCallBuilder.parameters(paramList);
                }
                Class [] paramArray = new Class[paramTypes.size()];
                paramTypes.toArray(paramArray);
                methodCallBuilder.expression(methodStr, paramArray);
            }
           
            NodeList defaultOutcomeList = (NodeList)
                    xpath.evaluate(".//ns1:default-outcome/text()", methodCallNode, XPathConstants.NODESET);
            if (null != defaultOutcomeList && 1 < defaultOutcomeList.getLength()) {
                throw new XPathExpressionException("Within <method-call> only one <default-outcome> child is allowed");
            }
            if (null != defaultOutcomeList) {
                String defaultOutcomeStr = defaultOutcomeList.item(0).getNodeValue().trim();
                methodCallBuilder.defaultOutcome(defaultOutcomeStr);
            }
           
        }
           
       
        // </editor-fold>
    }
   
    private void processInitializerFinalizer(XPath xpath, Node flowDefinition, FlowBuilder flowBuilder) throws XPathExpressionException {
        // <editor-fold defaultstate="collapsed">
        NodeList initializerNodeList = (NodeList)
                xpath.evaluate(".//ns1:initializer/text()", flowDefinition, XPathConstants.NODESET);
        if (1 < initializerNodeList.getLength()) {
            throw new XPathExpressionException("At most one <initializer> is allowed.");
        }
       
        if (1 == initializerNodeList.getLength()) {
            String initializerStr = initializerNodeList.item(0).getNodeValue().trim();
            flowBuilder.initializer(initializerStr);
        }

        NodeList finalizerNodeList = (NodeList)
                xpath.evaluate(".//ns1:finalizer/text()", flowDefinition, XPathConstants.NODESET);
        if (1 < finalizerNodeList.getLength()) {
            throw new XPathExpressionException("At most one <finalizer> is allowed.");
        }
       
        if (1 == finalizerNodeList.getLength()) {
            String finalizerStr = finalizerNodeList.item(0).getNodeValue().trim();
            flowBuilder.finalizer(finalizerStr);
        }
       
        // </editor-fold>
       
    }
   
    private String processStartNode(XPath xpath, Node flowDefinition, FlowBuilder flowBuilder) throws XPathExpressionException {
        // <editor-fold defaultstate="collapsed">
        String startNodeId = null;
        NodeList startNodeList = (NodeList) xpath.evaluate(".//ns1:start-node/text()",
                flowDefinition, XPathConstants.NODESET);
        if (1 < startNodeList.getLength()) {
            throw new XPathExpressionException("Within <flow-definition> at most one <start-node> is allowed");
        }
        if (null != startNodeList && 1 == startNodeList.getLength()) {
            startNodeId = startNodeList.item(0).getNodeValue().trim();
        }
       
        return startNodeId;
        // </editor-fold>
    }
   
    protected String getAttribute(Node node, String attrName) {
        // <editor-fold defaultstate="collapsed">
        Util.notNull("flow definition element", node);
        String result = null;
        NamedNodeMap attrs = node.getAttributes();
       
        if (null != attrs) {
            Attr idAttr = (Attr) attrs.getNamedItem(attrName);
            if (null != idAttr) {
                result = idAttr.getValue();
            }
        }

        return result;
        // </editor-fold>
    }
   
    protected String getIdAttribute(Node node) throws XPathExpressionException {
        // <editor-fold defaultstate="collapsed">

        Util.notNull("flow definition element", node);
        String result = null;
        NamedNodeMap attrs = node.getAttributes();
        String localName = "";
        boolean throwException = false;
       
        if (null != attrs) {
            Attr idAttr = (Attr) attrs.getNamedItem("id");
            if (null != idAttr) {
                result = idAttr.getValue();
                if (!idAttr.isId()) {
                    if (LOGGER.isLoggable(Level.FINEST)) {
                        LOGGER.log(Level.FINEST, "Element {0} has an id attribute, but it is not declared as type xsd:id", node.getLocalName());
                    }
                }
            } else {
                localName = node.getLocalName();
                throwException = true;
            }
        } else {
            localName = node.getLocalName();
            throwException = true;
        }
       
        if (throwException) {
            throw new XPathExpressionException("<" + localName +
                    "> must have an \"id\" attribute.");
        }
       
        return result;
        // </editor-fold>
    }

   
}
TOP

Related Classes of com.sun.faces.config.processor.FacesFlowDefinitionConfigProcessor$FlowDefinitionDocument

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.