Example usage for javax.xml.xpath XPathConstants NODE

List of usage examples for javax.xml.xpath XPathConstants NODE

Introduction

In this page you can find the example usage for javax.xml.xpath XPathConstants NODE.

Prototype

QName NODE

To view the source code for javax.xml.xpath XPathConstants NODE.

Click Source Link

Document

The XPath 1.0 NodeSet data type.

Usage

From source file:org.kramerius.replications.SecondPhase.java

private void replicateImg(String pid, String url, File foxml) throws PhaseException {
    try {/*  ww  w  .  j a v a2s. c om*/
        String handlePid = K4ReplicationProcess.pidFrom(url);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(foxml);
        String relsExt = RelsExtHelper.getRelsExtTilesUrl(document); // url of tiles

        if (relsExt != null) {
            InputStream stream = orignalImgData(pid, url);
            String imageserverDir = KConfiguration.getInstance().getConfiguration()
                    .getString("convert.imageServerDirectory");
            String path = imageserverDir + File.separator + handlePid.substring(5) + File.separator;
            FileUtils.forceMkdir(new File(path));
            File replicatedImage = new File(path + pid.substring(5) + ".jp2");
            FileUtils.copyInputStreamToFile(stream, replicatedImage);

            XPathFactory xpfactory = XPathFactory.newInstance();
            XPath xpath = xpfactory.newXPath();
            xpath.setNamespaceContext(new FedoraNamespaceContext());

            Node nodeTilesUrl = (Node) xpath.evaluate("//kramerius:tiles-url", document, XPathConstants.NODE);
            String imageServerTilesUrl = KConfiguration.getInstance().getConfiguration()
                    .getString("convert.imageServerTilesURLPrefix");

            String suffixTiles = KConfiguration.getInstance().getConfiguration()
                    .getString("convert.imageServerSuffix.tiles");
            String imageTilesUrl;
            if (KConfiguration.getInstance().getConfiguration()
                    .getBoolean("convert.imageServerSuffix.removeFilenameExtensions", false)) {
                imageTilesUrl = imageServerTilesUrl + "/" + handlePid.substring(5) + pid.substring(5)
                        + suffixTiles;
            } else {
                imageTilesUrl = imageServerTilesUrl + "/" + handlePid.substring(5) + pid.substring(5) + ".jp2"
                        + suffixTiles;
            }
            nodeTilesUrl.setTextContent(imageTilesUrl);

            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.transform(new DOMSource(document), new StreamResult(foxml));
        }
    } catch (ParserConfigurationException | IOException | XPathExpressionException | SAXException
            | TransformerException e) {
        throw new PhaseException(this, e);
    }
}

From source file:org.kuali.rice.ken.service.impl.NotificationMessageContentServiceImpl.java

/**
 * This method is the meat of the notification message parsing.  It uses DOM to parse out the notification
 * message XML and into a Notification BO.  It handles lookup of reference objects' primary keys so that it
 * can properly populate the notification object.
 * @param bytes/*from  w ww  .  j  a  va  2 s.  c o  m*/
 * @return Notification
 * @throws IOException
 * @throws XmlException
 */
