/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.parser.helper;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.jboss.forge.roaster.model.util.Strings;
/**
* Various XML helper methods used for parsing XML routes.
*/
public final class CamelXmlHelper {
private CamelXmlHelper() {
// utility class
}
public static String getSafeAttribute(Node node, String key) {
if (node != null) {
Node attr = node.getAttributes().getNamedItem(key);
if (attr != null) {
return attr.getNodeValue();
}
}
return null;
}
public static List<Node> findAllEndpoints(Document dom) {
List<Node> nodes = new ArrayList<>();
NodeList list = dom.getElementsByTagName("endpoint");
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
if ("endpoint".equals(child.getNodeName())) {
// it may not be a camel namespace, so skip those
String ns = child.getNamespaceURI();
if (ns == null) {
NamedNodeMap attrs = child.getAttributes();
if (attrs != null) {
Node node = attrs.getNamedItem("xmlns");
if (node != null) {
ns = node.getNodeValue();
}
}
}
// assume no namespace its for camel
if (ns == null || ns.contains("camel")) {
nodes.add(child);
}
}
}
list = dom.getElementsByTagName("onException");
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
findAllUrisRecursive(child, nodes);
}
list = dom.getElementsByTagName("onCompletion");
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
findAllUrisRecursive(child, nodes);
}
list = dom.getElementsByTagName("intercept");
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
findAllUrisRecursive(child, nodes);
}
list = dom.getElementsByTagName("interceptFrom");
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
findAllUrisRecursive(child, nodes);
}
list = dom.getElementsByTagName("interceptSendToEndpoint");
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
findAllUrisRecursive(child, nodes);
}
list = dom.getElementsByTagName("rest");
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
if ("route".equals(child.getNodeName()) || "to".equals(child.getNodeName())) {
findAllUrisRecursive(child, nodes);
}
}
list = dom.getElementsByTagName("route");
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
if ("route".equals(child.getNodeName())) {
findAllUrisRecursive(child, nodes);
}
}
return nodes;
}
private static void findAllUrisRecursive(Node node, List<Node> nodes) {
// okay its a route so grab all uri attributes we can find
String url = getSafeAttribute(node, "uri");
if (url != null) {
nodes.add(node);
}
NodeList children = node.getChildNodes();
if (children != null) {
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
findAllUrisRecursive(child, nodes);
}
}
}
}
public static List<Node> findAllSimpleExpressions(Document dom) {
List<Node> nodes = new ArrayList<>();
NodeList list = dom.getElementsByTagName("route");
for (int i = 0; i < list.getLength(); i++) {
Node child = list.item(i);
if ("route".equals(child.getNodeName())) {
findAllSimpleExpressionsRecursive(child, nodes);
}
}
return nodes;
}
private static void findAllSimpleExpressionsRecursive(Node node, List<Node> nodes) {
// okay its a route so grab if its <simple>
if ("simple".equals(node.getNodeName())) {
nodes.add(node);
}
NodeList children = node.getChildNodes();
if (children != null) {
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
findAllSimpleExpressionsRecursive(child, nodes);
}
}
}
}
public static Element getSelectedCamelElementNode(String key, InputStream resourceInputStream) throws Exception {
Document root = loadCamelXmlFileAsDom(resourceInputStream);
Element selectedElement = null;
if (root != null) {
Node selectedNode = findCamelNodeInDocument(root, key);
if (selectedNode instanceof Element) {
selectedElement = (Element) selectedNode;
}
}
return selectedElement;
}
private static Document loadCamelXmlFileAsDom(InputStream resourceInputStream) throws Exception {
// must enforce the namespace to be http://camel.apache.org/schema/spring which is what the camel-core JAXB model uses
Document root = XmlLineNumberParser.parseXml(resourceInputStream, "camelContext,routes,rests", "http://camel.apache.org/schema/spring");
return root;
}
private static Node findCamelNodeInDocument(Document root, String key) {
Node selectedNode = null;
if (root != null && !Strings.isBlank(key)) {
String[] paths = key.split("/");
NodeList camels = getCamelContextElements(root);
if (camels != null) {
Map<String, Integer> rootNodeCounts = new HashMap<>();
for (int i = 0, size = camels.getLength(); i < size; i++) {
Node node = camels.item(i);
boolean first = true;
for (String path : paths) {
if (first) {
first = false;
String actual = getIdOrIndex(node, rootNodeCounts);
if (!equal(actual, path)) {
node = null;
}
} else {
node = findCamelNodeForPath(node, path);
}
if (node == null) {
break;
}
}
if (node != null) {
return node;
}
}
}
}
return selectedNode;
}
private static Node findCamelNodeForPath(Node node, String path) {
NodeList childNodes = node.getChildNodes();
if (childNodes != null) {
Map<String, Integer> nodeCounts = new HashMap<>();
for (int i = 0, size = childNodes.getLength(); i < size; i++) {
Node child = childNodes.item(i);
if (child instanceof Element) {
String actual = getIdOrIndex(child, nodeCounts);
if (equal(actual, path)) {
return child;
}
}
}
}
return null;
}
private static String getIdOrIndex(Node node, Map<String, Integer> nodeCounts) {
String answer = null;
if (node instanceof Element) {
Element element = (Element) node;
String elementName = element.getTagName();
if ("routes".equals(elementName)) {
elementName = "camelContext";
}
Integer countObject = nodeCounts.get(elementName);
int count = countObject != null ? countObject.intValue() : 0;
nodeCounts.put(elementName, ++count);
answer = element.getAttribute("id");
if (Strings.isBlank(answer)) {
answer = "_" + elementName + count;
}
}
return answer;
}
private static NodeList getCamelContextElements(Document dom) {
NodeList camels = dom.getElementsByTagName("camelContext");
if (camels == null || camels.getLength() == 0) {
camels = dom.getElementsByTagName("routes");
}
return camels;
}
private static boolean equal(Object a, Object b) {
return a == b ? true : a != null && b != null && a.equals(b);
}
}