1 /*
2  * Copyright 2008-2019 by Emeric Vernat
3  *
4  *     This file is part of Java Melody.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18 package net.bull.javamelody.internal.web.html;
19
20 import java.io.IOException;
21 import java.io.Writer;
22 import java.util.List;
23
24 import net.bull.javamelody.internal.model.MBeanNode;
25 import net.bull.javamelody.internal.model.MBeanNode.MBeanAttribute;
26 import net.bull.javamelody.internal.model.MBeans;
27 import net.bull.javamelody.internal.model.PID;
28
29 /**
30  * Partie du rapport html pour les MBeans.
31  * @author Emeric Vernat
32  */

33 class HtmlMBeansReport extends HtmlAbstractReport {
34     private static final String BR = "<br/>";
35     private final List<MBeanNode> mbeans;
36     private final String pid = PID.getPID();
37     private int sequence;
38
39     HtmlMBeansReport(List<MBeanNode> mbeans, Writer writer) {
40         super(writer);
41         assert mbeans != null;
42         this.mbeans = mbeans;
43     }
44
45     @Override
46     void toHtml() throws IOException {
47         writeLinks();
48         writeln(BR);
49
50         writeTitle("mbeans.png", getString("MBeans"));
51
52         writeTree();
53     }
54
55     void writeTree() throws IOException {
56         if (mbeans.isEmpty()) {
57             return;
58         }
59         final String endDiv = "</div>";
60
61         // MBeans pour la plateforme
62         final MBeanNode platformNode = mbeans.get(0);
63         writeln("<div class='mbeanNode'>");
64         writeTree(platformNode.getChildren());
65         writeln(endDiv);
66
67         for (final MBeanNode node : mbeans) {
68             if (node != platformNode) {
69                 writeDirectly("<br/><b>" + htmlEncodeButNotSpace(node.getName()) + "</b>");
70                 writeln("<div class='mbeanNode'><br/>");
71                 writeTree(node.getChildren());
72                 writeln(endDiv);
73             }
74         }
75     }
76
77     private void writeTree(List<MBeanNode> nodes) throws IOException {
78         boolean first = true;
79         for (final MBeanNode node : nodes) {
80             final String name = node.getName();
81             if (first) {
82                 first = false;
83             } else {
84                 write(BR);
85             }
86             final List<MBeanNode> children = node.getChildren();
87             if (children != null) {
88                 final String id = getNextId();
89                 writePrintedShowHideLink(id, htmlEncodeButNotSpace(name));
90                 writeln("<div id='" + id + "' class='displayNone mbeanNode'><div>");
91                 writeTree(children);
92                 writeln("</div></div>");
93             } else {
94                 writeMBeanNode(node);
95             }
96         }
97     }
98
99     private void writeMBeanNode(MBeanNode mbean) throws IOException {
100         String mbeanName = mbean.getName();
101         final String mbeanId = getNextId();
102         final int indexOfComma = mbeanName.indexOf(',');
103         if (indexOfComma != -1) {
104             mbeanName = mbeanName.substring(indexOfComma + 1);
105             writePrintedShowHideLink(mbeanId, htmlEncodeButNotSpace(mbeanName));
106             writeln("<div id='" + mbeanId + "' class='displayNone mbeanNode'>");
107             // pas besoin d'ajouter un div pour le scroll-down, car les attributs sont
108             // dans une table
109             writeAttributes(mbean);
110             writeln("</div>");
111         } else {
112             writeAttributes(mbean);
113         }
114     }
115
116     private void writeAttributes(MBeanNode mbean) throws IOException {
117         final String description = mbean.getDescription();
118         final List<MBeanAttribute> attributes = mbean.getAttributes();
119         if (description != null || !attributes.isEmpty()) {
120             writeln("<table border='0' summary=''>");
121             if (description != null) {
122                 write("<tr><td colspan='3' class='mbeanAttributes'>(");
123                 writeDirectly(htmlEncodeButNotSpace(description));
124                 write(")</td></tr>");
125             }
126             for (final MBeanAttribute attribute : attributes) {
127                 writeAttribute(mbean, attribute);
128             }
129             writeln("</table>");
130         }
131     }
132
133     private void writeAttribute(MBeanNode mbean, MBeanAttribute attribute) throws IOException {
134         final String attributeName = attribute.getName();
135         final String formattedValue = attribute.getFormattedValue();
136         final String description = attribute.getDescription();
137         write("<tr valign='top'><td>");
138         if (mbean.getName().indexOf(MBeans.ATTRIBUTES_SEPARATOR) == -1
139                 && attributeName.indexOf(MBeans.ATTRIBUTES_SEPARATOR) == -1) {
140             writeDirectly(
141                     "<a href='?jmxValue=" + mbean.getName().replace(" ""%20").replace("'""%27")
142                             + '.' + attributeName + "' ");
143             writeln("title=\"#Lien_valeur_mbeans#\">-</a>&nbsp;");
144         } else {
145             // si le nom du mbean ou si le nom de l'attribut contient le caractère séparateur ('|'),
146             // alors l'appel de l'external api avec le lien ne fonctionnerait pas, donc on n'écrit pas le lien
147             // (cela peut arriver avec c3p0 si il n'y a pas com.mchange.v2.c3p0.management.ExcludeIdentityToken=true)
148             writeln("-&nbsp;");
149         }
150         writeDirectly(htmlEncodeButNotSpace(attributeName));
151         write("</td><td>");
152         // \n sera encodé dans <br/> dans htmlEncode
153         writeDirectly(htmlEncodeButNotSpace(formattedValue));
154         write("</td><td>");
155         if (description != null) {
156             write("(");
157             writeDirectly(htmlEncodeButNotSpace(description));
158             write(")");
159         } else {
160             write("&nbsp;");
161         }
162         write("</td></tr>");
163     }
164
165     private String getNextId() {
166         return 'x' + pid + '_' + sequence++;
167     }
168
169     void writeLinks() throws IOException {
170         writeln("<div class='noPrint'>");
171         writeln("<a class='back' href=''><img src='?resource=action_back.png' alt='#Retour#'/> #Retour#</a>");
172         writeln("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
173         writeln("<a href='?part=mbeans'><img src='?resource=action_refresh.png' alt='#Actualiser#'/> #Actualiser#</a>");
174         if (isPdfEnabled()) {
175             writeln("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
176             write("<a href='?part=mbeans&amp;format=pdf' title='#afficher_PDF#'>");
177             write("<img src='?resource=pdf.png' alt='#PDF#'/> #PDF#</a>");
178         }
179         writeln("</div>");
180     }
181
182     private void writePrintedShowHideLink(String idToShow, String label) throws IOException {
183         writeDirectly("<a class='showHide' href='' id='" + idToShow + "A' data-show-hide-id='"
184                 + idToShow + "'><img id='" + idToShow
185                 + "Img' src='?resource=bullets/plus.png' alt=''/> " + label + "</a>");
186     }
187 }
188