private NotificationBo parseNotificationRequestMessage(byte[] bytes) throws IOException, XmlException {
    /* First we'll fully parse the DOM with validation turned on */
    Document doc;
    try {
        doc = Util.parseWithNotificationEntityResolver(new InputSource(new ByteArrayInputStream(bytes)), true,
                true, notificationContentTypeService);
    } catch (ParserConfigurationException pce) {
        throw new XmlException("Error obtaining XML parser", pce);
    } catch (SAXException se) {
        throw new XmlException("Error validating notification request", se);
    }

    Element root = doc.getDocumentElement();
    /* XPath is namespace-aware, so if the DOM that XPath will be evaluating has fully qualified elements
       (because, e.g., it has been parsed with a validating DOM parser as above, then we need to set a
       "NamespaceContext" which essentially declares the defined namespace mappings to XPath.
            
       Unfortunately there is no EASY way (that I have found at least) to automatically expose the namespaces
       that have been discovered in the XML document parsed into DOM to XPath (an oversight in my opinion as
       this requires duplicate footwork to re-expose known definitions).
            
       So what we do is create a set of helper classes that will expose both the "known" core Notification system
       namespaces, as well as those that can be derived from the DOM Document (Document exposes these but through a
       different API than XPath NamespaceContext).  We create CompoundNamespaceContext that consists of both of these
       constituent namespace contexts (so that our core NamespaceContext takes precedent...nobody should be redefining
       these!).
            
       We can *then* use fully qualified XPath expressions like: /nreq:notification/nreq:channel ...
            
       (Another alternative would be to REPARSE the incoming XML with validation turned off so we can have simpler XPath
       expresssions.  This is less correct, but also not ideal as we will want to use qualified XPath expressions with
       notification content type also)
     */
    XPath xpath = XPathFactory.newInstance().newXPath();
    xpath.setNamespaceContext(Util.getNotificationNamespaceContext(doc));

    /* First parse immediate/primitive Notification member data */
    LOG.debug("URI: " + xpath.getNamespaceContext().getNamespaceURI("nreq"));
    try {
        NotificationBo notification = new NotificationBo();

        String channelName = (String) xpath.evaluate("/nreq:notification/nreq:channel", root);
        LOG.debug("CHANNELNAME: " + channelName);
        String producerName = xpath.evaluate("/nreq:notification/nreq:producer", root);

        List<String> senders = new ArrayList<String>();
        NodeList nodes = (NodeList) xpath.evaluate("/nreq:notification/nreq:senders/nreq:sender", root,
                XPathConstants.NODESET);
        for (int i = 0; i < nodes.getLength(); i++) {
            LOG.debug("sender node: " + nodes.item(i));
            LOG.debug("sender node VALUE: " + nodes.item(i).getTextContent());
            senders.add(nodes.item(i).getTextContent());
        }
        nodes = (NodeList) xpath.evaluate(
                "/nreq:notification/nreq:recipients/nreq:group|/nreq:notification/nreq:recipients/nreq:user",
                root, XPathConstants.NODESET);
        List<NotificationRecipientBo> recipients = new ArrayList<NotificationRecipientBo>();
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            NotificationRecipientBo recipient = new NotificationRecipientBo();
            // NOTE: assumes validation has occurred; does not check validity of element name
            if (NotificationConstants.RECIPIENT_TYPES.GROUP.equalsIgnoreCase(node.getLocalName())) {
                //recipient.setRecipientType(NotificationConstants.RECIPIENT_TYPES.GROUP);
                recipient.setRecipientType(KimGroupMemberTypes.GROUP_MEMBER_TYPE.getCode());
                recipient.setRecipientId(KimApiServiceLocator.getGroupService()
                        .getGroupByNamespaceCodeAndName(
                                Utilities.parseGroupNamespaceCode(node.getTextContent()),
                                Utilities.parseGroupName(node.getTextContent()))
                        .getId());
            } else if (NotificationConstants.RECIPIENT_TYPES.USER.equalsIgnoreCase(node.getLocalName())) {
                //recipient.setRecipientType(NotificationConstants.RECIPIENT_TYPES.USER);
                recipient.setRecipientType(KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode());
                recipient.setRecipientId(node.getTextContent());
            } else {
                throw new XmlException("Invalid 'recipientType' value: '" + node.getLocalName()
                        + "'.  Needs to either be 'user' or 'group'");
            }
            recipient.setNotification(notification);
            recipients.add(recipient);
        }

        String deliveryType = xpath.evaluate("/nreq:notification/nreq:deliveryType", root);
        String sendDateTime = xpath.evaluate("/nreq:notification/nreq:sendDateTime", root);
        String autoRemoveDateTime = xpath.evaluate("/nreq:notification/nreq:autoRemoveDateTime", root);

        String priorityName = xpath.evaluate("/nreq:notification/nreq:priority", root);
        String title = xpath.evaluate("/nreq:notification/nreq:title", root);
        String contentTypeName = xpath.evaluate("/nreq:notification/nreq:contentType", root);

        /* Construct the Notification business object */

        if (!StringUtils.isBlank(title)) {
            notification.setTitle(title);
        }

        /* channel and producer require lookups in the system (i.e. we can't just create new instances out of whole cloth), so
           we call a helper method to retrieve references to the respective objects
         */
        NotificationChannelBo channel = Util.retrieveFieldReference("channel", "name", channelName,
                NotificationChannelBo.class, dataObjectService);
        notification.setChannel(channel);

        NotificationProducerBo producer = Util.retrieveFieldReference("producer", "name", producerName,
                NotificationProducerBo.class, dataObjectService);
        notification.setProducer(producer);

        for (String sender : senders) {
            NotificationSenderBo ns = new NotificationSenderBo();
            LOG.debug("Setting sender: " + sender);
            ns.setSenderName(sender);
            ns.setNotification(notification);
            notification.addSender(ns);
        }

        for (NotificationRecipientBo recipient : recipients) {
            LOG.debug("Setting recipient id: " + recipient.getRecipientId());
            //                recipient.setNotification(notification);
            notification.addRecipient(recipient);
        }

        /* validate the delivery type */
        if (!NotificationConstants.DELIVERY_TYPES.ACK.equalsIgnoreCase(deliveryType)
                && !NotificationConstants.DELIVERY_TYPES.FYI.equalsIgnoreCase(deliveryType)) {
            throw new XmlException(
                    "Invalid 'deliveryType' value: '" + deliveryType + "'.  Must be either 'ACK' or 'FYI'.");
        }
        notification.setDeliveryType(deliveryType);

        /* If we have gotten this far, then these dates have obviously already passed XML schema validation,
           but as that may be volatile we make sure to validate programmatically.
         */
        Date d;
        if (StringUtils.isNotBlank(sendDateTime)) {
            try {
                d = Util.parseXSDDateTime(sendDateTime);
            } catch (ParseException pe) {
                throw new XmlException("Invalid 'sendDateTime' value: " + sendDateTime, pe);
            }
            notification.setSendDateTimeValue(new Timestamp(d.getTime()));
        }
        if (StringUtils.isNotBlank(autoRemoveDateTime)) {
            try {
                d = Util.parseXSDDateTime(autoRemoveDateTime);
            } catch (ParseException pe) {
                throw new XmlException("Invalid 'autoRemoveDateTime' value: " + autoRemoveDateTime, pe);
            }
            notification.setAutoRemoveDateTimeValue(new Timestamp(d.getTime()));
        }

        /* we have to look up priority and content type in the system also */
        NotificationPriorityBo priority = Util.retrieveFieldReference("priority", "name", priorityName,
                NotificationPriorityBo.class, dataObjectService);
        notification.setPriority(priority);

        NotificationContentTypeBo contentType = Util.retrieveFieldReference("contentType", "name",
                contentTypeName, NotificationContentTypeBo.class, dataObjectService, Boolean.TRUE);
        notification.setContentType(contentType);

        /* Now handle and validate actual notification content.  This is a tricky part.
           Our job is to validate the incoming content xml blob.  However that content could be under ANY namespace
           (since we have pluggable content types).  So how can we construct an XPath expression, that refers to
           node names that are fully qualified with the correct namespace/uri, when we don't KNOW at this point what that
           correct namespace URI is?
                
           The solution is to use a namespace naming convention coupled with the defined content type name in order to generate
           the canonical namespace uri for any custom content type.
                
           ns:notification/Content<Content Type name>
                
           e.g. ns:notification/ContentSimple, or ns:notification/ContentEvent
                
           We then construct an "ephemeral" namespace prefix to use in the NamespaceContext/XPath expressions to refer to this namespace URI.
                
           e.g. contentNS_<unique number>
                
           It doesn't (shouldn't!) matter what this ephemeral namespace is.
                
           We then define a temporary NamespaceContext that consists only of this ephemeral namespace mapping, and wrap the existing
           XPath NamespaceContext (the nice one we set up above to do our original qualifizzizing) with it.  Then we are off and on our
           way and can use XPath to parse the content type of arbitrary namespace.
         */
        Map<String, String> contentTypeNamespace = new HashMap<String, String>();
        String ephemeralNamespace = "contentNS_" + System.currentTimeMillis();
        contentTypeNamespace.put(ephemeralNamespace, CONTENT_TYPE_NAMESPACE_PREFIX + contentType.getName());
        xpath.setNamespaceContext(new CompoundNamespaceContext(
                new ConfiguredNamespaceContext(contentTypeNamespace), xpath.getNamespaceContext()));
        Node contentNode = (Node) xpath.evaluate("/nreq:notification/" + ephemeralNamespace + ":content", root,
                XPathConstants.NODE);
        Element contentElement = null;
        String content = "";
        /* Since we have had to use <any processContents="lax" minOccurs="1" maxOccurs="1"/> for the content element
         * (since there is no way to specify a mandatory element of specified name, but unspecified type), we need to
         * make sure to *programmatically* enforce its existence, since schema won't (the above statement says any
         * element occuring once, but we don't want "any" element, we want an element named 'content').
         */
        if (contentNode == null) {
            throw new XmlException("The 'content' element is mandatory.");
        }
        if (contentNode != null) {
            if (!(contentNode instanceof Element)) {
                // don't know what could possibly cause this
                throw new XmlException("The 'content' node is not an Element! (???).");
            }
            contentElement = (Element) contentNode;
            /* Take the literal XML content value of the DOM node.
               This should be symmetric/reversable */
            content = XmlJotter.jotNode(contentNode, true);
        }

        notification.setContent(content);

        LOG.debug("Content type: " + contentType.getName());
        LOG.debug("Content: " + content);

        /* double check that we got content of the type that was declared, not just any valid
           content type! (e.g., can't send valid Event content for a Simple notification type)
         */
        validateContent(notification, contentType.getName(), contentElement, content);

        return notification;
    } catch (XPathExpressionException xpee) {
        throw new XmlException("Error parsing request", xpee);
    }
}

