/* * Copyright 2008-2017 by Emeric Vernat * * This file is part of Java Melody. * * Licensed 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 net.bull.javamelody; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import net.bull.javamelody.HtmlCounterReport.HtmlCounterRequestGraphReport; import net.bull.javamelody.SamplingProfiler.SampledMethod; /** * Rapport html. * @author Emeric Vernat */ class HtmlReport extends HtmlAbstractReport { private static final String SCRIPT_BEGIN = "<script type='text/javascript'>"; private static final String SCRIPT_END = "</script>"; private final Collector collector; private final CollectorServer collectorServer; private final List<JavaInformations> javaInformationsList; private final Range range; private final HtmlCoreReport htmlCoreReport; HtmlReport(Collector collector, CollectorServer collectorServer, List<JavaInformations> javaInformationsList, Range range, Writer writer) { super(writer); assert collector != null; assert javaInformationsList != null && !javaInformationsList.isEmpty(); assert range != null; this.collector = collector; this.collectorServer = collectorServer; this.javaInformationsList = javaInformationsList; this.range = range; this.htmlCoreReport = new HtmlCoreReport(collector, collectorServer, javaInformationsList, range, writer); } HtmlReport(Collector collector, CollectorServer collectorServer, List<JavaInformations> javaInformationsList, Period period, Writer writer) { this(collector, collectorServer, javaInformationsList, period.getRange(), writer); } @Override void toHtml() throws IOException { writeHtmlHeader(); htmlCoreReport.toHtml(); writeHtmlFooter(); } void toHtml(String message, String anchorNameForRedirect) throws IOException { writeHtmlHeader(); htmlCoreReport.toHtml(message, anchorNameForRedirect); writeHtmlFooter(); } void writeLastShutdown() throws IOException { writeHtmlHeader(false, true); htmlCoreReport.toHtml(null, null); writeHtmlFooter(); } static void writeAddAndRemoveApplicationLinks(String currentApplication, Writer writer) throws IOException { HtmlCoreReport.writeAddAndRemoveApplicationLinks(currentApplication, writer); } void writeAllCurrentRequestsAsPart() throws IOException { writeHtmlHeader(); final List<Counter> counters = collector.getRangeCountersToBeDisplayed(range); final Map<JavaInformations, List<CounterRequestContext>> currentRequests; if (collectorServer == null) { assert javaInformationsList.size() == 1; final JavaInformations javaInformations = javaInformationsList.get(0); final List<CounterRequestContext> rootCurrentContexts = collector .getRootCurrentContexts(counters); currentRequests = Collections.singletonMap(javaInformations, rootCurrentContexts); } else { currentRequests = collectorServer.collectCurrentRequests(collector.getApplication()); final List<CounterRequestContext> allCurrentRequests = new ArrayList<CounterRequestContext>(); for (final List<CounterRequestContext> rootCurrentContexts : currentRequests.values()) { allCurrentRequests.addAll(rootCurrentContexts); } CounterRequestContext.replaceParentCounters(allCurrentRequests, counters); } htmlCoreReport.writeAllCurrentRequestsAsPart(currentRequests); writeHtmlFooter(); } void writeAllThreadsAsPart() throws IOException { writeHtmlHeader(); htmlCoreReport.writeAllThreadsAsPart(); writeHtmlFooter(); } void writeThreadsDump() throws IOException { htmlCoreReport.writeThreadsDump(); } void writeCounterSummaryPerClass(String counterName, String requestId) throws IOException { writeHtmlHeader(); htmlCoreReport.writeCounterSummaryPerClass(counterName, requestId); writeHtmlFooter(); } void writeSource(String className) throws IOException { assert className != null; writeHtmlHeader(); new HtmlSourceReport(className, getWriter()).toHtml(); writeHtmlFooter(); } void writeDependencies() throws IOException { writeHtmlHeader(); final Map<String, MavenArtifact> dependencies = MavenArtifact.getWebappDependencies(); new HtmlDependenciesReport(dependencies, getWriter()).toHtml(); writeHtmlFooter(); } void writeSpringContext() throws IOException { writeHtmlHeader(); final SpringContext springContext = SpringContext.getSingleton(); new HtmlSpringContextReport(springContext, getWriter()).toHtml(); writeHtmlFooter(); } void writeHtmlHeader() throws IOException { writeHtmlHeader(false, false); } private void writeHtmlHeader(boolean includeSlider, boolean includeCssInline) throws IOException { writeln("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); writeDirectly("<html lang='" + I18N.getCurrentLocale().getLanguage() + "'><head><title>" + getFormattedString("Monitoring_sur", collector.getApplication()) + "</title>"); writeln(""); if (includeCssInline) { writeln("<style type='text/css'>"); final InputStream in = new BufferedInputStream( getClass().getResourceAsStream(Parameters.getResourcePath("monitoring.css"))); final ByteArrayOutputStream out = new ByteArrayOutputStream(); try { TransportFormat.pump(in, out); } finally { in.close(); } writeDirectly(out.toString()); writeln("</style>"); } else { writeln("<link rel='stylesheet' href='?resource=monitoring.css' type='text/css'/>"); writeln("<link rel='stylesheet' href='?resource=customizableMonitoring.css' type='text/css'/>"); } writeln("<link type='image/png' rel='shortcut icon' href='?resource=systemmonitor.png' />"); writeln("<script type='text/javascript' src='?resource=resizable_tables.js'></script>"); writeln("<script type='text/javascript' src='?resource=sorttable.js'></script>"); // prototype.js nécessaire pour effects.js et slider.js writeln("<script type='text/javascript' src='?resource=prototype.js'></script>"); // Effect slidedown/slideup décrit ici http://madrobby.github.com/scriptaculous/effect-slidedown/ writeln("<script type='text/javascript' src='?resource=effects.js'></script>"); // open dialog (for java sources), http://www.p51labs.com/lightwindow/ writeln("<script type='text/javascript' src='?resource=lightwindow.js'></script>"); if (includeSlider) { writeln("<script type='text/javascript' src='?resource=slider.js'></script>"); } writeln("<script type='text/javascript' src='?resource=customizableMonitoring.js'></script>"); writeJavaScript(); writeln("</head><body>"); } void writeHtmlFooter() throws IOException { final String analyticsId = Parameters.getParameter(Parameter.ANALYTICS_ID); if (analyticsId != null && !"disabled".equals(analyticsId)) { writeDirectly(SCRIPT_BEGIN); writeDirectly( "var gaJsHost = (('https:' == document.location.protocol) ? 'https://ssl.' : 'http://www.');\n"); writeDirectly( "document.write(unescape(\"%3Cscript src='\" + gaJsHost + \"google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E\"));\n"); writeDirectly(SCRIPT_END); writeDirectly(SCRIPT_BEGIN); writeDirectly(" try{\n"); writeDirectly("var pageTracker = _gat._getTracker('" + analyticsId + "');\n"); writeDirectly("pageTracker._trackPageview();\n"); writeDirectly("} catch(err) {}\n"); writeDirectly(SCRIPT_END); writeDirectly("\n"); } writeln("</body></html>"); } private void writeJavaScript() throws IOException { writeln(SCRIPT_BEGIN); writeln("function showHide(id){"); writeln(" if (document.getElementById(id).style.display=='none') {"); writeln(" if (document.getElementById(id + 'Img') != null) {"); writeln(" document.getElementById(id + 'Img').src='?resource=bullets/minus.png';"); writeln(" }"); writeln(" try {"); writeln(" Effect.SlideDown(id, { duration: 0.5 });"); writeln(" } catch (e) {"); // si effects.js n'est pas chargé, par exemple dans last_shutdown.html writeln(" document.getElementById(id).style.display='inline';"); writeln(" }"); writeln(" } else {"); writeln(" if (document.getElementById(id + 'Img') != null) {"); writeln(" document.getElementById(id + 'Img').src='?resource=bullets/plus.png';"); writeln(" }"); writeln(" try {"); writeln(" Effect.SlideUp(id, { duration: 0.5 });"); writeln(" } catch (e) {"); // si effects.js n'est pas chargé, par exemple dans last_shutdown.html writeln(" document.getElementById(id).style.display='none';"); writeln(" }"); writeln(" }"); writeln("}"); writeln(SCRIPT_END); } void writeMessageIfNotNull(String message, String partToRedirectTo) throws IOException { htmlCoreReport.writeMessageIfNotNull(message, partToRedirectTo, null); } void writeRequestAndGraphDetail(String graphName) throws IOException { writeHtmlHeader(true, false); writeln("<div align='center'>"); htmlCoreReport.writeRefreshAndPeriodLinks(graphName, "graph"); writeln("</div>"); new HtmlCounterRequestGraphReport(range, getWriter()).writeRequestAndGraphDetail(collector, collectorServer, graphName); writeHtmlFooter(); } void writeRequestUsages(String graphName) throws IOException { writeHtmlHeader(true, false); writeln("<div align='center'>"); htmlCoreReport.writeRefreshAndPeriodLinks(graphName, "usages"); writeln("</div>"); new HtmlCounterRequestGraphReport(range, getWriter()).writeRequestUsages(collector, graphName); writeHtmlFooter(); } void writeSessions(List<SessionInformations> sessionsInformations, String message, String sessionsPart) throws IOException { assert sessionsInformations != null; writeHtmlHeader(); writeMessageIfNotNull(message, sessionsPart); new HtmlSessionInformationsReport(sessionsInformations, getWriter()).toHtml(); writeHtmlFooter(); } void writeSessionDetail(String sessionId, SessionInformations sessionInformations) throws IOException { assert sessionId != null; writeHtmlHeader(); new HtmlSessionInformationsReport(null, getWriter()).writeSessionDetails(sessionId, sessionInformations); writeHtmlFooter(); } void writeHotspots(List<SampledMethod> hotspots) throws IOException { writeHtmlHeader(); new HtmlHotspotsReport(hotspots, getWriter()).toHtml(); writeHtmlFooter(); } void writeHeapHistogram(HeapHistogram heapHistogram, String message, String heapHistoPart) throws IOException { assert heapHistogram != null; writeHtmlHeader(); writeMessageIfNotNull(message, heapHistoPart); new HtmlHeapHistogramReport(heapHistogram, getWriter()).toHtml(); writeHtmlFooter(); } void writeProcesses(List<ProcessInformations> processInformationsList) throws IOException { assert processInformationsList != null; writeHtmlHeader(); new HtmlProcessInformationsReport(processInformationsList, getWriter()).toHtml(); writeHtmlFooter(); } void writeProcesses(Map<String, List<ProcessInformations>> processesByTitle) throws IOException { assert processesByTitle != null; writeHtmlHeader(); new HtmlProcessInformationsReport(new ArrayList<ProcessInformations>(), getWriter()) .writeLinks(); for (final Map.Entry<String, List<ProcessInformations>> entry : processesByTitle .entrySet()) { final String title = entry.getKey(); final List<ProcessInformations> processes = entry.getValue(); writeDirectly("<h3 class='chapterTitle'><img src='?resource=processes.png' alt='" + title + "'/> " + title + "</h3>"); new HtmlProcessInformationsReport(processes, getWriter()).writeTable(); } writeHtmlFooter(); } void writeDatabase(DatabaseInformations databaseInformations) throws IOException { assert databaseInformations != null; writeHtmlHeader(); new HtmlDatabaseInformationsReport(databaseInformations, getWriter()).toHtml(); writeHtmlFooter(); } void writeConnections(List<ConnectionInformations> connectionInformationsList, boolean withoutHeaders) throws IOException { assert connectionInformationsList != null; final HtmlConnectionInformationsReport htmlConnectionInformationsReport = new HtmlConnectionInformationsReport( connectionInformationsList, getWriter()); if (withoutHeaders) { // pour affichage dans serveur de collecte htmlConnectionInformationsReport.writeConnections(); } else { writeHtmlHeader(); htmlConnectionInformationsReport.toHtml(); writeHtmlFooter(); } } void writeJndi(List<JndiBinding> jndiBindings, String path) throws IOException { assert jndiBindings != null; writeHtmlHeader(); new HtmlJndiTreeReport(jndiBindings, path, getWriter()).toHtml(); writeHtmlFooter(); } void writeMBeans(List<MBeanNode> mbeans) throws IOException { assert mbeans != null; writeHtmlHeader(); new HtmlMBeansReport(mbeans, getWriter()).toHtml(); writeHtmlFooter(); } void writeMBeans(Map<String, List<MBeanNode>> mbeansByTitle) throws IOException { assert mbeansByTitle != null; writeHtmlHeader(); new HtmlMBeansReport(new ArrayList<MBeanNode>(), getWriter()).writeLinks(); for (final Map.Entry<String, List<MBeanNode>> entry : mbeansByTitle.entrySet()) { final String title = entry.getKey(); final List<MBeanNode> nodes = entry.getValue(); writeDirectly("<h3 class='chapterTitle'><img src='?resource=mbeans.png' alt='" + title + "'/> " + title + "</h3>"); new HtmlMBeansReport(nodes, getWriter()).writeTree(); } writeHtmlFooter(); } void writeCacheWithKeys(String cacheId, CacheInformations cacheInformations, String message, String cacheKeyPart, boolean withoutHeaders) throws IOException { assert cacheId != null; if (cacheInformations != null) { final HtmlCacheInformationsReport htmlCacheInformationsReport = new HtmlCacheInformationsReport( Collections.singletonList(cacheInformations), getWriter()); if (withoutHeaders) { htmlCacheInformationsReport.writeCacheWithKeys(cacheId, withoutHeaders); } else { writeHtmlHeader(); htmlCacheInformationsReport.writeCacheWithKeys(cacheId, withoutHeaders); writeHtmlFooter(); writeMessageIfNotNull(message, cacheKeyPart); } } } }