| /* |
| * 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.management.mbean; |
| |
| import java.io.InputStream; |
| import java.util.Stack; |
| |
| import javax.xml.XMLConstants; |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.SAXParser; |
| import javax.xml.parsers.SAXParserFactory; |
| |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| |
| import org.xml.sax.Attributes; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| import org.apache.camel.CamelContext; |
| import org.apache.camel.api.management.ManagedCamelContext; |
| import org.apache.camel.api.management.mbean.ManagedProcessorMBean; |
| import org.apache.camel.api.management.mbean.ManagedRouteMBean; |
| |
| /** |
| * An XML parser that uses SAX to enrich route stats in the route dump. |
| * <p/> |
| * The coverage details: |
| * <ul> |
| * <li>exchangesTotal - Total number of exchanges</li> |
| * <li>totalProcessingTime - Total processing time in millis</li> |
| * </ul> |
| * Is included as attributes on the route nodes. |
| */ |
| public final class RouteCoverageXmlParser { |
| |
| private RouteCoverageXmlParser() { |
| } |
| |
| /** |
| * Parses the XML. |
| * |
| * @param camelContext the CamelContext |
| * @param is the XML content as an input stream |
| * @return the DOM model of the routes with coverage information stored as attributes |
| * @throws Exception is thrown if error parsing |
| */ |
| public static Document parseXml(final CamelContext camelContext, final InputStream is) throws Exception { |
| final SAXParserFactory factory = SAXParserFactory.newInstance(); |
| factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); |
| final SAXParser parser = factory.newSAXParser(); |
| final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); |
| docBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); |
| final DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); |
| final Document doc = docBuilder.newDocument(); |
| |
| final Stack<Element> elementStack = new Stack<>(); |
| final StringBuilder textBuffer = new StringBuilder(); |
| final DefaultHandler handler = new DefaultHandler() { |
| |
| @Override |
| public void setDocumentLocator(final Locator locator) { |
| // noop |
| } |
| |
| @Override |
| public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException { |
| addTextIfNeeded(); |
| |
| final Element el = doc.createElement(qName); |
| // add other elements |
| for (int i = 0; i < attributes.getLength(); i++) { |
| el.setAttribute(attributes.getQName(i), attributes.getValue(i)); |
| } |
| |
| String id = el.getAttribute("id"); |
| if (id != null) { |
| try { |
| if ("route".equals(qName)) { |
| ManagedRouteMBean route = camelContext.getExtension(ManagedCamelContext.class).getManagedRoute(id); |
| if (route != null) { |
| long total = route.getExchangesTotal(); |
| el.setAttribute("exchangesTotal", "" + total); |
| long totalTime = route.getTotalProcessingTime(); |
| el.setAttribute("totalProcessingTime", "" + totalTime); |
| } |
| } else if ("from".equals(qName)) { |
| // grab statistics from the parent route as from would be the same |
| Element parent = elementStack.peek(); |
| if (parent != null) { |
| String routeId = parent.getAttribute("id"); |
| ManagedRouteMBean route = camelContext.getExtension(ManagedCamelContext.class).getManagedRoute(routeId); |
| if (route != null) { |
| long total = route.getExchangesTotal(); |
| el.setAttribute("exchangesTotal", "" + total); |
| long totalTime = route.getTotalProcessingTime(); |
| el.setAttribute("totalProcessingTime", "" + totalTime); |
| // from is index-0 |
| el.setAttribute("index", "0"); |
| } |
| } |
| } else { |
| ManagedProcessorMBean processor = camelContext.getExtension(ManagedCamelContext.class).getManagedProcessor(id); |
| if (processor != null) { |
| long total = processor.getExchangesTotal(); |
| el.setAttribute("exchangesTotal", "" + total); |
| long totalTime = processor.getTotalProcessingTime(); |
| el.setAttribute("totalProcessingTime", "" + totalTime); |
| int index = processor.getIndex(); |
| el.setAttribute("index", "" + index); |
| } |
| } |
| } catch (Exception e) { |
| // ignore |
| } |
| } |
| |
| // we do not want customId in output of the EIPs |
| if (!"route".equals(qName)) { |
| el.removeAttribute("customId"); |
| } |
| |
| elementStack.push(el); |
| } |
| |
| @Override |
| public void endElement(final String uri, final String localName, final String qName) { |
| addTextIfNeeded(); |
| final Element closedEl = elementStack.pop(); |
| if (elementStack.isEmpty()) { |
| // is this the root element? |
| doc.appendChild(closedEl); |
| } else { |
| final Element parentEl = elementStack.peek(); |
| parentEl.appendChild(closedEl); |
| } |
| } |
| |
| @Override |
| public void characters(final char[] ch, final int start, final int length) throws SAXException { |
| textBuffer.append(ch, start, length); |
| } |
| |
| /** |
| * outputs text accumulated under the current node |
| */ |
| private void addTextIfNeeded() { |
| if (textBuffer.length() > 0) { |
| final Element el = elementStack.peek(); |
| final Node textNode = doc.createTextNode(textBuffer.toString()); |
| el.appendChild(textNode); |
| textBuffer.delete(0, textBuffer.length()); |
| } |
| } |
| }; |
| parser.parse(is, handler); |
| |
| return doc; |
| } |
| } |