From source file:org.kuali.rice.kew.docsearch.xml.XMLSearchableAttributeContent.java

Node getSearchingConfig() throws XPathExpressionException, ParserConfigurationException {
    if (searchingConfig == null) {
        XPath xpath = XPathHelper.newXPath();
        // technically this should probably only be "searchingConfig", and not search the whole tree
        String searchingConfigExpr = "//searchingConfig";
        searchingConfig = (Node) xpath.evaluate(searchingConfigExpr, getAttributeConfig(), XPathConstants.NODE);
    }/*from  www. j ava 2  s .  c om*/
    return searchingConfig;
}

From source file:org.kuali.rice.kew.docsearch.xml.XMLSearchableAttributeContent.java

String getSearchContent() throws XPathExpressionException, ParserConfigurationException {
    if (searchContent == null) {
        Node cfg = getSearchingConfig();
        XPath xpath = XPathHelper.newXPath();
        Node n = (Node) xpath.evaluate("xmlSearchContent", cfg, XPathConstants.NODE);
        if (n != null) {
            StringBuilder sb = new StringBuilder();
            NodeList list = n.getChildNodes();
            for (int i = 0; i < list.getLength(); i++) {
                sb.append(XmlJotter.jotNode(list.item(i)));
            }//from  ww  w . ja  v a2 s  .c  om
            this.searchContent = sb.toString();
        }
    }
    return searchContent;
}

