/* * * Copyright (c) void.fm * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name void.fm nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ package etm.core.jmx; import etm.core.aggregation.Aggregate; import etm.core.metadata.AggregatorMetaData; import etm.core.monitor.EtmException; import etm.core.monitor.EtmMonitor; import etm.core.renderer.MeasurementRenderer; import java.io.CharArrayWriter; import java.io.IOException; import java.io.Writer; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TreeMap; /** * The ManagedEtmMonitor wraps an existing EtmMonitor instance * and exposes it through JMX. * * @author void.fm * @version $Revision$ * @deprecated Please use {@link EtmMonitorMBean} and {@link EtmMonitorJmxPlugin} instead. Will be removed with JETM 2.0.0. */ public class ManagedEtmMonitor implements ManagedEtmMonitorMBean { private static final String LINE_SEPARATOR = System.getProperty("line.separator"); private EtmMonitor monitor; private MeasurementRenderer textRenderer; private CharArrayWriter writer; public ManagedEtmMonitor(EtmMonitor aMonitor) { this(aMonitor, Locale.getDefault()); } public ManagedEtmMonitor(EtmMonitor aMonitor, Locale locale) { monitor = aMonitor; writer = new CharArrayWriter(); textRenderer = new HtmlRenderer(writer, locale); } public synchronized String showHtmlInfos() { try { monitor.render(textRenderer); return writer.toString(); } finally { writer.reset(); } } public synchronized void reset() { monitor.reset(); } public Date getStartTime() { return monitor.getMetaData().getStartTime(); } public Date getLastResetTime() { return monitor.getMetaData().getLastResetTime(); } public String getMonitorImplementationClass() { return monitor.getMetaData().getImplementationClass().getName(); } public String getMonitorDescription() { return monitor.getMetaData().getDescription(); } public String getTimerImplementationClass() { return monitor.getMetaData().getTimerMetaData().getImplementationClass().getName(); } public String getTimerDescription() { return monitor.getMetaData().getTimerMetaData().getDescription(); } public long getTimerTicksPerSecond() { return monitor.getMetaData().getTimerMetaData().getTicksPerSecond(); } public String[] getAggregatorChain() { List list = new ArrayList(); AggregatorMetaData aggregatorMetaData = monitor.getMetaData().getAggregatorMetaData(); while (aggregatorMetaData != null) { list.add(aggregatorMetaData.toString() + LINE_SEPARATOR); aggregatorMetaData = aggregatorMetaData.getNestedMetaData(); } return (String[]) list.toArray(new String[list.size()]); } public void start() { monitor.start(); } public void stop() { monitor.stop(); } public boolean isStarted() { return monitor.isStarted(); } static class HtmlRenderer implements MeasurementRenderer { private static final String TREE_SIGN = "|-"; private static final String HEAD = "<table border=\"1\" cellpadding=\"5\" >\n" + " <tr>\n" + " <th>Etm Point</th>\n" + " <th>Measurements</th>\n" + " <th>Average</th>\n" + " <th>Min/Max</th>\n" + " <th>Total Time</th>\n" + " </tr>\n"; private static final String FOOTER = "</table>"; private NumberFormat timeFormatter; private Writer responseWriter; private static final String SPACE = " "; /** * Constructs a SimpleTextRenderer using the provided locale * and provided writer. * * @param aWriter The writer to write to. * @param aLocale The locale to use. */ public HtmlRenderer(Writer aWriter, Locale aLocale) { responseWriter = aWriter; timeFormatter = NumberFormat.getNumberInstance(aLocale); timeFormatter.setMaximumFractionDigits(3); timeFormatter.setMinimumFractionDigits(3); timeFormatter.setGroupingUsed(true); } public void render(Map points) { try { responseWriter.write(HEAD.toCharArray()); StringBuffer buffer = new StringBuffer(); TreeMap map = new TreeMap(points); for (Iterator iterator = map.values().iterator(); iterator.hasNext();) { Aggregate point = (Aggregate) iterator.next(); buffer.append(" <tr>\n"); buffer.append(" <td align=\"left\">"); writeNames(buffer, point, 0); buffer.append("</td>\n"); buffer.append(" <td align=\"right\">"); writeMeasurements(buffer, point, 0); buffer.append("</td>\n"); buffer.append(" <td align=\"right\">"); writeTime(buffer, point, 0); buffer.append("</td>\n"); buffer.append(" <td align=\"right\">"); writeMinMax(buffer, point, 0); buffer.append("</td>\n"); buffer.append(" <td align=\"right\">"); writeTotals(buffer, point, 0); buffer.append("</td>\n"); buffer.append(" </tr>\n"); } responseWriter.write(buffer.toString().toCharArray()); responseWriter.write(FOOTER.toCharArray()); responseWriter.flush(); } catch (IOException e) { throw new EtmException("Unable to write to writer: " + e); } } private void writeNames(StringBuffer aBuffer, Aggregate aPoint, int depth) { if (depth > 0) { writeNestingLevel(aBuffer, depth); aBuffer.append(TREE_SIGN); } aBuffer.append(aPoint.getName()); aBuffer.append("<br />"); if (aPoint.hasChilds()) { int currentDepth = depth + 1; Map childs = aPoint.getChilds(); for (Iterator iterator = childs.values().iterator(); iterator.hasNext();) { Aggregate child = (Aggregate) iterator.next(); writeNames(aBuffer, child, currentDepth); } } } private void writeTotals(StringBuffer aBuffer, Aggregate aPoint, int depth) { aBuffer.append(timeFormatter.format(aPoint.getTotal())); aBuffer.append("<br />"); if (aPoint.hasChilds()) { Map childs = aPoint.getChilds(); int currentDepth = depth + 1; for (Iterator iterator = childs.values().iterator(); iterator.hasNext();) { Aggregate child = (Aggregate) iterator.next(); writeTotals(aBuffer, child, currentDepth); } } } private void writeTime(StringBuffer aBuffer, Aggregate aPoint, int depth) { aBuffer.append(timeFormatter.format(aPoint.getAverage())); aBuffer.append("<br />"); if (aPoint.hasChilds()) { Map childs = aPoint.getChilds(); int currentDepth = depth + 1; for (Iterator iterator = childs.values().iterator(); iterator.hasNext();) { Aggregate child = (Aggregate) iterator.next(); writeTime(aBuffer, child, currentDepth + 1); } } } private void writeMinMax(StringBuffer aBuffer, Aggregate aPoint, int depth) { aBuffer.append(timeFormatter.format(aPoint.getMin())); aBuffer.append("/"); aBuffer.append(timeFormatter.format(aPoint.getMax())); aBuffer.append("<br />"); if (aPoint.hasChilds()) { Map childs = aPoint.getChilds(); int currentDepth = depth + 1; for (Iterator iterator = childs.values().iterator(); iterator.hasNext();) { Aggregate child = (Aggregate) iterator.next(); writeMinMax(aBuffer, child, currentDepth + 1); } } } private void writeMeasurements(StringBuffer aBuffer, Aggregate aPoint, int depth) { aBuffer.append(aPoint.getMeasurements()); aBuffer.append("<br />"); if (aPoint.hasChilds()) { Map childs = aPoint.getChilds(); int currentDepth = depth + 1; for (Iterator iterator = childs.values().iterator(); iterator.hasNext();) { Aggregate child = (Aggregate) iterator.next(); writeMeasurements(aBuffer, child, currentDepth); } } } protected void writeNestingLevel(StringBuffer buffer, int newDepth) { for (int i = 0; i < newDepth; i++) { buffer.append(SPACE); } } } }