DocumentTypeXmlParser.java :  » ERP-CRM-Financial » rice » edu » iu » uis » eden » xml » Java Open Source

Java Open Source » ERP CRM Financial » rice 
rice » edu » iu » uis » eden » xml » DocumentTypeXmlParser.java
/*
 * Copyright 2005-2006 The Kuali Foundation.
 *
 *
 * Licensed under the Educational Community License, Version 1.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.opensource.org/licenses/ecl1.php
 *
 * 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 edu.iu.uis.eden.xml;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;

import org.apache.commons.lang.StringUtils;
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;
import org.xml.sax.SAXException;

import edu.iu.uis.eden.EdenConstants;
import edu.iu.uis.eden.KEWServiceLocator;
import edu.iu.uis.eden.doctype.DocumentType;
import edu.iu.uis.eden.doctype.DocumentTypeAttribute;
import edu.iu.uis.eden.doctype.DocumentTypePolicy;
import edu.iu.uis.eden.doctype.DocumentTypePolicyEnum;
import edu.iu.uis.eden.engine.node.ActivationTypeEnum;
import edu.iu.uis.eden.engine.node.BranchPrototype;
import edu.iu.uis.eden.engine.node.Process;
import edu.iu.uis.eden.engine.node.RouteNode;
import edu.iu.uis.eden.engine.node.RouteNodeConfigParam;
import edu.iu.uis.eden.exception.InvalidWorkgroupException;
import edu.iu.uis.eden.exception.InvalidXmlException;
import edu.iu.uis.eden.exception.WorkflowException;
import edu.iu.uis.eden.exception.WorkflowRuntimeException;
import edu.iu.uis.eden.routetemplate.FlexRM;
import edu.iu.uis.eden.routetemplate.RuleAttribute;
import edu.iu.uis.eden.routetemplate.RuleTemplate;
import edu.iu.uis.eden.routetemplate.xmlrouting.XPathHelper;
import edu.iu.uis.eden.user.WorkflowUser;
import edu.iu.uis.eden.util.Utilities;
import edu.iu.uis.eden.util.XmlHelper;
import edu.iu.uis.eden.workgroup.GroupNameId;
import edu.iu.uis.eden.workgroup.Workgroup;

/**
 * A parser for parsing an XML file into {@link DocumentType}s.
 *
 * @author Kuali Rice Team (kuali-rice@googlegroups.com)
 */