From source file:org.kuali.rice.kew.docsearch.xml.XMLSearchableAttributeContent.java

private static String getNodeText(XPath xpath, Node n, String expression) throws XPathExpressionException {
    Node node = (Node) xpath.evaluate(expression, n, XPathConstants.NODE);
    if (node == null)
        return null;
    return node.getTextContent();
}

From source file:org.kuali.rice.kew.rule.xmlrouting.StandardGenericXMLRuleAttribute.java

/**
 * Performs attribute validation producing a list of errors of the parameterized type T generated by the ErrorGenerator<T>
 * @throws XPathExpressionException/*from  w w  w.j  a  va  2 s.  c o  m*/
 */
private <T> List<T> validate(Element root, String[] types, Map map, ErrorGenerator<T> errorGenerator)
        throws XPathExpressionException {
    List<T> errors = new ArrayList();
    XPath xpath = XPathHelper.newXPath();

    NodeList nodes = getFields(xpath, root, types);
    for (int i = 0; i < nodes.getLength(); i++) {
        Node field = nodes.item(i);
        NamedNodeMap fieldAttributes = field.getAttributes();
        String fieldName = fieldAttributes.getNamedItem("name").getNodeValue();

        LOG.debug("evaluating field: " + fieldName);
        String findValidation = "//routingConfig/" + FIELD_DEF_E + "[@name='" + fieldName + "']/validation";

        Node validationNode = (Node) xpath.evaluate(findValidation, root, XPathConstants.NODE);
        boolean fieldIsRequired = false;
        if (validationNode != null) {
            NamedNodeMap validationAttributes = validationNode.getAttributes();
            Node reqAttribNode = validationAttributes.getNamedItem("required");
            fieldIsRequired = reqAttribNode != null && "true".equalsIgnoreCase(reqAttribNode.getNodeValue());
        }

        String findRegex = "//routingConfig/" + FIELD_DEF_E + "[@name='" + fieldName + "']/validation/regex";

        String regex = null;
        Node regexNode = (Node) xpath.evaluate(findRegex, root, XPathConstants.NODE);

        if (regexNode != null && regexNode.getFirstChild() != null) {
            regex = regexNode.getFirstChild().getNodeValue();
            if (regex == null) {
                throw new RuntimeException("Null regex text node");
            }
        } /* else {
          if (fieldIsRequired) {
              fieldIsOnlyRequired = true;
              LOG.debug("Setting empty regex to .+ as field is required");
              // NOTE: ok, so technically .+ is not the same as checking merely
              // for existence, because a field can be extant but "empty"
              // however this has no relevance to the user as an empty field
              // is for all intents and purposes non-existent (not-filled-in)
              // so let's just use this regex to simplify the logic and
              // pass everything through a regex check
              regex = ".+";
          } else {
              LOG.debug("Setting empty regex to .* as field is NOT required");
              regex = ".*";
          }
          }*/

        LOG.debug("regex for field '" + fieldName + "': '" + regex + "'");

        String fieldValue = null;
        if (map != null) {
            fieldValue = (String) map.get(fieldName);
        }

        LOG.debug("field value: " + fieldValue);

        // fix up non-existent value for regex purposes only
        if (fieldValue == null) {
            fieldValue = "";
        }

        if (regex == null) {
            if (fieldIsRequired) {
                if (fieldValue.length() == 0) {
                    errors.add(errorGenerator.generateMissingFieldError(field, fieldName,
                            getValidationErrorMessage(xpath, root, fieldName)));
                }
            }
        } else {
            if (!Pattern.compile(regex).matcher(fieldValue).matches()) {
                LOG.debug("field value does not match validation regex");
                errors.add(errorGenerator.generateInvalidFieldError(field, fieldName,
                        getValidationErrorMessage(xpath, root, fieldName)));
            }
        }
    }
    return errors;
}

