View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2005 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  
18  package ch.elca.el4j.services.statistics.light;
19  
20  import java.text.MessageFormat;
21  
22  import javax.management.MBeanServer;
23  import javax.management.ObjectName;
24  
25  import org.springframework.beans.factory.DisposableBean;
26  import org.springframework.beans.factory.InitializingBean;
27  
28  import ch.elca.el4j.services.monitoring.jmx.display.DisplayManager;
29  import ch.elca.el4j.services.monitoring.jmx.display.HtmlDisplayManager;
30  import ch.elca.el4j.services.monitoring.jmx.display.HtmlTabulator;
31  import ch.elca.el4j.services.monitoring.jmx.display.Section;
32  
33  import com.jamonapi.MonitorFactory;
34  
35  /**
36   * This class is a JMX proxy for JAMon performance measurements.
37   *
38   * @svnLink $Revision: 3880 $;$Date: 2009-08-04 15:17:52 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/light_statistics/jmx/src/main/java/ch/elca/el4j/services/statistics/light/LightStatisticsReporter.java $
39   *
40   * @author Andreas Bur (ABU)
41   */
42  public class LightStatisticsReporter
43  		implements LightStatisticsReporterMBean, InitializingBean,
44  		DisposableBean {
45  
46  	/** The address that points to this class. */
47  	public static final String NAME = "Performance:key=lightStatisticsReporter";
48  	
49  	/** The measurements' captions. */
50  	private static String[] CAPTIONS = {
51  		"Target", "Hits", "Avg",
52  		"Total", "StdDev", "LastValue",
53  		"Min", "Max", "Active",
54  		"AvgActive", "MaxActive", "FirstAccess",
55  		"LastAccess", "Enabled", "Primary", "HasListeners"
56  	};
57  	
58  	
59  	/** Foramt string used to render responses. */
60  	private String m_formatString;
61  	
62  	/** The MBean server where this class is registered in. */
63  	private MBeanServer m_server;
64  	
65  	/** Whether class names are printed fully qualified or not. */
66  	private boolean m_fullyQualified = false;
67  	
68  	/**
69  	 * {@inheritDoc}
70  	 */
71  	public String getFormatString() {
72  		return m_formatString;
73  	}
74  
75  	/**
76  	 * {@inheritDoc}
77  	 */
78  	public void setFormatString(String formatString) {
79  		this.m_formatString = formatString;
80  	}
81  
82  	/**
83  	 * {@inheritDoc}
84  	 */
85  	public boolean isFullyQualified() {
86  		return m_fullyQualified;
87  	}
88  
89  	/**
90  	 * {@inheritDoc}
91  	 */
92  	public void setFullyQualified(boolean fullyQualified) {
93  		this.m_fullyQualified = fullyQualified;
94  	}
95  
96  	/**
97  	 * @return Retruns the MBean server instance where this instance is
98  	 * retistered in.
99  	 */
100 	public MBeanServer getServer() {
101 		return m_server;
102 	}
103 
104 	/**
105 	 * Sets the MBean server where this instance has to register.
106 	 * @param beanServer The MBean server to set.
107 	 */
108 	public void setServer(MBeanServer beanServer) {
109 		m_server = beanServer;
110 	}
111 	
112 	/**
113 	 * {@inheritDoc}
114 	 */
115 	public void resetMonitor() {
116 		MonitorFactory.reset();
117 	}
118 
119 	/**
120 	 * {@inheritDoc}
121 	 */
122 	public void enableMonitor() {
123 		MonitorFactory.setEnabled(true);
124 	}
125 
126 	/**
127 	 * {@inheritDoc}
128 	 */
129 	public void disableMonitor() {
130 		MonitorFactory.setEnabled(false);
131 	}
132 	
133 	/**
134 	 * {@inheritDoc}
135 	 */
136 	public String[] getData() {
137 		Object[][] dataAsObj = MonitorFactory.getRootMonitor().getBasicData();
138 		
139 		if (dataAsObj == null) {
140 			return new String[]  {" "};
141 		}
142 		
143 		// make simple conversion to String[][]
144 		String[][] data;
145 		data = new String[dataAsObj.length][];
146 		for (int i = 0; i < dataAsObj.length; i++) {
147 			String[] line = new String[dataAsObj[i].length];
148 			for (int j = 0; j < dataAsObj[i].length; j++) {
149 				line[j] = (dataAsObj[i][j]).toString();
150 			}
151 			data[i] = line;
152 		}
153 		
154 		
155 		String[] paddedCaptions = new String[CAPTIONS.length];
156 		String[] result = new String[data.length + 1];
157 		MessageFormat format = new MessageFormat(m_formatString);
158 		
159 		int[] lengths = prepareData(data);
160 		
161 		// pad header
162 		for (int i = 0; i < CAPTIONS.length; i++) {
163 			paddedCaptions[i] = padString(CAPTIONS[i], lengths[i]);
164 		}
165 		
166 		// format header
167 		result[0] = format.format(paddedCaptions);
168 		
169 		
170 		if (data[0].length >= CAPTIONS.length) {
171 			// pad data
172 			for (int i = 0; i < data.length; i++) {
173 				for (int j = 0; j < CAPTIONS.length; j++) {
174 					data[i][j] = padString(data[i][j], lengths[j]);
175 				}
176 			}
177 			
178 			// format data
179 			for (int i = 0; i < data.length; i++) {
180 				result[i + 1] = format.format(data[i]);
181 			}
182 		}
183 		
184 		return result;
185 	}
186 	
187 	/**
188 	 * Converts class names, removes blank characters and computes the number
189 	 * of chars in the widest line.
190 	 * @param data The measurement data.
191 	 * @return The number of chars in the widest row for each column of the
192 	 * data.
193 	 */
194 	protected int[] prepareData(String[][] data) {
195 		int[] lengths = new int[CAPTIONS.length];
196 		
197 		for (int i = 0; i < CAPTIONS.length; i++) {
198 			lengths[i] = CAPTIONS[i].length();
199 		}
200 		
201 		// no measurements taken
202 		if (data[0].length == 1) {
203 			return lengths;
204 		}
205 		
206 		// convert class names
207 		for (int j = 0; j < data.length; j++) {
208 			data[j][0] = convertClassName(data[j][0]);
209 			int len = data[j][0].length();
210 			if (len > lengths[0]) {
211 				lengths[0] = len;
212 			}
213 		}
214 		
215 		for (int i = 1; i < CAPTIONS.length; i++) {
216 			for (int j = 0; j < data.length; j++) {
217 				// remove &nbsp
218 				data[j][i] = data[j][i].replaceAll("&nbsp", " ");
219 				
220 				// compute length
221 				int len = data[j][i].length();
222 				if (len > lengths[i]) {
223 					lengths[i] = len;
224 				}
225 			}
226 		}
227 		return lengths;
228 	}
229 	
230 	/**
231 	 * Pads the given string to the requested lengths using <code>_</code>.
232 	 * @param s The string to pad.
233 	 * @param len The final length of the padded string.
234 	 * @return The padded string.
235 	 */
236 	private String padString(String s, int len) {
237 		StringBuffer buffer = new StringBuffer(s);
238 		for (int i = s.length(); i < len; i++) {
239 			buffer.append("_");
240 		}
241 		return buffer.toString();
242 	}
243 	
244 	/**
245 	 * Formats a class name in demanded representation, fully qualified or just
246 	 * <code>ClassName.MethodName</code>.
247 	 * @param className
248 	 *      The fully qualified class name with method name appended.
249 	 * @return The string in demanded representation.
250 	 */
251 	private String convertClassName(String className) {
252 		if (m_fullyQualified) {
253 			return className;
254 			
255 		} else {
256 			int pos = className.lastIndexOf('.');
257 			String fqClassName = className.substring(0, pos);
258 			pos = fqClassName.lastIndexOf('.');
259 			return className.substring(pos + 1);
260 		}
261 	}
262 
263 	/**
264 	 * {@inheritDoc}
265 	 */
266 	public void afterPropertiesSet() throws Exception {
267 		if (m_server == null) {
268 			throw new IllegalStateException("m_beanServer has not been set!");
269 		}
270 		
271 		m_server.registerMBean(this, new ObjectName(NAME));
272 	}
273 
274 	/**
275 	 * {@inheritDoc}
276 	 */
277 	public void destroy() throws Exception {
278 		if (m_server != null) {
279 			m_server.unregisterMBean(new ObjectName(NAME));
280 		}
281 	}
282 	
283 	/** {@inheritDoc} */
284 	public String report() {
285 		DisplayManager manager = new HtmlDisplayManager();
286 		manager.setTitle("Light Statistics");
287 		Section section = new Section("Light Statistics");
288 		HtmlTabulator table = new HtmlTabulator(CAPTIONS);
289 		Object[][] data = MonitorFactory.getRootMonitor().getBasicData();
290 		
291 		if (data == null) {
292 			section.addWarning("No data.");
293 			manager.addSection(section);
294 			return manager.getPage();
295 		}
296 		
297 		for (Object[] row : data) {
298 			String[] thisRow = new String[row.length];
299 			for (int i = 0; i < row.length; i++) {
300 				thisRow[i] = row[i].toString();
301 			}
302 			table.addRow(thisRow);
303 		}
304 		section.add(table.tabulate());
305 		manager.addSection(section);
306 		
307 		return manager.getPage();
308 	}
309 }