/*
* Copyright (c) 2012 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.server.status.war.components.memory;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior;
import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.request.resource.CssResourceReference;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.apache.wicket.resource.JQueryPluginResourceReference;
import org.apache.wicket.util.time.Duration;
/**
* The main page for the memory view. It contains labels that show the current
* memory situtation and a self-updating chart showing the memory values of the
* last 60 seconds.
*
* @author Michel Kraemer
*/
public class MemoryPanel extends Panel {
private static final long serialVersionUID = 5228052421880544175L;
/**
* Default constructor
*
* @param id the component ID
*/
public MemoryPanel(String id) {
super(id);
// calculate start values
long curMax = Runtime.getRuntime().maxMemory() / 1024 / 1024;
long curTotal = Runtime.getRuntime().totalMemory() / 1024 / 1024;
long curUsed = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024;
// create labels that show the current memory situation (they will be
// updated via Ajax)
final Label maxLabel = new Label("max_memory_label", String.valueOf(curMax));
final Label totalLabel = new Label("total_memory_label", String.valueOf(curTotal));
final Label usedLabel = new Label("used_memory_label", String.valueOf(curUsed));
maxLabel.setOutputMarkupId(true);
totalLabel.setOutputMarkupId(true);
usedLabel.setOutputMarkupId(true);
// create a container that redraws itself every second
WebMarkupContainer redrawContainer = new WebMarkupContainer("redraw_container");
redrawContainer.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(1)) {
private static final long serialVersionUID = -5579424950201876034L;
/**
* These arrays store the memory values of the last 61 seconds (one
* second more, because the chart goes from 0 to 60)
*/
private final long[] maxMemory = new long[61];
private final long[] totalMemory = new long[61];
private final long[] usedMemory = new long[61];
/**
* Shifts all values in the given array to the right and sets the
* first entry to the given value
*
* @param arr the array to shift
* @param val the new value to insert at position 0
*/
private void updateArray(long[] arr, long val) {
System.arraycopy(arr, 0, arr, 1, arr.length - 1);
arr[0] = val;
}
/**
* Creates a string that can be used as plotting data for the memory
* chart
*
* @param arr the array that contains the memory values of the last
* 61 seconds
* @return the plot data string
*/
private String makePlot(long[] arr) {
StringBuffer result = new StringBuffer();
for (int i = 0; i < arr.length; ++i) {
if (arr[i] != 0) {
if (result.length() > 0) {
result.append(",");
}
result.append("[" + i + "," + arr[i] + "]");
}
}
return result.toString();
}
/**
* Gets the maximum value from an array
*
* @param arr the array
* @return the maximum value in <code>arr</code>
*/
private long getMax(long[] arr) {
long result = 0;
for (int i = 0; i < arr.length; ++i) {
if (arr[i] > result) {
result = arr[i];
}
}
return result;
}
@Override
protected void onPostProcessTarget(final AjaxRequestTarget target) {
// get current memory situation
long curMax = Runtime.getRuntime().maxMemory() / 1024 / 1024;
long curTotal = Runtime.getRuntime().totalMemory() / 1024 / 1024;
long curUsed = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime()
.freeMemory()) / 1024 / 1024;
// update plot data of last 61 seconds
updateArray(totalMemory, curTotal);
updateArray(usedMemory, curUsed);
// create plot data string
String total = makePlot(totalMemory);
String free = makePlot(usedMemory);
// calculate the maximum for the chart's y axis (+ 50 MB)
long ymax = getMax(totalMemory) + 50;
// reset labels
maxLabel.setDefaultModelObject(String.valueOf(curMax));
totalLabel.setDefaultModelObject(String.valueOf(curTotal));
usedLabel.setDefaultModelObject(String.valueOf(curUsed));
target.add(maxLabel);
target.add(totalLabel);
target.add(usedLabel);
// redraw chart
target.appendJavaScript("chart_plot.axes.xaxis.max = " + (maxMemory.length - 1)
+ ";" + "chart_plot.axes.yaxis.max = " + ymax + ";"
+ "chart_plot.series[0].data = [" + total + "];"
+ "chart_plot.series[1].data = [" + free + "];" + "chart_plot.replot();");
}
});
redrawContainer.add(maxLabel);
redrawContainer.add(totalLabel);
redrawContainer.add(usedLabel);
add(redrawContainer);
// add a button that performs garbage collection
AjaxFallbackLink<Object> performGC = new AjaxFallbackLink<Object>("perform-gc") {
private static final long serialVersionUID = -1411055574233411598L;
@Override
public void onClick(AjaxRequestTarget target) {
System.gc();
}
};
redrawContainer.add(performGC);
}
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptHeaderItem.forReference(new JQueryPluginResourceReference(
MemoryPanel.class, "jquery.jqplot.min.js")));
response.render(CssHeaderItem.forReference(new CssResourceReference(MemoryPanel.class,
"jquery.jqplot.min.css")));
response.render(JavaScriptHeaderItem.forReference(new JavaScriptResourceReference(
MemoryPanel.class, "update.js")));
}
}