From source file:org.kuali.rice.kew.rule.xmlrouting.StandardGenericXMLRuleAttribute.java

public String getDocContent() {
    XPath xpath = XPathHelper.newXPath();
    final String findDocContent = "//routingConfig/xmlDocumentContent";
    try {/* w w  w .j a  v a 2  s . c om*/
        Node xmlDocumentContent = (Node) xpath.evaluate(findDocContent, getConfigXML(), XPathConstants.NODE);

        NodeList nodes = getFields(xpath, getConfigXML(), new String[] { "ALL", "REPORT", "RULE" });
        //            if (nodes == null || nodes.getLength() == 0) {
        //                return "";
        //            }

        if (xmlDocumentContent != null && xmlDocumentContent.hasChildNodes()) {
            // Custom doc content in the routingConfig xml.
            String documentContent = "";
            NodeList customNodes = xmlDocumentContent.getChildNodes();
            for (int i = 0; i < customNodes.getLength(); i++) {
                Node childNode = customNodes.item(i);
                documentContent += XmlJotter.jotNode(childNode);
            }

            for (int i = 0; i < nodes.getLength(); i++) {
                Node field = nodes.item(i);
                NamedNodeMap fieldAttributes = field.getAttributes();
                String fieldName = fieldAttributes.getNamedItem("name").getNodeValue();
                LOG.debug("Replacing field '" + fieldName + "'");
                Map map = getParamMap();
                String fieldValue = (String) map.get(fieldName);
                if (map != null && !org.apache.commons.lang.StringUtils.isEmpty(fieldValue)) {
                    LOG.debug("Replacing %" + fieldName + "% with field value: '" + fieldValue + "'");
                    documentContent = documentContent.replaceAll("%" + fieldName + "%", fieldValue);
                } else {
                    LOG.debug("Field map is null or fieldValue is empty");
                }
            }
            return documentContent;
        } else {
            // Standard doc content if no doc content is found in the routingConfig xml.
            StringBuffer documentContent = new StringBuffer("<xmlRouting>");
            for (int i = 0; i < nodes.getLength(); i++) {
                Node field = nodes.item(i);
                NamedNodeMap fieldAttributes = field.getAttributes();
                String fieldName = fieldAttributes.getNamedItem("name").getNodeValue();
                Map map = getParamMap();
                if (map != null && !org.apache.commons.lang.StringUtils.isEmpty((String) map.get(fieldName))) {
                    documentContent.append("<field name=\"");
                    documentContent.append(fieldName);
                    documentContent.append("\"><value>");
                    documentContent.append((String) map.get(fieldName));
                    documentContent.append("</value></field>");
                }
            }
            documentContent.append("</xmlRouting>");
            return documentContent.toString();
        }
    } catch (XPathExpressionException e) {
        LOG.error("error in getDocContent ", e);
        throw new RuntimeException("Error trying to find xml content with xpath expression", e);
    } catch (Exception e) {
        LOG.error("error in getDocContent attempting to find xml doc content", e);
        throw new RuntimeException("Error trying to get xml doc content.", e);
    }
}