public class DocumentTypeXmlParser implements XmlConstants {

    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentTypeXmlParser.class);

    /**
     * Default route node activation type to use if omitted
     */
    private static final String DEFAULT_ACTIVATION_TYPE = "S";

    public List docTypeRouteNodes;
    private Map nodesMap;
    private XPath xpath;
    private Workgroup defaultExceptionWorkgroup;
    private static final String NEXT_NODE_EXP = "./@nextNode";
    private static final String PARENT_NEXT_NODE_EXP = "../@nextNode";
    private static final String PROCESS_NAME_ATTR = "processName";

    public List parseDocumentTypes(InputStream input) throws SAXException, IOException, ParserConfigurationException, XPathExpressionException, WorkflowException, TransformerException {

        List documentTypeBeans = new ArrayList();

      Document routeDocument=XmlHelper.trimXml(input);
        xpath = XPathHelper.newXPath();
        NodeList documentTypeNodes = (NodeList) xpath.evaluate("/data/documentTypes/documentType", routeDocument, XPathConstants.NODESET);
        for (int i = 0; i < documentTypeNodes.getLength(); i++) {
            DocumentType documentType = getDocumentType(documentTypeNodes.item(i));
            NodeList policiesList = (NodeList) xpath.evaluate("./policies", documentTypeNodes.item(i), XPathConstants.NODESET);
            if (policiesList.getLength() > 1) {
                throw new InvalidXmlException("More than one policies node is present in a document type node");
            }
            if (policiesList.getLength() > 0) {
                NodeList policyNodes = (NodeList) xpath.evaluate("./policy", policiesList.item(0), XPathConstants.NODESET);
                documentType.setPolicies(getDocumentTypePolicies(policyNodes, documentType));
            }

            NodeList attributeList = (NodeList) xpath.evaluate("./attributes", documentTypeNodes.item(i), XPathConstants.NODESET);
            if (attributeList.getLength() > 1) {
                throw new InvalidXmlException("More than one attributes node is present in a document type node");
            }

            if (attributeList.getLength() > 0) {
                NodeList attributeNodes = (NodeList) xpath.evaluate("./attribute", attributeList.item(0), XPathConstants.NODESET);
                documentType.setDocumentTypeAttributes(getDocumentTypeAttributes(attributeNodes, documentType));
            }


            NodeList securityList = (NodeList) xpath.evaluate("./security", documentTypeNodes.item(i), XPathConstants.NODESET);
            if (securityList.getLength() > 1) {
                throw new InvalidXmlException("More than one security node is present in a document type node");
            }

            if (securityList.getLength() > 0) {
               try {
                 Node securityNode = securityList.item(0);
                 String securityText = XmlHelper.writeNode(securityNode);
                 documentType.setDocumentTypeSecurityXml(securityText);
               }
               catch (Exception e) {
                 throw new InvalidXmlException(e);
               }
            }

            parseStructure(documentTypeNodes.item(i), routeDocument, documentType, new RoutePathContext());

            LOG.debug("Saving document type " + documentType.getName());
            WorkflowUser user = null;
            routeDocumentType(documentType, user);
            documentTypeBeans.add(documentType);
        }

        return documentTypeBeans;
    }

    private void routeDocumentType(DocumentType documentType, WorkflowUser user) {
        KEWServiceLocator.getDocumentTypeService().versionAndSave(documentType);
    }

    private DocumentType getDocumentType(Node documentTypeNode) throws XPathExpressionException, InvalidWorkgroupException, InvalidXmlException {
        DocumentType documentType = new DocumentType();
        try {
            documentType.setName((String) xpath.evaluate("./name", documentTypeNode, XPathConstants.STRING));
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type name", xpee);
            throw xpee;
        }
        try {
            documentType.setDescription((String) xpath.evaluate("./description", documentTypeNode, XPathConstants.STRING));
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type description", xpee);
            throw xpee;
        }
        try {
            documentType.setLabel((String) xpath.evaluate("./label", documentTypeNode, XPathConstants.STRING));
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type label", xpee);
            throw xpee;
        }
        try {
            if (((Boolean) xpath.evaluate("./postProcessorName", documentTypeNode, XPathConstants.BOOLEAN)).booleanValue()) {
                documentType.setPostProcessorName((String) xpath.evaluate("./postProcessorName", documentTypeNode, XPathConstants.STRING));
            }
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type postProcessorName", xpee);
            throw xpee;
        }
        String docHandler = null;
        try {
            docHandler = (String) xpath.evaluate("./docHandler", documentTypeNode, XPathConstants.STRING);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type docHandler", xpee);
            throw xpee;
        }

        if (Utilities.isEmpty(docHandler)) {
            throw new InvalidXmlException("docHandler element must be specified");
        }

        documentType.setDocHandlerUrl(docHandler);


        String messageEntity = null; // by default set this to null and let the system sort out what the "default" is
        if (((Boolean) xpath.evaluate("./" + MESSAGE_ENTITY, documentTypeNode, XPathConstants.BOOLEAN)).booleanValue()) {
            try {
                messageEntity = (String) xpath.evaluate("./" + MESSAGE_ENTITY, documentTypeNode, XPathConstants.STRING);
            } catch (XPathExpressionException xpee) {
                LOG.error("Error obtaining document type messageEntity", xpee);
                throw xpee;
            }
        }

        documentType.setMessageEntity(messageEntity);

        try {
          if (((Boolean) xpath.evaluate("./" + NOTIFICATION_FROM_ADDRESS, documentTypeNode, XPathConstants.BOOLEAN)).booleanValue()) {
                documentType.setNotificationFromAddress((String) xpath.evaluate("./" + NOTIFICATION_FROM_ADDRESS, documentTypeNode, XPathConstants.STRING));
            }
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type " + NOTIFICATION_FROM_ADDRESS, xpee);
            throw xpee;
        }

        try {
            if (XmlHelper.pathExists(xpath, "./" + CUSTOM_EMAIL_STYLESHEET, documentTypeNode)) {
                documentType.setCustomEmailStylesheet((String) xpath.evaluate("./" + CUSTOM_EMAIL_STYLESHEET, documentTypeNode, XPathConstants.STRING));
            }
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type " + CUSTOM_EMAIL_STYLESHEET, xpee);
            throw xpee;
        }

        documentType.setCurrentInd(Boolean.TRUE);

        String exceptionWgName;
        try {
            exceptionWgName = (String) xpath.evaluate("./defaultExceptionWorkgroupName", documentTypeNode, XPathConstants.STRING);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type defaultExceptionWorkgroupName", xpee);
            throw xpee;
        }

        if (! Utilities.isEmpty(exceptionWgName)) {
            // allow core config parameter replacement in documenttype workgroups
            exceptionWgName = Utilities.substituteConfigParameters(exceptionWgName);
          Workgroup exceptionWg = KEWServiceLocator.getWorkgroupService().getWorkgroup(new GroupNameId(exceptionWgName), true);
          if(exceptionWg == null) {
            throw new WorkflowRuntimeException("Exception workgroup name " + exceptionWgName + " does not exist");
          }
            documentType.setDefaultExceptionWorkgroup(exceptionWg);
            defaultExceptionWorkgroup = exceptionWg;
        }

        try {
            if (((Boolean) xpath.evaluate("./active", documentTypeNode, XPathConstants.BOOLEAN)).booleanValue()) {
                documentType.setActiveInd(Boolean.valueOf((String) xpath.evaluate("./active", documentTypeNode, XPathConstants.STRING)));
            } else {
                documentType.setActiveInd(Boolean.TRUE);
            }
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type active flag", xpee);
            throw xpee;
        }
        boolean parentElementExists = false;
        try {
            parentElementExists = XmlHelper.pathExists(xpath, "./parent", documentTypeNode);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type parent", xpee);
            throw xpee;
        }
        if (parentElementExists) {
            String parentDocumentTypeName = null;
            try {
                parentDocumentTypeName = (String) xpath.evaluate("./parent", documentTypeNode, XPathConstants.STRING);
            } catch (XPathExpressionException xpee) {
                LOG.error("Error obtaining document type parent", xpee);
                throw xpee;
            }
            DocumentType parentDocumentType = KEWServiceLocator.getDocumentTypeService().findByName(parentDocumentTypeName);
            if (parentDocumentType == null) {
                throw new InvalidXmlException("Invalid parent document type: '" + parentDocumentTypeName + "'");
            }
            documentType.setDocTypeParentId(parentDocumentType.getDocumentTypeId());
        }

        try {
            if (((Boolean) xpath.evaluate("./superUserWorkgroupName", documentTypeNode, XPathConstants.BOOLEAN)).booleanValue()) {
                String wg;
                try {
                    wg = (String) xpath.evaluate("./superUserWorkgroupName", documentTypeNode, XPathConstants.STRING);
                } catch (XPathExpressionException xpee) {
                    LOG.error("Error obtaining document type superUserWorkgroupName", xpee);
                    throw xpee;
                }
                // allow core config parameter replacement in documenttype workgroups
                wg = Utilities.substituteConfigParameters(wg);
                Workgroup suWorkgroup = KEWServiceLocator.getWorkgroupService().getWorkgroup(new GroupNameId(wg), true);
                if (suWorkgroup == null) {
                    throw new InvalidWorkgroupException("Workgroup could not be found: " + wg);
                }
                documentType.setSuperUserWorkgroupNoInheritence(suWorkgroup);
            }
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type superUserWorkgroupName", xpee);
            throw xpee;
        }
        String blanketWorkGroupName = null;
      String blanketApprovePolicy = null;
        try {
          if (((Boolean) xpath.evaluate("./blanketApproveWorkgroupName", documentTypeNode, XPathConstants.BOOLEAN)).booleanValue()) {
                blanketWorkGroupName =(String) xpath.evaluate("./blanketApproveWorkgroupName", documentTypeNode, XPathConstants.STRING);
        }
          if (((Boolean) xpath.evaluate("./blanketApprovePolicy", documentTypeNode, XPathConstants.BOOLEAN)).booleanValue()) {
                    blanketApprovePolicy =(String) xpath.evaluate("./blanketApprovePolicy", documentTypeNode, XPathConstants.STRING);
            }
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type blanketApproveWorkgroupName", xpee);
            throw xpee;
        }
        if (!StringUtils.isBlank(blanketWorkGroupName) && !StringUtils.isBlank(blanketApprovePolicy)){
          throw new InvalidXmlException("Only one of blanket approve name need to be set");
        } else if (!StringUtils.isBlank(blanketWorkGroupName)){
            // allow core config parameter replacement in documenttype workgroups
            blanketWorkGroupName = Utilities.substituteConfigParameters(blanketWorkGroupName);
          Workgroup blanketAppWorkgroup = KEWServiceLocator.getWorkgroupService().getWorkgroup(new GroupNameId(blanketWorkGroupName), true);
          if (blanketAppWorkgroup == null) {
            throw new InvalidWorkgroupException("The blanket approve workgroup " + blanketWorkGroupName + " does not exist");
          }
          documentType.setBlanketApproveWorkgroup(blanketAppWorkgroup);
        } else if (!StringUtils.isBlank(blanketApprovePolicy)){
          documentType.setBlanketApprovePolicy(blanketApprovePolicy);
        }
        try {
            if (((Boolean) xpath.evaluate("./routingVersion", documentTypeNode, XPathConstants.BOOLEAN)).booleanValue()) {
                String version;
                try {
                    version = (String) xpath.evaluate("./routingVersion", documentTypeNode, XPathConstants.STRING);
                } catch (XPathExpressionException xpee) {
                    LOG.error("Error obtaining document type routingVersion", xpee);
                    throw xpee;
                }
                if (!(version.equals(EdenConstants.ROUTING_VERSION_ROUTE_LEVEL) || version.equals(EdenConstants.ROUTING_VERSION_NODAL))) {
                    throw new WorkflowRuntimeException("Invalid routing version on document type: " + version);
                }
                documentType.setRoutingVersion(version);
            }
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type routingVersion", xpee);
            throw xpee;
        }

        return documentType;
    }

    private void parseStructure(Node documentTypeNode, Document routeDocument, DocumentType documentType, RoutePathContext context) throws XPathExpressionException, InvalidXmlException, InvalidWorkgroupException, TransformerException {
        // TODO have a validation function that takes an xpath statement and blows chunks if that
        // statement returns false

        NodeList processNodes;

        try {
            if (((Boolean) xpath.evaluate("./routePaths/routePath", documentTypeNode, XPathConstants.BOOLEAN)).booleanValue()) {
                processNodes = (NodeList) xpath.evaluate("./routePaths/routePath", documentTypeNode, XPathConstants.NODESET);
            } else {
                return;
            }
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type routePaths", xpee);
            throw xpee;
        }

        createProcesses(processNodes, documentType);

        NodeList nodeList = null;
        try {
            nodeList = (NodeList) xpath.evaluate("./routePaths/routePath/start", documentTypeNode, XPathConstants.NODESET);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type routePath start", xpee);
            throw xpee;
        }
        if (nodeList.getLength() > 1) {
            throw new InvalidXmlException("More than one start node is present in route path");
        } else if (nodeList.getLength() == 0) {
            throw new InvalidXmlException("No start node is present in route path");
        }
        try {
            nodeList = (NodeList) xpath.evaluate(".//routeNodes", documentTypeNode, XPathConstants.NODESET);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining document type routeNodes", xpee);
            throw xpee;
        }
        if (nodeList.getLength() > 1) {
            throw new InvalidXmlException("More than one routeNodes node is present in documentType node");
        } else if (nodeList.getLength() == 0) {
            throw new InvalidXmlException("No routeNodes node is present in documentType node");
        }
        Node routeNodesNode = nodeList.item(0);
        checkForOrphanedRouteNodes(documentTypeNode, routeNodesNode);

        // passed validation.
        nodesMap = new HashMap();
        for (int index = 0; index < processNodes.getLength(); index++) {
            Node processNode = processNodes.item(index);
            String startName;
            try {
                startName = (String) xpath.evaluate("./start/@name", processNode, XPathConstants.STRING);
            } catch (XPathExpressionException xpee) {
                LOG.error("Error obtaining routePath start name attribute", xpee);
                throw xpee;
            }
            String processName = EdenConstants.PRIMARY_PROCESS_NAME;
            if (Utilities.isEmpty(startName)) {
                try {
                    startName = (String) xpath.evaluate("./@initialNode", processNode, XPathConstants.STRING);
                } catch (XPathExpressionException xpee) {
                    LOG.error("Error obtaining routePath initialNode attribute", xpee);
                    throw xpee;
                }
                try {
                    processName = (String) xpath.evaluate("./@processName", processNode, XPathConstants.STRING);
                } catch (XPathExpressionException xpee) {
                    LOG.error("Error obtaining routePath processName attribute", xpee);
                    throw xpee;
                }
                if (Utilities.isEmpty(startName)) {
                    throw new InvalidXmlException("Invalid routePath: no initialNode attribute defined!");
                }
            }
            RouteNode routeNode = createRouteNode(null, startName, processNode, routeNodesNode, documentType, context);
            if (routeNode != null) {
                Process process = documentType.getNamedProcess(processName);
                process.setInitialRouteNode(routeNode);
            }
        }

    }

    /**
     * Checks for route nodes that are declared but never used and throws an InvalidXmlException if one is discovered.
     */
    private void checkForOrphanedRouteNodes(Node documentTypeNode, Node routeNodesNode) throws XPathExpressionException, InvalidXmlException {
      NodeList nodesInPath = (NodeList) xpath.evaluate("./routePaths/routePath//*/@name", documentTypeNode, XPathConstants.NODESET);
      List<String> nodeNamesInPath = new ArrayList<String>(nodesInPath.getLength());
      for (int index = 0; index < nodesInPath.getLength(); index++) {
        Node nameNode = nodesInPath.item(index);
        nodeNamesInPath.add(nameNode.getNodeValue());
      }

      NodeList declaredNodes = (NodeList) xpath.evaluate("./*/@name", routeNodesNode, XPathConstants.NODESET);
      List<String> declaredNodeNames = new ArrayList<String>(declaredNodes.getLength());
      for (int index = 0; index < declaredNodes.getLength(); index++) {
        Node nameNode = declaredNodes.item(index);
        declaredNodeNames.add(nameNode.getNodeValue());
      }

      // now compare the declared nodes to the ones actually used
      List<String> orphanedNodes = new ArrayList<String>();
      for (String declaredNode : declaredNodeNames) {
        boolean foundNode = false;
        for (String nodeInPath : nodeNamesInPath) {
          if (nodeInPath.equals(declaredNode)) {
            foundNode = true;
            break;
          }
        }
        if (!foundNode) {
          orphanedNodes.add(declaredNode);
        }
      }
      if (!orphanedNodes.isEmpty()) {
        String message = "The following nodes were declared but never used: ";
        for (Iterator iterator = orphanedNodes.iterator(); iterator.hasNext();) {
        String orphanedNode = (String) iterator.next();
        message += orphanedNode + (iterator.hasNext() ? ", " : "");
      }
        throw new InvalidXmlException(message);
      }
    }

    private void createProcesses(NodeList processNodes, DocumentType documentType) {
        for (int index = 0; index < processNodes.getLength(); index++) {
            Node processNode = processNodes.item(index);
            NamedNodeMap attributes = processNode.getAttributes();
            Node processNameNode = attributes.getNamedItem(PROCESS_NAME_ATTR);
            String processName = (processNameNode == null ? null : processNameNode.getNodeValue());
            Process process = new Process();
            if (Utilities.isEmpty(processName)) {
                process.setInitial(true);
                process.setName(EdenConstants.PRIMARY_PROCESS_NAME);
            } else {
                process.setInitial(false);
                process.setName(processName);
            }
            process.setDocumentType(documentType);
            documentType.addProcess(process);
        }
    }

    private RouteNode createRouteNode(RouteNode previousRouteNode, String nodeName, Node routePathNode, Node routeNodesNode, DocumentType documentType, RoutePathContext context) throws XPathExpressionException, InvalidXmlException, InvalidWorkgroupException, TransformerException {
        if (nodeName == null) return null;

        Node currentNode;
        try {
            currentNode = (Node) xpath.evaluate(".//*[@name = '" + nodeName + "']", routePathNode, XPathConstants.NODE);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining routePath for routeNode", xpee);
            throw xpee;
        }
        if (currentNode == null) {
            String message = "Next node '" + nodeName + "' for node '" + previousRouteNode.getRouteNodeName() + "' not found!";
            LOG.error(message);
            throw new InvalidXmlException(message);
        }
        boolean nodeIsABranch;
        try {
            nodeIsABranch = ((Boolean) xpath.evaluate("self::node()[local-name() = 'branch']", currentNode, XPathConstants.BOOLEAN)).booleanValue();
        } catch (XPathExpressionException xpee) {
            LOG.error("Error testing whether node is a branch", xpee);
            throw xpee;
        }
        if (nodeIsABranch) {
            throw new InvalidXmlException("Next node cannot be a branch node");
        }

        String localName;
        try {
            localName = (String) xpath.evaluate("local-name(.)", currentNode, XPathConstants.STRING);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining node local-name", xpee);
            throw xpee;
        }
        RouteNode currentRouteNode = null;
        if (nodesMap.containsKey(nodeName)) {
            currentRouteNode = (RouteNode) nodesMap.get(nodeName);
        } else {
            String nodeExpression = ".//*[@name='" + nodeName + "']";
            currentRouteNode = makeRouteNodePrototype(localName, nodeName, nodeExpression, routeNodesNode, documentType, context);
        }

        if ("split".equalsIgnoreCase(localName)) {
            getSplitNextNodes(currentNode, routePathNode, currentRouteNode, routeNodesNode, documentType, context);
        }

        if (previousRouteNode != null) {
            previousRouteNode.getNextNodes().add(currentRouteNode);
            nodesMap.put(previousRouteNode.getRouteNodeName(), previousRouteNode);
            currentRouteNode.getPreviousNodes().add(previousRouteNode);
        }

        String nextNodeName = null;
        boolean hasNextNodeAttrib;
        try {
            hasNextNodeAttrib = ((Boolean) xpath.evaluate(NEXT_NODE_EXP, currentNode, XPathConstants.BOOLEAN)).booleanValue();
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining node nextNode attrib", xpee);
            throw xpee;
        }
        if (hasNextNodeAttrib) {
            // if the node has a nextNode but is not a split node, the nextNode is used for its node
            if (!"split".equalsIgnoreCase(localName)) {
                try {
                    nextNodeName = (String) xpath.evaluate(NEXT_NODE_EXP, currentNode, XPathConstants.STRING);
                } catch (XPathExpressionException xpee) {
                    LOG.error("Error obtaining node nextNode attrib", xpee);
                    throw xpee;
                }
                createRouteNode(currentRouteNode, nextNodeName, routePathNode, routeNodesNode, documentType, context);
            } else {
                // if the node has a nextNode but is a split node, the nextNode must be used for that split node's join node
                nodesMap.put(currentRouteNode.getRouteNodeName(), currentRouteNode);
            }
        } else {
            // if the node has no nextNode of its own and is not a join which gets its nextNode from its parent split node
            if (!"join".equalsIgnoreCase(localName)) {
                nodesMap.put(currentRouteNode.getRouteNodeName(), currentRouteNode);
                // if join has a parent nextNode (on its split node) and join has not already walked this path
            } else {
                boolean parentHasNextNodeAttrib;
                try {
                    parentHasNextNodeAttrib = ((Boolean) xpath.evaluate(PARENT_NEXT_NODE_EXP, currentNode, XPathConstants.BOOLEAN)).booleanValue();
                } catch (XPathExpressionException xpee) {
                    LOG.error("Error obtaining parent node nextNode attrib", xpee);
                    throw xpee;
                }
                if (parentHasNextNodeAttrib && !nodesMap.containsKey(nodeName)) {
                    try {
                        nextNodeName = (String) xpath.evaluate(PARENT_NEXT_NODE_EXP, currentNode, XPathConstants.STRING);
                    } catch (XPathExpressionException xpee) {
                        LOG.error("Error obtaining parent node nextNode attrib", xpee);
                        throw xpee;
                    }
                    createRouteNode(currentRouteNode, nextNodeName, routePathNode, routeNodesNode, documentType, context);
                } else {
                    // if join's parent split node does not have a nextNode
                    nodesMap.put(currentRouteNode.getRouteNodeName(), currentRouteNode);
                }
            }
        }
        return currentRouteNode;
    }

    private void getSplitNextNodes(Node splitNode, Node routePathNode, RouteNode splitRouteNode, Node routeNodesNode, DocumentType documentType, RoutePathContext context) throws XPathExpressionException, InvalidXmlException, InvalidWorkgroupException, TransformerException {
        NodeList splitBranchNodes;
        try {
            splitBranchNodes = (NodeList) xpath.evaluate("./branch", splitNode, XPathConstants.NODESET);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining split node branch", xpee);
            throw xpee;
        }
        for (int i = 0; i < splitBranchNodes.getLength(); i++) {
            String branchName;
            try {
                branchName = (String) xpath.evaluate("./@name", splitBranchNodes.item(i), XPathConstants.STRING);
            } catch (XPathExpressionException xpee) {
                LOG.error("Error obtaining branch name attribute", xpee);
                throw xpee;
            }
            String name;
            try {
                name = (String) xpath.evaluate("./*[1]/@name", splitBranchNodes.item(i), XPathConstants.STRING);
            } catch (XPathExpressionException xpee) {
                LOG.error("Error obtaining first split branch node name", xpee);
                throw xpee;
            }
            context.branch = new BranchPrototype();
            context.branch.setName(branchName);

            createRouteNode(splitRouteNode, name, routePathNode, routeNodesNode, documentType, context);
        }
    }

    private RouteNode makeRouteNodePrototype(String nodeTypeName, String nodeName, String nodeExpression, Node routeNodesNode, DocumentType documentType, RoutePathContext context) throws XPathExpressionException, InvalidWorkgroupException, InvalidXmlException, TransformerException {
        NodeList nodeList;
        try {
            nodeList = (NodeList) xpath.evaluate(nodeExpression, routeNodesNode, XPathConstants.NODESET);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error evaluating node expression: '" + nodeExpression + "'");
            throw xpee;
        }
        if (nodeList.getLength() > 1) {
            throw new InvalidXmlException("More than one node under routeNodes has the same name of '" + nodeName + "'");
        }
        if (nodeList.getLength() == 0) {
            throw new InvalidXmlException("No node definition was found with the name '" + nodeName + "'");
        }
        Node node = nodeList.item(0);

        RouteNode routeNode = new RouteNode();
        // set fields that all route nodes of all types should have defined 
        routeNode.setDocumentType(documentType);
        routeNode.setRouteNodeName((String) xpath.evaluate("./@name", node, XPathConstants.STRING));
        routeNode.setContentFragment(XmlHelper.writeNode(node));
        
        if (XmlHelper.pathExists(xpath, "./activationType", node)) {
            routeNode.setActivationType(ActivationTypeEnum.parse((String) xpath.evaluate("./activationType", node, XPathConstants.STRING)).getCode());
        } else {
            routeNode.setActivationType(DEFAULT_ACTIVATION_TYPE);
        }

        Workgroup exceptionWorkgroup = defaultExceptionWorkgroup;
        String exceptionWorkgroupName = (String) xpath.evaluate("./exceptionWorkgroupName", node, XPathConstants.STRING);
        if (Utilities.isEmpty(exceptionWorkgroupName)) {
          // for backward compatibility we also need to be able to support exceptionWorkgroup
          exceptionWorkgroupName = (String) xpath.evaluate("./exceptionWorkgroup", node, XPathConstants.STRING);
        }
        if (Utilities.isEmpty(exceptionWorkgroupName)) {
          if (routeNode.getDocumentType().getDefaultExceptionWorkgroup() != null) {
            exceptionWorkgroupName = routeNode.getDocumentType().getDefaultExceptionWorkgroup().getGroupNameId().getNameId();
          }
        }
        if (!Utilities.isEmpty(exceptionWorkgroupName)) {
            exceptionWorkgroup = KEWServiceLocator.getWorkgroupService().getWorkgroup(new GroupNameId(exceptionWorkgroupName), true);
            if (exceptionWorkgroup == null) {
                throw new InvalidWorkgroupException("Could not locate exception workgroup by name " + exceptionWorkgroupName);
            }
        }
        if (exceptionWorkgroup == null) {
            throw new InvalidXmlException("No exception workgroup specified at node " + routeNode.getRouteNodeName() + ".  Either specify an exceptionWorkgroupName for each node or specify the defaultExceptionWorkgroupName.\n" + XmlHelper.jotNode(node));
        }
        routeNode.setExceptionWorkgroupName(exceptionWorkgroup.getGroupNameId().getNameId());
        routeNode.setExceptionWorkgroupId(exceptionWorkgroup.getWorkflowGroupId().getGroupId());
        if (((Boolean) xpath.evaluate("./mandatoryRoute", node, XPathConstants.BOOLEAN)).booleanValue()) {
            routeNode.setMandatoryRouteInd(Boolean.valueOf((String)xpath.evaluate("./mandatoryRoute", node, XPathConstants.STRING)));
        } else {
            routeNode.setMandatoryRouteInd(Boolean.FALSE);
        }
        if (((Boolean) xpath.evaluate("./finalApproval", node, XPathConstants.BOOLEAN)).booleanValue()) {
            routeNode.setFinalApprovalInd(Boolean.valueOf((String)xpath.evaluate("./finalApproval", node, XPathConstants.STRING)));
        } else {
            routeNode.setFinalApprovalInd(Boolean.FALSE);
        }
        
        // for every simple child element of the node, store a config parameter of the element name and text content
        NodeList children = node.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node n = children.item(i);
            if (n instanceof Element) {
                Element e = (Element) n;
                String name = e.getNodeName();
                String content = XmlHelper.getTextContent(e);
                routeNode.getConfigParams().add(new RouteNodeConfigParam(routeNode, name, content));
            }
        }

        // make sure a default rule selector is set
        Map<String, String> cfgMap = Utilities.getKeyValueCollectionAsMap(routeNode.getConfigParams());
        if (!cfgMap.containsKey(RouteNode.RULE_SELECTOR_CFG_KEY)) {
            routeNode.getConfigParams().add(new RouteNodeConfigParam(routeNode, RouteNode.RULE_SELECTOR_CFG_KEY, FlexRM.DEFAULT_RULE_SELECTOR));
        }
        
        if (((Boolean) xpath.evaluate("./ruleTemplate", node, XPathConstants.BOOLEAN)).booleanValue()) {
            String ruleTemplateName = (String) xpath.evaluate("./ruleTemplate", node, XPathConstants.STRING);
            RuleTemplate ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(ruleTemplateName);
            if (ruleTemplate == null) {
                throw new InvalidXmlException("Rule template for node '" + routeNode.getRouteNodeName() + "' not found: " + ruleTemplateName);
            }
            routeNode.setRouteMethodName(ruleTemplateName);
            routeNode.setRouteMethodCode(EdenConstants.ROUTE_LEVEL_FLEX_RM);
        } else if (((Boolean) xpath.evaluate("./routeModule", node, XPathConstants.BOOLEAN)).booleanValue()) {
            routeNode.setRouteMethodName((String) xpath.evaluate("./routeModule", node, XPathConstants.STRING));
            routeNode.setRouteMethodCode(EdenConstants.ROUTE_LEVEL_ROUTE_MODULE);
        }

        String nodeType = null;
        if (((Boolean) xpath.evaluate("./type", node, XPathConstants.BOOLEAN)).booleanValue()) {
            nodeType = (String) xpath.evaluate("./type", node, XPathConstants.STRING);
        } else {
            String localName = (String) xpath.evaluate("local-name(.)", node, XPathConstants.STRING);
            if ("start".equalsIgnoreCase(localName)) {
                nodeType = "edu.iu.uis.eden.engine.node.InitialNode";
            } else if ("split".equalsIgnoreCase(localName)) {
                nodeType = "edu.iu.uis.eden.engine.node.SimpleSplitNode";
            } else if ("join".equalsIgnoreCase(localName)) {
                nodeType = "edu.iu.uis.eden.engine.node.SimpleJoinNode";
            } else if ("requests".equalsIgnoreCase(localName)) {
                nodeType = "edu.iu.uis.eden.engine.node.RequestsNode";
            } else if ("process".equalsIgnoreCase(localName)) {
                nodeType = "edu.iu.uis.eden.engine.node.SimpleSubProcessNode";
            }
        }
        if (Utilities.isEmpty(nodeType)) {
            throw new InvalidXmlException("Could not determine node type for the node named '" + routeNode.getRouteNodeName() + "'");
        }
        routeNode.setNodeType(nodeType);

        String localName = (String) xpath.evaluate("local-name(.)", node, XPathConstants.STRING);
        if ("split".equalsIgnoreCase(localName)) {
            context.splitNodeStack.addFirst(routeNode);
        } else if ("join".equalsIgnoreCase(localName) && context.splitNodeStack.size() != 0) {
            // join node should have same branch prototype as split node
            RouteNode splitNode = (RouteNode)context.splitNodeStack.removeFirst();
            context.branch = splitNode.getBranch();
        }
        routeNode.setBranch(context.branch);

        return routeNode;
    }

    private List getDocumentTypePolicies(NodeList documentTypePolicies, DocumentType documentType) throws XPathExpressionException, InvalidXmlException {
        List policies = new ArrayList();
        Set policyNames = new HashSet();

        for (int i = 0; i < documentTypePolicies.getLength(); i++) {
            DocumentTypePolicy policy = new DocumentTypePolicy();
            policy.setDocumentTypeId(documentType.getDocumentTypeId());
            try {
                String policyName = (String) xpath.evaluate("./name", documentTypePolicies.item(i), XPathConstants.STRING);
                policy.setPolicyName(DocumentTypePolicyEnum.lookup(policyName).getName());
            } catch (XPathExpressionException xpee) {
                LOG.error("Error obtaining document type policy name", xpee);
                throw xpee;
            }
            //don't need this it's determined by the doctype bean based on the data - i think
//            if (((Boolean) xpath.evaluate("./inherited", documentTypePolicies.item(i), XPathConstants.BOOLEAN)).booleanValue()) {
//                policy.setInheritedFlag(new Boolean((String) xpath.evaluate("./inherited", documentTypePolicies.item(i), XPathConstants.STRING)));
//            } else {
//                policy.setInheritedFlag(Boolean.FALSE);
//            }
            try {

                if (((Boolean) xpath.evaluate("./value", documentTypePolicies.item(i), XPathConstants.BOOLEAN)).booleanValue()) {
                    policy.setPolicyValue(Boolean.valueOf((String) xpath.evaluate("./value", documentTypePolicies.item(i), XPathConstants.STRING)));
                } else {
                    policy.setPolicyValue(Boolean.FALSE);
                }
            } catch (XPathExpressionException xpee) {
                LOG.error("Error obtaining document type policy value", xpee);
                throw xpee;
            }
            if (!policyNames.add(policy.getPolicyName())) {
                throw new InvalidXmlException("Policy '" + policy.getPolicyName() + "' has already been defined on this document");
            } else {
                policies.add(policy);
            }
        }

        return policies;
    }

    private List getDocumentTypeAttributes(NodeList documentTypeAttributes, DocumentType documentType) throws XPathExpressionException, WorkflowException {
        List attributes = new ArrayList();

        for (int i = 0; i < documentTypeAttributes.getLength(); i++) {
            DocumentTypeAttribute attribute = new DocumentTypeAttribute();
            attribute.setDocumentType(documentType);
            String ruleAttributeName;
            try {
                ruleAttributeName = (String) xpath.evaluate("./name", documentTypeAttributes.item(i), XPathConstants.STRING);
            } catch (XPathExpressionException xpee) {
                LOG.error("Error obtaining rule attribute name", xpee);
                throw xpee;
            }
            RuleAttribute ruleAttribute = KEWServiceLocator.getRuleAttributeService().findByName(ruleAttributeName);
            if (ruleAttribute == null) {
                throw new WorkflowException("Could not find rule attribute: " + ruleAttributeName);
            }
            attribute.setDocumentType(documentType);
            attribute.setRuleAttribute(ruleAttribute);
            attribute.setOrderIndex(i+1);
            attributes.add(attribute);
        }
        return attributes;
    }

    private class RoutePathContext {
        public BranchPrototype branch;
        public LinkedList splitNodeStack = new LinkedList();
    }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.