summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java6
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStats.java73
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStatsRow.java69
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/StatsMetadata.java84
-rw-r--r--src/com.gluster.storage.management.gui.feature.webstart/rootfiles/gluster-management-console.jnlp5
-rw-r--r--src/com.gluster.storage.management.gui.feature/feature.xml4
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ChartViewerComposite.java (renamed from src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/PieChartViewerComposite.java)167
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java107
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java28
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersSummaryView.java6
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java6
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableTreeViewerPage.java2
-rw-r--r--src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml18
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java45
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java160
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ValidationExceptionMapper.java39
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java106
17 files changed, 789 insertions, 136 deletions
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java
index 455ecc11..d4b0e43a 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java
@@ -42,6 +42,7 @@ public class RESTConstants {
public static final String RESOURCE_SERVERS = "servers";
public static final String RESOURCE_TASKS = "tasks";
public static final String RESOURCE_KEYS = "keys";
+ public static final String RESOURCE_STATISTICS = "statistics";
public static final String TASK_START = "start";
public static final String TASK_PAUSE = "pause";
@@ -98,6 +99,11 @@ public class RESTConstants {
public static final String QUERY_PARAM_DOWNLOAD = "download";
public static final String QUERY_PARAM_SERVER_NAME = "serverName";
public static final String QUERY_PARAM_DETAILS = "details";
+ public static final String QUERY_PARAM_TYPE = "type";
+
+ public static final String STATISTICS_TYPE_CPU = "cpu";
+ public static final String STATISTICS_TYPE_NETWORK = "network";
+ public static final String STATISTICS_TYPE_MEMORY = "memory";
public static final String FORMAT_XML = "xml";
public static final String FORMAT_JSON = "json";
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStats.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStats.java
new file mode 100644
index 00000000..042af256
--- /dev/null
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStats.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.core.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ */
+@XmlRootElement(name="xport")
+public class ServerStats {
+ private StatsMetadata metadata;
+ private List<ServerStatsRow> rows;
+
+ public ServerStats() {
+ }
+
+ public ServerStats(ServerStats newStats) {
+ copyFrom(newStats);
+ }
+
+ public void setRows(List<ServerStatsRow> rows) {
+ this.rows = rows;
+ }
+
+ @XmlElementWrapper(name="data")
+ @XmlElement(name="row", type=ServerStatsRow.class)
+ public List<ServerStatsRow> getRows() {
+ return rows;
+ }
+
+ public void setMetadata(StatsMetadata metadata) {
+ this.metadata = metadata;
+ }
+
+ @XmlElement(name="meta")
+ public StatsMetadata getMetadata() {
+ return metadata;
+ }
+
+ public void copyFrom(ServerStats newStats) {
+ setMetadata(newStats.getMetadata());
+
+ List<ServerStatsRow> newRows = newStats.getRows();
+ int rowCount = newRows.size();
+
+ rows = new ArrayList<ServerStatsRow>(rowCount);
+ for(ServerStatsRow newRow : newRows) {
+ rows.add(new ServerStatsRow(newRow));
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStatsRow.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStatsRow.java
new file mode 100644
index 00000000..0088cef6
--- /dev/null
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStatsRow.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.core.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ */
+@XmlRootElement(name="row")
+public class ServerStatsRow {
+ private Long timestamp;
+ private List<Double> usageData;
+
+ public ServerStatsRow() {
+ }
+
+ public ServerStatsRow(ServerStatsRow newRow) {
+ copyFrom(newRow);
+ }
+
+ private void copyFrom(ServerStatsRow newRow) {
+ setTimestamp(newRow.getTimestamp());
+
+ List<Double> myData = new ArrayList<Double>(newRow.getUsageData().size());
+ for(Double dataElement : newRow.getUsageData()) {
+ myData.add(dataElement);
+ }
+ setUsageData(myData);
+ }
+
+ @XmlElement(name="t")
+ public Long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public void setUsageData(List<Double> usageData) {
+ this.usageData = usageData;
+ }
+
+ @XmlElement(name="v")
+ public List<Double> getUsageData() {
+ return usageData;
+ }
+}
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/StatsMetadata.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/StatsMetadata.java
new file mode 100644
index 00000000..22b42671
--- /dev/null
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/StatsMetadata.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.core.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ */
+@XmlRootElement(name="meta")
+public class StatsMetadata {
+ private Long startTimestamp;
+ private Long endTimestamp;
+ private Integer step;
+ private Integer rowCount;
+ private List<String> legend = new ArrayList<String>();
+
+ @XmlElement(name="start")
+ public Long getStartTimestamp() {
+ return startTimestamp;
+ }
+
+ public void setStartTimestamp(Long startTimestamp) {
+ this.startTimestamp = startTimestamp;
+ }
+
+ @XmlElement(name="end")
+ public Long getEndTimestamp() {
+ return endTimestamp;
+ }
+
+ public void setEndTimestamp(Long endTimestamp) {
+ this.endTimestamp = endTimestamp;
+ }
+
+ @XmlElement(name="step")
+ public Integer getStep() {
+ return step;
+ }
+
+ public void setStep(Integer step) {
+ this.step = step;
+ }
+
+ @XmlElement(name="rows")
+ public Integer getRowCount() {
+ return rowCount;
+ }
+
+ public void setRowCount(Integer rowCount) {
+ this.rowCount = rowCount;
+ }
+
+ @XmlElementWrapper(name="legend")
+ @XmlElement(name="entry", type=String.class)
+ public List<String> getLegend() {
+ return legend;
+ }
+
+ public void setLegend(List<String> legend) {
+ this.legend = legend;
+ }
+}
diff --git a/src/com.gluster.storage.management.gui.feature.webstart/rootfiles/gluster-management-console.jnlp b/src/com.gluster.storage.management.gui.feature.webstart/rootfiles/gluster-management-console.jnlp
index c99eece8..597adf4c 100644
--- a/src/com.gluster.storage.management.gui.feature.webstart/rootfiles/gluster-management-console.jnlp
+++ b/src/com.gluster.storage.management.gui.feature.webstart/rootfiles/gluster-management-console.jnlp
@@ -6,6 +6,11 @@
<homepage href="$$codebase" />
<description>Gluster Management Console</description>
<icon kind="splash" href="splash.jpg"/>
+
+ <shortcut online="true">
+ <desktop/>
+ <menu submenu="Gluster"/>
+ </shortcut>
</information>
<security>
<all-permissions/>
diff --git a/src/com.gluster.storage.management.gui.feature/feature.xml b/src/com.gluster.storage.management.gui.feature/feature.xml
index 0f0c9e8b..7f526f72 100644
--- a/src/com.gluster.storage.management.gui.feature/feature.xml
+++ b/src/com.gluster.storage.management.gui.feature/feature.xml
@@ -538,7 +538,7 @@
id="org.eclipse.core.net.win32.x86_64"
os="win32"
ws="win32"
- arch="x86_64"
+ arch="x86_64, amd64"
download-size="0"
install-size="0"
version="0.0.0"
@@ -609,7 +609,7 @@
<plugin
id="org.eclipse.equinox.launcher.win32.win32.x86"
- os="win32"
+ os="Windows XP, Windows 7"
ws="win32"
arch="x86"
download-size="0"
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/PieChartViewerComposite.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ChartViewerComposite.java
index ad8e2fa3..edf18011 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/PieChartViewerComposite.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ChartViewerComposite.java
@@ -18,6 +18,7 @@
*******************************************************************************/
package com.gluster.storage.management.gui.utils;
+import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -28,23 +29,43 @@ import org.eclipse.birt.chart.exception.ChartException;
import org.eclipse.birt.chart.factory.GeneratedChartState;
import org.eclipse.birt.chart.factory.Generator;
import org.eclipse.birt.chart.model.Chart;
+import org.eclipse.birt.chart.model.ChartWithAxes;
import org.eclipse.birt.chart.model.ChartWithoutAxes;
+import org.eclipse.birt.chart.model.attribute.Anchor;
+import org.eclipse.birt.chart.model.attribute.AxisType;
import org.eclipse.birt.chart.model.attribute.Bounds;
import org.eclipse.birt.chart.model.attribute.ChartDimension;
+import org.eclipse.birt.chart.model.attribute.FontDefinition;
+import org.eclipse.birt.chart.model.attribute.LineAttributes;
+import org.eclipse.birt.chart.model.attribute.LineStyle;
+import org.eclipse.birt.chart.model.attribute.Marker;
+import org.eclipse.birt.chart.model.attribute.TickStyle;
import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl;
+import org.eclipse.birt.chart.model.attribute.impl.FontDefinitionImpl;
+import org.eclipse.birt.chart.model.attribute.impl.JavaDateFormatSpecifierImpl;
+import org.eclipse.birt.chart.model.attribute.impl.LineAttributesImpl;
+import org.eclipse.birt.chart.model.attribute.impl.TextAlignmentImpl;
+import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.component.Series;
import org.eclipse.birt.chart.model.component.impl.SeriesImpl;
+import org.eclipse.birt.chart.model.data.DateTimeDataSet;
import org.eclipse.birt.chart.model.data.NumberDataSet;
import org.eclipse.birt.chart.model.data.SeriesDefinition;
import org.eclipse.birt.chart.model.data.TextDataSet;
+import org.eclipse.birt.chart.model.data.impl.DateTimeDataSetImpl;
import org.eclipse.birt.chart.model.data.impl.NumberDataSetImpl;
import org.eclipse.birt.chart.model.data.impl.SeriesDefinitionImpl;
import org.eclipse.birt.chart.model.data.impl.TextDataSetImpl;
+import org.eclipse.birt.chart.model.impl.ChartWithAxesImpl;
import org.eclipse.birt.chart.model.impl.ChartWithoutAxesImpl;
import org.eclipse.birt.chart.model.layout.Legend;
import org.eclipse.birt.chart.model.layout.Plot;
+import org.eclipse.birt.chart.model.type.AreaSeries;
+import org.eclipse.birt.chart.model.type.LineSeries;
import org.eclipse.birt.chart.model.type.PieSeries;
+import org.eclipse.birt.chart.model.type.impl.AreaSeriesImpl;
+import org.eclipse.birt.chart.model.type.impl.LineSeriesImpl;
import org.eclipse.birt.chart.model.type.impl.PieSeriesImpl;
import org.eclipse.birt.core.framework.PlatformConfig;
import org.eclipse.core.runtime.Platform;
@@ -57,20 +78,42 @@ import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
+import com.ibm.icu.util.Calendar;
/**
*
*/
-public final class PieChartViewerComposite extends Composite implements
- PaintListener, IUpdateNotifier {
+public final class ChartViewerComposite extends Composite implements PaintListener, IUpdateNotifier {
+
+ public enum CHART_TYPE {
+ PIE, LINE
+ };
private IDeviceRenderer deviceReader = null;
private Chart chart = null;
private GeneratedChartState generatedChartState = null;
private boolean needsGeneration = true;
- private static Logger logger = Logger
- .getLogger(PieChartViewerComposite.class.getName());
+ private static Logger logger = Logger.getLogger(ChartViewerComposite.class.getName());
+
+ /**
+ * @param parent
+ * Parent composite of this pie chart viewer composite
+ * @param style
+ * SWT style to be used
+ * @param categories
+ * Categories of the pie chart
+ * @param values
+ * Values of each category in the pie chart Constructs a pie
+ * chart viewer composite for given categories and values
+ */
+ public ChartViewerComposite(Composite parent, int style, String[] categories, Double[] values) {
+ super(parent, style);
+ init();
+
+ chart = createPieChart(categories, values);
+ addPaintListener(this);
+ }
/**
* @param parent
@@ -83,17 +126,22 @@ public final class PieChartViewerComposite extends Composite implements
* Values of each category in the pie chart Constructs a pie
* chart viewer composite for given categories and values
*/
- public PieChartViewerComposite(Composite parent, int style, String[] categories,
- Double[] values) {
+ public ChartViewerComposite(Composite parent, int style, Calendar[] categories, Double[] values) {
super(parent, style);
+ init();
+
+ chart = createLineChart(categories, values);
+ addPaintListener(this);
+ }
+
+ public void init() {
try {
PlatformConfig config = new PlatformConfig();
config.setBIRTHome(Platform.getInstallLocation().getURL().getPath());
// Get the connection with SWT device to render the graphics.
deviceReader = ChartEngine.instance(config).getRenderer("dv.SWT");//$NON-NLS-1$
} catch (ChartException ex) {
- logger.log(Level.SEVERE, "Could not create Chart Renderer for SWT",
- ex);
+ logger.log(Level.SEVERE, "Could not create Chart Renderer for SWT", ex);
}
addControlListener(new ControlListener() {
@@ -106,9 +154,97 @@ public final class PieChartViewerComposite extends Composite implements
needsGeneration = true;
}
});
+ }
- chart = createPieChart(categories, values);
- addPaintListener(this);
+ private Chart createLineChart(Calendar[] timestamps, Double[] values) {
+ return createAreaChart(timestamps, new Double[][] {values});
+ }
+
+ /**
+ * Creates a line chart model as a reference implementation
+ *
+ * @return An instance of the simulated runtime chart model (containing
+ * filled datasets)
+ */
+ public static final Chart createAreaChart(Calendar[] timestamps, Double[][] values) {
+ ChartWithAxes cwaLine = ChartWithAxesImpl.create();
+
+ // Plot
+ cwaLine.getBlock().setBackground(ColorDefinitionImpl.TRANSPARENT());
+ Plot p = cwaLine.getPlot();
+ p.getClientArea().setBackground(ColorDefinitionImpl.TRANSPARENT());
+ //p.getClientArea().setBackground(ColorDefinitionImpl.TRANSPARENT());
+
+
+ // Title
+ //cwaLine.getTitle().getLabel().getCaption().setValue("Line Chart");//$NON-NLS-1$
+ cwaLine.getTitle().setVisible(false);
+
+ // Legend
+ cwaLine.getLegend().setVisible(false);
+ Legend lg = cwaLine.getLegend();
+ LineAttributes lia = lg.getOutline( );
+ lg.getText( ).getFont( ).setSize( 16 );
+ lia.setStyle( LineStyle.SOLID_LITERAL );
+ lg.getInsets( ).set( 10, 5, 0, 0 );
+ lg.getOutline( ).setVisible( false );
+ lg.setAnchor( Anchor.NORTH_LITERAL );
+
+ // X-Axis
+ Axis xAxisPrimary = cwaLine.getPrimaryBaseAxes()[0];
+ xAxisPrimary.setType(AxisType.TEXT_LITERAL);
+ xAxisPrimary.getMajorGrid().setTickStyle(TickStyle.BELOW_LITERAL);
+ xAxisPrimary.getMajorGrid().setLineAttributes(LineAttributesImpl.create(ColorDefinitionImpl.GREY(), LineStyle.DOTTED_LITERAL, 1));
+ xAxisPrimary.getTitle().setVisible(false);
+ xAxisPrimary.setInterval(4);
+ xAxisPrimary.getLabel().getCaption().setFont(createChartFont());
+ xAxisPrimary.setFormatSpecifier( JavaDateFormatSpecifierImpl.create( "HH:mm" ) );
+
+ // Y-Axis
+ Axis yAxisPrimary = cwaLine.getPrimaryOrthogonalAxis(xAxisPrimary);
+ yAxisPrimary.getMajorGrid().setTickStyle(TickStyle.LEFT_LITERAL);
+ yAxisPrimary.getMajorGrid().setLineAttributes(LineAttributesImpl.create(ColorDefinitionImpl.GREY(), LineStyle.SOLID_LITERAL, 1));
+ yAxisPrimary.setInterval(2);
+ yAxisPrimary.getLabel().setVisible(true);
+ yAxisPrimary.getLabel().getCaption().setFont(createChartFont());
+
+ // Data Set
+ DateTimeDataSet categoryValues = DateTimeDataSetImpl.create(timestamps);
+
+ // X-Series
+ Series seCategory = SeriesImpl.create();
+ seCategory.setDataSet(categoryValues);
+ SeriesDefinition sdX = SeriesDefinitionImpl.create();
+
+ xAxisPrimary.getSeriesDefinitions().add(sdX);
+ sdX.getSeries().add(seCategory);
+
+ SeriesDefinition sdY = SeriesDefinitionImpl.create();
+ sdY.getSeriesPalette().shift(-3);
+ yAxisPrimary.getSeriesDefinitions().add(sdY);
+
+ for (int i = 0; i < values.length; i++) {
+ // Y-Sereis
+ AreaSeries ls = (AreaSeries) AreaSeriesImpl.create();
+ // LineSeries ls = (LineSeries) LineSeriesImpl.create();
+
+ NumberDataSet orthoValues = NumberDataSetImpl.create(values[i]);
+ ls.setDataSet(orthoValues);
+ ls.getLineAttributes().setColor(ColorDefinitionImpl.create(50, 50, 255));
+ for (int j = 0; j < ls.getMarkers().size(); j++) {
+ // ( (Marker) ls.getMarkers( ).get( j ) ).setType( MarkerType.CIRCLE_LITERAL);
+ ((Marker) ls.getMarkers().get(j)).setVisible(false);
+ }
+ ls.setTranslucent(true);
+ // don't show values on each point on the line chart
+ ls.getLabel().setVisible(false);
+ sdY.getSeries().add(ls);
+ }
+ return cwaLine;
+ }
+
+ public static FontDefinition createChartFont() {
+ return FontDefinitionImpl.create("Serif", 8, false, false, false, false, false, 0d, TextAlignmentImpl.create());
}
/**
@@ -118,8 +254,7 @@ public final class PieChartViewerComposite extends Composite implements
* Values of each category in the pie chart
* @return The chart object created for given categories and values
*/
- public static final Chart createPieChart(String[] categories,
- Double[] values) {
+ public static final Chart createPieChart(String[] categories, Double[] values) {
ChartWithoutAxes pieChart = ChartWithoutAxesImpl.create();
// Plot
@@ -127,7 +262,7 @@ public final class PieChartViewerComposite extends Composite implements
pieChart.setDimension(ChartDimension.TWO_DIMENSIONAL_WITH_DEPTH_LITERAL);
pieChart.getBlock().setBackground(ColorDefinitionImpl.WHITE());
Plot p = pieChart.getPlot();
-
+
p.getClientArea().setBackground(null);
p.getClientArea().getOutline().setVisible(false);
p.getOutline().setVisible(false);
@@ -196,8 +331,7 @@ public final class PieChartViewerComposite extends Composite implements
if (needsGeneration) {
needsGeneration = false;
try {
- generatedChartState = gr.build(deviceReader.getDisplayServer(),
- chart, bo, null, null, null);
+ generatedChartState = gr.build(deviceReader.getDisplayServer(), chart, bo, null, null, null);
} catch (ChartException ce) {
ce.printStackTrace();
}
@@ -208,8 +342,7 @@ public final class PieChartViewerComposite extends Composite implements
GC gc = e.gc;
gc.drawImage(imgChart, d.x, d.y);
} catch (ChartException gex) {
- logger.log(Level.SEVERE, "Exception while rendering pie chart ["
- + gex.getMessage() + "]", gex);
+ logger.log(Level.SEVERE, "Exception while rendering pie chart [" + gex.getMessage() + "]", gex);
}
}
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java
index 49c55b8a..f970effd 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java
@@ -20,8 +20,10 @@
*/
package com.gluster.storage.management.gui.views;
+import java.util.Date;
import java.util.List;
+import org.eclipse.birt.chart.util.CDateTime;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.graphics.Image;
@@ -40,21 +42,18 @@ import org.eclipse.ui.part.ViewPart;
import com.gluster.storage.management.client.GlusterDataModelManager;
import com.gluster.storage.management.core.model.Alert;
import com.gluster.storage.management.core.model.Cluster;
-import com.gluster.storage.management.core.model.Device.DEVICE_STATUS;
-import com.gluster.storage.management.core.model.Disk;
import com.gluster.storage.management.core.model.EntityGroup;
import com.gluster.storage.management.core.model.GlusterDataModel;
import com.gluster.storage.management.core.model.GlusterServer;
import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS;
import com.gluster.storage.management.core.model.Server;
import com.gluster.storage.management.core.model.TaskInfo;
-import com.gluster.storage.management.core.model.Volume;
-import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
import com.gluster.storage.management.core.utils.NumberUtil;
import com.gluster.storage.management.gui.IImageKeys;
import com.gluster.storage.management.gui.actions.IActionConstants;
+import com.gluster.storage.management.gui.utils.ChartViewerComposite;
import com.gluster.storage.management.gui.utils.GUIHelper;
-import com.gluster.storage.management.gui.utils.PieChartViewerComposite;
+import com.ibm.icu.util.Calendar;
/**
* @author root
@@ -82,16 +81,6 @@ public class ClusterSummaryView extends ViewPart {
createSections(parent);
}
- private int getVolumeCountByStatus(Cluster cluster, VOLUME_STATUS status) {
- int count = 0;
- for (Volume volume : cluster.getVolumes()) {
- if (volume.getStatus() == status) {
- count++;
- }
- }
- return count;
- }
-
private int getServerCountByStatus(Cluster cluster, SERVER_STATUS status) {
int count = 0;
for (GlusterServer server : cluster.getServers()) {
@@ -102,14 +91,6 @@ public class ClusterSummaryView extends ViewPart {
return count;
}
- private void createVolumesSection() {
- Composite section = guiHelper.createSection(form, toolkit, "Volumes", null, 1, false);
-
- Double[] values = new Double[] { Double.valueOf(getVolumeCountByStatus(cluster, VOLUME_STATUS.ONLINE)),
- Double.valueOf(getVolumeCountByStatus(cluster, VOLUME_STATUS.OFFLINE)) };
- createDiskSpaceChart(toolkit, section, values);
- }
-
private void createServersSection() {
Composite section = guiHelper.createSection(form, toolkit, "Servers", null, 2, false);
@@ -135,34 +116,13 @@ public class ClusterSummaryView extends ViewPart {
double totalDiskSpace = cluster.getTotalDiskSpace();
double diskSpaceInUse = cluster.getDiskSpaceInUse();
Double[] values = new Double[] { diskSpaceInUse, totalDiskSpace - diskSpaceInUse };
- createDiskSpaceChart(toolkit, section, values);
- }
-
- private int getDiskCountByStatus(Cluster cluster, DEVICE_STATUS status) {
- int diskCount = 0;
- for(GlusterServer server : cluster.getServers()) {
- for(Disk disk : server.getDisks()) {
- if(disk.getStatus() == status) {
- diskCount++;
- }
- }
- }
- return diskCount;
+ createDiskSpaceChart(section, values);
}
- private int getDiskCount(Cluster cluster) {
- int diskCount = 0;
- for(GlusterServer server : cluster.getServers()) {
- diskCount += server.getDisks().size();
- }
- return diskCount;
- }
-
- private void createDiskSpaceChart(FormToolkit toolkit, Composite section, Double[] values) {
+ private void createDiskSpaceChart(Composite section, Double[] values) {
String[] categories = new String[] { "Used Space: " + NumberUtil.formatNumber((values[0] / 1024)) + " GB",
- "Free Space: " + NumberUtil.formatNumber((values[1] / 1024)) + " GB"};
- PieChartViewerComposite chartViewerComposite = new PieChartViewerComposite(section, SWT.NONE, categories,
- values);
+ "Free Space: " + NumberUtil.formatNumber((values[1] / 1024)) + " GB" };
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values);
GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
data.widthHint = 400;
@@ -170,6 +130,15 @@ public class ClusterSummaryView extends ViewPart {
data.verticalAlignment = SWT.CENTER;
chartViewerComposite.setLayoutData(data);
}
+
+ private void createLineChart(Composite section, Calendar timestamps[], Double values[]) {
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, timestamps, values);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = 400;
+ data.heightHint = 300;
+ data.verticalAlignment = SWT.CENTER;
+ chartViewerComposite.setLayoutData(data);
+ }
private void createAlertsSection() {
Composite section = guiHelper.createSection(form, toolkit, "Alerts", null, 1, false);
@@ -254,23 +223,51 @@ public class ClusterSummaryView extends ViewPart {
parent.layout(); // IMP: lays out the form properly
}
- private void createMemoryUsageSection() {
- Composite section = guiHelper.createSection(form, toolkit, "Memory Usage (aggregated)", null, 1, false);
- toolkit.createLabel(section, "Historical Memory Usage graph aggregated across all servers will be displayed here.");
- }
-
private void createCPUUsageSection() {
Composite section = guiHelper.createSection(form, toolkit, "CPU Usage (aggregated)", null, 1, false);
if (cluster.getServers().size() == 0) {
toolkit.createLabel(section, "This section will be populated after at least\none server is added to the storage cloud.");
return;
}
- toolkit.createLabel(section, "Historical CPU Usage graph aggregated across\nall servers will be displayed here.");
+ //toolkit.createLabel(section, "Historical CPU Usage graph aggregated across\nall servers will be displayed here.");
+
+// Date[] timestamps = new Date[] { new Date(1310468100), new Date(1310468400), new Date(1310468700),
+// new Date(1310469000), new Date(1310469300), new Date(1310469600), new Date(1310469900),
+// new Date(1310470200), new Date(1310470500), new Date(1310470800), new Date(1310471100),
+// new Date(1310471400), new Date(1310471700), new Date(1310472000), new Date(1310472300),
+// new Date(1310472600), new Date(1310472900), new Date(1310473200), new Date(1310473500),
+// new Date(1310473800) };
+ Calendar[] timestamps = new Calendar[] { new CDateTime(1000l*1310468100), new CDateTime(1000l*1310468400), new CDateTime(1000l*1310468700),
+ new CDateTime(1000l*1310469000), new CDateTime(1000l*1310469300), new CDateTime(1000l*1310469600), new CDateTime(1000l*1310469900),
+ new CDateTime(1000l*1310470200), new CDateTime(1000l*1310470500), new CDateTime(1000l*1310470800), new CDateTime(1000l*1310471100),
+ new CDateTime(1000l*1310471400), new CDateTime(1000l*1310471700), new CDateTime(1000l*1310472000), new CDateTime(1000l*1310472300),
+ new CDateTime(1000l*1310472600), new CDateTime(1000l*1310472900), new CDateTime(1000l*1310473200), new CDateTime(1000l*1310473500),
+ new CDateTime(1000l*1310473800) };
+
+ //String[] timestampsarr = new String[] {"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t16", "t17", "t18", "t19", "t20"};
+ Double[] values = new Double[] { 10d, 11.23d, 17.92d, 18.69d, 78.62d, 89.11d, 92.43d, 89.31d, 57.39d, 18.46d, 10.44d, 16.28d, 13.51d, 17.53d, 12.21, 20d, 21.43d, 16.45d, 14.86d, 15.27d };
+ createLineChart(section, timestamps, values);
}
private void createNetworkUsageSection() {
Composite section = guiHelper.createSection(form, toolkit, "Network Usage", null, 1, false);
- toolkit.createLabel(section, "Historical Network Usage graph will be displayed here.");
+ //toolkit.createLabel(section, "Historical Network Usage graph will be displayed here.");
+
+ Calendar[] timestamps = new Calendar[] { new CDateTime(1000l*1310468100), new CDateTime(1000l*1310468400), new CDateTime(1000l*1310468700),
+ new CDateTime(1000l*1310469000), new CDateTime(1000l*1310469300), new CDateTime(1000l*1310469600), new CDateTime(1000l*1310469900),
+ new CDateTime(1000l*1310470200), new CDateTime(1000l*1310470500), new CDateTime(1000l*1310470800), new CDateTime(1000l*1310471100),
+ new CDateTime(1000l*1310471400), new CDateTime(1000l*1310471700), new CDateTime(1000l*1310472000), new CDateTime(1000l*1310472300),
+ new CDateTime(1000l*1310472600), new CDateTime(1000l*1310472900), new CDateTime(1000l*1310473200), new CDateTime(1000l*1310473500),
+ new CDateTime(1000l*1310473800) };
+// Date[] timestamps = new Date[] { new Date(1310468100), new Date(1310468400), new Date(1310468700),
+// new Date(1310469000), new Date(1310469300), new Date(1310469600), new Date(1310469900),
+// new Date(1310470200), new Date(1310470500), new Date(1310470800), new Date(1310471100),
+// new Date(1310471400), new Date(1310471700), new Date(1310472000), new Date(1310472300),
+// new Date(1310472600), new Date(1310472900), new Date(1310473200), new Date(1310473500),
+// new Date(1310473800) };
+ String[] timestampsarr = new String[] {"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t16", "t17", "t18", "t19", "t20"};
+ Double[] values = new Double[] { 32d, 31.23d, 27.92d, 48.69d, 58.62d, 49.11d, 72.43d, 69.31d, 87.39d, 78.46d, 60.44d, 56.28d, 33.51d, 27.53d, 12.21, 10d, 21.43d, 36.45d, 34.86d, 35.27d };
+ createLineChart(section, timestamps, values);
}
private void createRunningTasksSection() {
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java
index 30072b97..50da72ff 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java
@@ -47,11 +47,12 @@ import com.gluster.storage.management.core.model.DefaultClusterListener;
import com.gluster.storage.management.core.model.Event;
import com.gluster.storage.management.core.model.GlusterServer;
import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS;
-import com.gluster.storage.management.core.model.Volume;
import com.gluster.storage.management.core.utils.NumberUtil;
import com.gluster.storage.management.gui.IImageKeys;
import com.gluster.storage.management.gui.NetworkInterfaceTableLabelProvider;
import com.gluster.storage.management.gui.toolbar.GlusterToolbarManager;
+import com.gluster.storage.management.gui.utils.ChartViewerComposite;
+import com.gluster.storage.management.gui.utils.ChartViewerComposite.CHART_TYPE;
import com.gluster.storage.management.gui.utils.GUIHelper;
import com.richclientgui.toolbox.gauges.CoolGauge;
@@ -100,12 +101,37 @@ public class GlusterServerSummaryView extends ViewPart {
GlusterDataModelManager.getInstance().removeClusterListener(serverChangedListener);
}
+ private void createLineChart(Composite section, String timestamps[], Double values[]) {
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, timestamps, values);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = 450;
+ data.heightHint = 300;
+ data.verticalAlignment = SWT.CENTER;
+ chartViewerComposite.setLayoutData(data);
+ }
+
+ private void createMemoryUsageSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Memory Usage (aggregated)", null, 1, false);
+ toolkit.createLabel(section, "Historical Memory Usage graph aggregated across all servers will be displayed here.");
+ }
+
+ private void createCPUUsageSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "CPU Usage (aggregated)", null, 1, false);
+ //toolkit.createLabel(section, "Historical CPU Usage graph aggregated across\nall servers will be displayed here.");
+
+ String[] timestamps = new String[] {"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t16", "t17", "t18", "t19", "t20"};
+ Double[] values = new Double[] { 10d, 11.23d, 17.92d, 18.69d, 78.62d, 89.11d, 92.43d, 20.31d, 19.63d, 18.46d, 10.44d, 16.28d, 13.51d, 17.53d, 12.21, 20d, 40d, 10d, 90d, 40d };
+ createLineChart(section, timestamps, values);
+ }
+
private void createSections(Composite parent) {
String serverName = server.getName();
form = guiHelper.setupForm(parent, toolkit, "Server Summary [" + serverName + "]");
createServerSummarySection(server, toolkit, form);
if (server.getStatus() == SERVER_STATUS.ONLINE) {
+ createMemoryUsageSection();
+ createCPUUsageSection();
createNetworkInterfacesSection(server, toolkit, form);
}
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersSummaryView.java
index d80e3879..d703c9a7 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersSummaryView.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersSummaryView.java
@@ -33,8 +33,9 @@ import org.eclipse.ui.part.ViewPart;
import com.gluster.storage.management.core.model.EntityGroup;
import com.gluster.storage.management.core.model.GlusterServer;
import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS;
+import com.gluster.storage.management.gui.utils.ChartViewerComposite.CHART_TYPE;
import com.gluster.storage.management.gui.utils.GUIHelper;
-import com.gluster.storage.management.gui.utils.PieChartViewerComposite;
+import com.gluster.storage.management.gui.utils.ChartViewerComposite;
/**
*
@@ -95,7 +96,7 @@ public class GlusterServersSummaryView extends ViewPart {
private void createStatusChart(Composite section, Double[] values) {
String[] categories = new String[] { "Online", "Offline" };
- PieChartViewerComposite chartViewerComposite = new PieChartViewerComposite(section, SWT.NONE, categories, values);
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values);
GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
data.widthHint = 300;
@@ -103,7 +104,6 @@ public class GlusterServersSummaryView extends ViewPart {
chartViewerComposite.setLayoutData(data);
}
-
private void createAlertsSection() {
Composite section = guiHelper.createSection(form, toolkit, "Alerts", null, 2, false);
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java
index a43330c4..daeecb83 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java
@@ -40,8 +40,9 @@ import com.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
import com.gluster.storage.management.core.model.Volume;
import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
import com.gluster.storage.management.gui.IImageKeys;
+import com.gluster.storage.management.gui.utils.ChartViewerComposite.CHART_TYPE;
import com.gluster.storage.management.gui.utils.GUIHelper;
-import com.gluster.storage.management.gui.utils.PieChartViewerComposite;
+import com.gluster.storage.management.gui.utils.ChartViewerComposite;
/**
*
@@ -157,8 +158,7 @@ public class VolumesSummaryView extends ViewPart {
private void createStatusChart(FormToolkit toolkit, Composite section, Double[] values) {
String[] categories = new String[] { "Online", "Offline" };
- PieChartViewerComposite chartViewerComposite = new PieChartViewerComposite(section, SWT.NONE, categories,
- values);
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values);
GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
data.widthHint = 300;
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableTreeViewerPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableTreeViewerPage.java
index 05a74b03..13c2ceef 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableTreeViewerPage.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableTreeViewerPage.java
@@ -38,7 +38,6 @@ import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.forms.widgets.FormToolkit;
-import org.eclipse.ui.forms.widgets.Hyperlink;
import com.gluster.storage.management.core.model.ClusterListener;
import com.gluster.storage.management.core.model.Disk;
@@ -46,7 +45,6 @@ import com.gluster.storage.management.gui.utils.GUIHelper;
public abstract class AbstractTableTreeViewerPage<T> extends Composite implements ISelectionListener {
-
protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
protected TreeViewer treeViewer;
protected GUIHelper guiHelper = GUIHelper.getInstance();
diff --git a/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml b/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml
index 7c20d6c7..405c4e40 100644
--- a/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml
+++ b/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml
@@ -81,14 +81,14 @@
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-
+
<security-constraint>
- <web-resource-collection>
- <web-resource-name>Gluster Management Gateway</web-resource-name>
- <url-pattern>/*</url-pattern>
- </web-resource-collection>
- <user-data-constraint>
- <transport-guarantee>CONFIDENTIAL</transport-guarantee>
- </user-data-constraint>
-</security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Gluster Management Gateway</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint>
</web-app>
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java
new file mode 100644
index 00000000..4cd7f4f9
--- /dev/null
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.server.resources.v1_0;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import com.gluster.storage.management.core.exceptions.GlusterValidationException;
+
+@Provider
+public class GenericExceptionMapper implements ExceptionMapper<Exception> {
+
+ /* (non-Javadoc)
+ * @see javax.ws.rs.ext.ExceptionMapper#toResponse(java.lang.Throwable)
+ */
+ @Override
+ public Response toResponse(Exception exception) {
+ ResponseBuilder builder;
+ if (exception instanceof GlusterValidationException) {
+ builder = Response.status(Response.Status.BAD_REQUEST);
+ } else {
+ builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ return builder.entity(exception.getMessage()).type(MediaType.TEXT_PLAIN).build();
+ }
+}
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java
index a5f366a2..09391841 100644
--- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java
@@ -18,15 +18,21 @@
*******************************************************************************/
package com.gluster.storage.management.server.resources.v1_0;
-import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME;
import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FSTYPE;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME;
import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_DISK_NAME;
import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_SERVER_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DETAILS;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_TYPE;
import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DISKS;
import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS;
import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_SERVERS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_STATISTICS;
import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS;
+import static com.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_CPU;
+import static com.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_NETWORK;
+import static com.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_MEMORY;
import java.util.ArrayList;
import java.util.List;
@@ -39,6 +45,7 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@@ -49,14 +56,15 @@ import com.gluster.storage.management.core.constants.CoreConstants;
import com.gluster.storage.management.core.constants.RESTConstants;
import com.gluster.storage.management.core.exceptions.ConnectionException;
import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.ServerStats;
import com.gluster.storage.management.core.model.GlusterServer;
import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS;
import com.gluster.storage.management.core.response.GlusterServerListResponse;
+import com.gluster.storage.management.core.response.ServerNameListResponse;
import com.gluster.storage.management.server.data.ClusterInfo;
import com.gluster.storage.management.server.data.ServerInfo;
import com.gluster.storage.management.server.services.ClusterService;
import com.gluster.storage.management.server.tasks.InitializeDiskTask;
-import com.gluster.storage.management.server.utils.GlusterUtil;
import com.gluster.storage.management.server.utils.SshUtil;
import com.sun.jersey.api.core.InjectParam;
import com.sun.jersey.spi.resource.Singleton;
@@ -92,17 +100,44 @@ public class GlusterServersResource extends AbstractServersResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
- public Response getGlusterServersJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
- return getGlusterServers(clusterName, MediaType.APPLICATION_JSON);
+ public Response getGlusterServersJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_DETAILS) Boolean details) {
+ return getGlusterServers(clusterName, MediaType.APPLICATION_JSON, details);
}
@GET
@Produces(MediaType.APPLICATION_XML)
- public Response getGlusterServersXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
- return getGlusterServers(clusterName, MediaType.APPLICATION_XML);
+ public Response getGlusterServersXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_DETAILS) Boolean details) {
+ return getGlusterServers(clusterName, MediaType.APPLICATION_XML, details);
}
+
+ private List<GlusterServer> getGlusterServers(String clusterName, boolean fetchDetails) {
+ List<GlusterServer> glusterServers;
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
- public Response getGlusterServers(String clusterName, String mediaType) {
+ try {
+ glusterServers = getGlusterServers(clusterName, onlineServer, fetchDetails);
+ } catch (ConnectionException e) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+ glusterServers = getGlusterServers(clusterName, onlineServer, fetchDetails);
+ }
+ return glusterServers;
+ }
+
+ private Response getGlusterServers(String clusterName, String mediaType, Boolean fetchDetails) {
+ if(fetchDetails == null) {
+ // by default, fetch the server details
+ fetchDetails = true;
+ }
+
List<GlusterServer> glusterServers = new ArrayList<GlusterServer>();
if (clusterName == null || clusterName.isEmpty()) {
@@ -118,37 +153,30 @@ public class GlusterServersResource extends AbstractServersResource {
return okResponse(new GlusterServerListResponse(glusterServers), mediaType);
}
- GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
- if (onlineServer == null) {
- return errorResponse("No online servers found in cluster [" + clusterName + "]");
- }
-
try {
- glusterServers = getGlusterServers(clusterName, onlineServer);
- } catch (ConnectionException e) {
- // online server has gone offline! try with a different one.
- onlineServer = clusterService.getNewOnlineServer(clusterName);
- if (onlineServer == null) {
- return errorResponse("No online servers found in cluster [" + clusterName + "]");
- }
- try {
- glusterServers = getGlusterServers(clusterName, onlineServer);
- } catch (Exception e1) {
- return errorResponse(e1.getMessage());
- }
+ glusterServers = getGlusterServers(clusterName, fetchDetails);
} catch (Exception e) {
return errorResponse(e.getMessage());
}
-
- String errMsg = fetchDetailsOfServers(glusterServers, onlineServer);
- if (!errMsg.isEmpty()) {
- return errorResponse("Couldn't fetch details for server(s): " + errMsg);
+
+ if(fetchDetails) {
+ return okResponse(new GlusterServerListResponse(glusterServers), mediaType);
+ } else {
+ // no details to be fetched. Return list of server names.
+ return okResponse(new ServerNameListResponse(getServerNames(glusterServers)), mediaType);
}
+ }
+
- return okResponse(new GlusterServerListResponse(glusterServers), mediaType);
+ private List<String> getServerNames(List<GlusterServer> glusterServers) {
+ List<String> serverNames = new ArrayList<String>();
+ for(GlusterServer server : glusterServers) {
+ serverNames.add(server.getName());
+ }
+ return serverNames;
}
- public String fetchDetailsOfServers(List<GlusterServer> glusterServers, GlusterServer onlineServer) {
+ private String fetchDetailsOfServers(List<GlusterServer> glusterServers, GlusterServer onlineServer) {
String errMsg = "";
for (GlusterServer server : glusterServers) {
@@ -161,7 +189,7 @@ public class GlusterServersResource extends AbstractServersResource {
return errMsg;
}
- public List<GlusterServer> getGlusterServers(String clusterName, GlusterServer onlineServer) {
+ private List<GlusterServer> getGlusterServers(String clusterName, GlusterServer onlineServer, boolean fetchDetails) {
List<GlusterServer> glusterServers;
try {
glusterServers = glusterUtil.getGlusterServers(onlineServer);
@@ -174,11 +202,18 @@ public class GlusterServersResource extends AbstractServersResource {
glusterServers = glusterUtil.getGlusterServers(onlineServer);
}
+
+ if (fetchDetails) {
+ String errMsg = fetchDetailsOfServers(glusterServers, onlineServer);
+ if (!errMsg.isEmpty()) {
+ throw new GlusterRuntimeException("Couldn't fetch details for server(s): " + errMsg);
+ }
+ }
return glusterServers;
}
@GET
- @Path("{serverName}")
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}")
@Produces(MediaType.APPLICATION_XML)
public Response getGlusterServerXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
@@ -186,7 +221,7 @@ public class GlusterServersResource extends AbstractServersResource {
}
@GET
- @Path("{serverName}")
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}")
@Produces(MediaType.APPLICATION_JSON)
public Response getGlusterServerJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
@@ -428,20 +463,57 @@ public class GlusterServersResource extends AbstractServersResource {
return errorResponse(e.getMessage());
}
}
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ @Path(RESOURCE_STATISTICS)
+ public Response getAggregatedPerformanceDataXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_TYPE) String type) {
+ return getAggregaredPerformanceData(clusterName, type, MediaType.APPLICATION_XML);
+ }
- private void setGlusterUtil(GlusterUtil glusterUtil) {
- this.glusterUtil = glusterUtil;
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path(RESOURCE_STATISTICS)
+ public Response getAggregaredPerformanceDataJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_TYPE) String type) {
+ return getAggregaredPerformanceData(clusterName, type, MediaType.APPLICATION_JSON);
}
- public static void main(String[] args) {
- GlusterServersResource glusterServersResource = new GlusterServersResource();
- GlusterUtil glusterUtil = new GlusterUtil();
- glusterUtil.setSshUtil(new SshUtil());
- glusterServersResource.setGlusterUtil(glusterUtil);
- // System.out.println(glusterServersResource.getServerDetails("127.0.0.1").size());
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_STATISTICS)
+ public Response getPerformanceDataXML(@PathParam(PATH_PARAM_SERVER_NAME) String serverName, @QueryParam(QUERY_PARAM_TYPE) String type) {
+ return getPerformanceData(serverName, type, MediaType.APPLICATION_XML);
+ }
- // To add a server
- // GlusterServerResponse response = glusterServersResource.addServer("my-server");
- // System.out.println(response.getData().getName());
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_STATISTICS)
+ public Response getPerformanceDataJSON(@PathParam(PATH_PARAM_SERVER_NAME) String serverName, @QueryParam(QUERY_PARAM_TYPE) String type) {
+ return getPerformanceData(serverName, type, MediaType.APPLICATION_JSON);
+ }
+
+ private Response getAggregaredPerformanceData(String clusterName, String type, String mediaType) {
+ List<String> serverNames = getServerNames(getGlusterServers(clusterName, false));
+ if(type.equals(STATISTICS_TYPE_CPU)) {
+ return okResponse(serverUtil.fetchAggregatedCPUStats(serverNames), mediaType);
+ } else {
+ return badRequestResponse("Server Statistics for [" + type + "] not supported! Valid values are ["
+ + STATISTICS_TYPE_CPU + ", " + STATISTICS_TYPE_NETWORK + ", " + STATISTICS_TYPE_MEMORY + "]");
+ }
+ }
+
+ private Response getPerformanceData(String serverName, String type, String mediaType) {
+ if(type.equals(STATISTICS_TYPE_CPU)) {
+ return okResponse(serverUtil.fetchCPUUsageData(serverName), mediaType);
+ } else if(type.equals(STATISTICS_TYPE_NETWORK)) {
+ return okResponse(serverUtil.fetchCPUUsageData(serverName), mediaType);
+ } else if(type.equals(STATISTICS_TYPE_MEMORY)) {
+ return okResponse(serverUtil.fetchCPUUsageData(serverName), mediaType);
+ } else {
+ return badRequestResponse("Server Statistics for [" + type + "] not supported! Valid values are ["
+ + STATISTICS_TYPE_CPU + ", " + STATISTICS_TYPE_NETWORK + ", " + STATISTICS_TYPE_MEMORY + "]");
+ }
}
}
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ValidationExceptionMapper.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ValidationExceptionMapper.java
new file mode 100644
index 00000000..cab6cc62
--- /dev/null
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ValidationExceptionMapper.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.server.resources.v1_0;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import com.gluster.storage.management.core.exceptions.GlusterValidationException;
+
+@Provider
+public class ValidationExceptionMapper implements ExceptionMapper<GlusterValidationException> {
+
+ /* (non-Javadoc)
+ * @see javax.ws.rs.ext.ExceptionMapper#toResponse(java.lang.Throwable)
+ */
+ @Override
+ public Response toResponse(GlusterValidationException exception) {
+ return Response.status(Response.Status.BAD_REQUEST).entity(exception.getMessage())
+ .type(MediaType.TEXT_PLAIN).build();
+ }
+}
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java
index ae4bc919..55be59b4 100644
--- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java
@@ -22,6 +22,8 @@ package com.gluster.storage.management.server.utils;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
import java.util.List;
import javax.servlet.ServletContext;
@@ -29,12 +31,15 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
+import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.gluster.storage.management.core.constants.CoreConstants;
import com.gluster.storage.management.core.exceptions.ConnectionException;
import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.ServerStatsRow;
+import com.gluster.storage.management.core.model.ServerStats;
import com.gluster.storage.management.core.model.Server;
import com.gluster.storage.management.core.model.Status;
import com.gluster.storage.management.core.response.GenericResponse;
@@ -48,6 +53,8 @@ public class ServerUtil {
@Autowired
private SshUtil sshUtil;
+
+ private static final Logger logger = Logger.getLogger(ServerUtil.class);
private static final String SCRIPT_DIR = "scripts";
private static final String SCRIPT_COMMAND = "python";
@@ -216,4 +223,103 @@ public class ServerUtil {
public Status getDiskForDir(String serverName, String brickDir) {
return (Status) executeOnServer(true, serverName, REMOTE_SCRIPT_GET_DISK_FOR_DIR + " " + brickDir, Status.class);
}
+
+ public ServerStats fetchCPUUsageData(String serverName) {
+ String cpuUsageData = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> <xport> <meta> <start>1310468100</start> <step>300</step> <end>1310471700</end> <rows>13</rows> <columns>3</columns> <legend> <entry>user</entry> <entry>system</entry> <entry>total</entry> </legend> </meta> <data> <row><t>1310468100</t><v>NaN</v><v>4.3747778209e-01</v><v>6.6128073384e-01</v></row> <row><t>1310468400</t><v>2.3387347338e-01</v><v>4.4642717442e-01</v><v>6.8030064780e-01</v></row> <row><t>1310468700</t><v>5.5043873220e+00</v><v>6.2462376636e+00</v><v>1.1750624986e+01</v></row> <row><t>1310469000</t><v>2.4350593653e+01</v><v>2.6214585217e+01</v><v>5.0565178869e+01</v></row> <row><t>1310469300</t><v>4.0786489953e+01</v><v>4.6784713828e+01</v><v>8.7571203781e+01</v></row> <row><t>1310469600</t><v>4.1459955508e+01</v><v>5.2546309044e+01</v><v>9.4006264551e+01</v></row> <row><t>1310469900</t><v>4.2312286165e+01</v><v>5.2390588332e+01</v><v>9.4702874497e+01</v></row> <row><t>1310470200</t><v>4.2603794982e+01</v><v>5.1598861493e+01</v><v>9.4202656475e+01</v></row> <row><t>1310470500</t><v>3.8238751290e+01</v><v>4.5312089966e+01</v><v>8.3550841256e+01</v></row> <row><t>1310470800</t><v>1.7949961224e+01</v><v>2.1282058418e+01</v><v>3.9232019642e+01</v></row> <row><t>1310471100</t><v>1.2330371421e-01</v><v>4.6347832868e-01</v><v>5.8678204289e-01</v></row> <row><t>1310471400</t><v>1.6313260492e-01</v><v>5.4088119561e-01</v><v>7.0401380052e-01</v></row> <row><t>1310471700</t><v>NaN</v><v>NaN</v><v>NaN</v></row> </data> </xport>";
+ Object output = unmarshal(ServerStats.class, cpuUsageData, false);
+ if(output instanceof Status) {
+ throw new GlusterRuntimeException(((Status)output).toString());
+ }
+ return (ServerStats) output;
+ }
+
+ private ServerStats getFirstOnlineServerCPUStats(List<String> serverNames, boolean removeServerOnError, boolean removeOnlineServer) {
+ for(String serverName : serverNames) {
+ try {
+ ServerStats stats = fetchCPUUsageData(serverName);
+ if(removeOnlineServer) {
+ serverNames.remove(serverName);
+ }
+ } catch(Exception e) {
+ // server might be offline - continue with next one
+ logger.warn("Couldn't fetch CPU stats from server [" + serverName + "]!", e);
+ if(removeServerOnError) {
+ serverNames.remove(serverName);
+ }
+ continue;
+ }
+ }
+ throw new GlusterRuntimeException("All servers offline!");
+ }
+
+ public Object fetchAggregatedCPUStats(List<String> serverNames) {
+ if(serverNames == null || serverNames.size() == 0) {
+ throw new GlusterRuntimeException("No server names passed to fetchAggregaredCPUUsageData!");
+ }
+
+ ServerStats firstServerStats = getFirstOnlineServerCPUStats(serverNames, true, true);
+
+ ServerStats aggregatedStats = new ServerStats(firstServerStats);
+ aggregateCPUStats(serverNames, aggregatedStats);
+ return aggregatedStats;
+ }
+
+ private void aggregateCPUStats(List<String> serverNames, ServerStats aggregatedStats) {
+ int[][] dataCount = new int[aggregatedStats.getMetadata().getRowCount()][aggregatedStats.getMetadata()
+ .getLegend().size()];
+
+ for (String serverName : serverNames) {
+ ServerStats serverStats;
+ try {
+ serverStats = fetchCPUUsageData(serverName);
+ } catch(Exception e) {
+ // server might be offline - continue with next one
+ logger.warn("Couldn't fetch CPU stats from server [" + serverName + "]!", e);
+ continue;
+ }
+ List<ServerStatsRow> serverStatsRows = addServerStats(serverStats, aggregatedStats, dataCount);
+ }
+
+ List<ServerStatsRow> rows = aggregatedStats.getRows();
+ for(int rowNum = 0; rowNum < rows.size(); rowNum++) {
+ List<Double> data = rows.get(rowNum).getUsageData();
+ for(int columnNum = 0; columnNum < data.size(); columnNum++) {
+ data.set(columnNum, data.get(columnNum) / dataCount[rowNum][columnNum]);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param statsToBeAdded
+ * @param targetStats
+ * @param dataCount Each element of this matrix will be incremented for every valid element added
+ * @return
+ */
+ private List<ServerStatsRow> addServerStats(ServerStats statsToBeAdded, ServerStats targetStats, int[][] dataCount) {
+ List<ServerStatsRow> serverStatsRows = statsToBeAdded.getRows();
+ for (int rowNum = 0; rowNum < serverStatsRows.size()
+ && rowNum < targetStats.getMetadata().getRowCount(); rowNum++) {
+ ServerStatsRow row = serverStatsRows.get(rowNum);
+ List<Double> rowData = row.getUsageData();
+
+ List<Double> aggregatedStatsRowData = targetStats.getRows().get(rowNum).getUsageData();
+ for(int i = 1; i < targetStats.getMetadata().getLegend().size(); i++) {
+ // Add the data
+ Double data = rowData.get(i);
+ if(!data.isNaN()) {
+ // data is available. add it.
+ aggregatedStatsRowData.set(i, aggregatedStatsRowData.get(i) + data);
+ // increment record count. this will be used for calculating average of aggregated data.
+ dataCount[rowNum][i]++;
+ }
+ }
+ }
+ return serverStatsRows;
+ }
+
+ public static void main(String[] args) {
+ ServerStats stats = new ServerUtil().fetchCPUUsageData("s1");
+ System.out.println(stats.getMetadata().getLegend());
+ }
}