From source file:org.kuali.rice.kew.xml.DocumentTypeXmlParser.java

public DocumentType generateNewDocumentTypeFromExisting(String documentTypeName)
        throws SAXException, IOException, ParserConfigurationException, XPathExpressionException,
        GroupNotFoundException, WorkflowException {
    // export the document type that exists in the database
    DocumentType docTypeFromDatabase = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
    if (docTypeFromDatabase != null) {
        KewExportDataSet kewExportDataSet = new KewExportDataSet();
        kewExportDataSet.getDocumentTypes().add(docTypeFromDatabase);
        byte[] xmlBytes = CoreApiServiceLocator.getXmlExporterService()
                .export(kewExportDataSet.createExportDataSet());
        // use the exported document type from the database to generate the new document type
        Document tempDocument = XmlHelper.trimXml(new BufferedInputStream(new ByteArrayInputStream(xmlBytes)));
        Node documentTypeNode = (Node) getXPath().evaluate(
                "/" + DATA_ELEMENT + "/" + DOCUMENT_TYPES + "/" + DOCUMENT_TYPE, tempDocument,
                XPathConstants.NODE);
        return getFullDocumentType(false, documentTypeNode);
    }/*from  w w  w  .  jav a2s .c o  m*/
    return null;
}

From source file:org.kuali.rice.kew.xml.DocumentTypeXmlParser.java

private RoutePathContext findNodeOnXPath(String nodeName, RoutePathContext context, Node routePathNode)
        throws XPathExpressionException, XmlException {
    Node currentNode;/*from  w w  w.  j a  va 2s . com*/

    while (context.nodeQName.length() > 1) {
        context.nodeXPath = context.nodeXPath.substring(0, context.nodeXPath.lastIndexOf("//"));
        context.nodeQName = context.nodeQName.substring(0,
                context.nodeQName.lastIndexOf(":", context.nodeQName.lastIndexOf(":") - 1) + 1);
        if (StringUtils.isBlank(context.nodeQName)) {
            context.nodeQName = ":";
        }

        try {
            currentNode = (Node) getXPath().evaluate(context.nodeXPath + "//" + "*[@name = '" + nodeName + "']",
                    routePathNode, XPathConstants.NODE);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining routePath for routeNode", xpee);
            throw xpee;
        }

        if (currentNode != null) {
            return context;
        }
    }

    return context;
}

From source file:org.kuali.rice.kew.xml.DocumentTypeXmlParser.java

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

    Node currentNode;//from   w  w w . j  a v a  2 s.c o m
    context.nodeXPath += "//" + "*[@name = '" + nodeName + "']";
    context.nodeQName += nodeName + ":";

    try {
        currentNode = (Node) getXPath().evaluate(context.nodeXPath + "//" + "*[@name = '" + nodeName + "']",
                routePathNode, XPathConstants.NODE);
        if (currentNode == null) {
            findNodeOnXPath(nodeName, context, routePathNode);
            currentNode = (Node) getXPath().evaluate(context.nodeXPath + "//" + "*[@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 XmlException(message);
    }

    context.nodeXPath += "//" + "*[@name = '" + nodeName + "']";
    context.nodeQName += nodeName + ":";
    LOG.debug("nodeQNme:" + context.nodeQName);
    boolean nodeIsABranch;

    try {
        nodeIsABranch = ((Boolean) getXPath().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 XmlException("Next node cannot be a branch node");
    }

    String localName;

    try {
        localName = (String) getXPath().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(context.nodeQName)) {
        currentRouteNode = (RouteNode) nodesMap.get(context.nodeQName);
    } else {
        String nodeExpression = ".//*[@name='" + nodeName + "']";
        currentRouteNode = makeRouteNodePrototype(localName, nodeName, nodeExpression, routeNodesNode,
                documentType, context);
    }

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

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

    String nextNodeName = null;
    boolean hasNextNodeAttrib;

    try {
        hasNextNodeAttrib = ((Boolean) getXPath().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) getXPath().evaluate(NEXT_NODE_EXP, currentNode, XPathConstants.STRING);
            } catch (XPathExpressionException xpee) {
                LOG.error("Error obtaining node nextNode attrib", xpee);
                throw xpee;
            }

            context.previousNodeQName = context.nodeQName;
            createRouteNode(currentRouteNode, nextNodeName, routePathNode, routeNodesNode, documentType,
                    cloneContext(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(context.nodeQName, 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(context.nodeQName, currentRouteNode);

        } else { // if join has a parent nextNode (on its split node) and join has not already walked this path
            boolean parentHasNextNodeAttrib;
            try {
                parentHasNextNodeAttrib = ((Boolean) getXPath().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(context.nodeQName)) {
                try {
                    nextNodeName = (String) getXPath().evaluate(PARENT_NEXT_NODE_EXP, currentNode,
                            XPathConstants.STRING);
                } catch (XPathExpressionException xpee) {
                    LOG.error("Error obtaining parent node nextNode attrib", xpee);
                    throw xpee;
                }

                context.previousNodeQName = context.nodeQName;
                createRouteNode(currentRouteNode, nextNodeName, routePathNode, routeNodesNode, documentType,
                        cloneContext(context));
            } else {
                // if join's parent split node does not have a nextNode
                nodesMap.put(context.nodeQName, currentRouteNode);
            }
        }
    }

    // handle nextAppDocStatus route node attribute
    String nextDocStatusName = null;
    boolean hasNextDocStatus;

    try {
        hasNextDocStatus = ((Boolean) getXPath().evaluate(NEXT_DOC_STATUS_EXP, currentNode,
                XPathConstants.BOOLEAN)).booleanValue();
    } catch (XPathExpressionException xpee) {
        LOG.error("Error obtaining node nextAppDocStatus attrib", xpee);
        throw xpee;
    }

    if (hasNextDocStatus) {
        try {
            nextDocStatusName = (String) getXPath().evaluate(NEXT_DOC_STATUS_EXP, currentNode,
                    XPathConstants.STRING);
        } catch (XPathExpressionException xpee) {
            LOG.error("Error obtaining node nextNode attrib", xpee);
            throw xpee;
        }

        //validate against allowable values if defined
        if (documentType.getValidApplicationStatuses() != null
                && documentType.getValidApplicationStatuses().size() > 0) {
            Iterator iter = documentType.getValidApplicationStatuses().iterator();
            boolean statusValidated = false;

            while (iter.hasNext()) {
                ApplicationDocumentStatus myAppDocStat = (ApplicationDocumentStatus) iter.next();
                if (nextDocStatusName.compareToIgnoreCase(myAppDocStat.getStatusName()) == 0) {
                    statusValidated = true;
                    break;
                }
            }

            if (!statusValidated) {
                XmlException xpee = new XmlException(
                        "AppDocStatus value " + nextDocStatusName + " not allowable.");
                LOG.error("Error validating nextAppDocStatus name: " + nextDocStatusName
                        + " against acceptable values.", xpee);
                throw xpee;
            }
        }

        currentRouteNode.setNextDocStatus(nextDocStatusName);
    }

    return currentRouteNode;
}